摘要:以下是對(duì)史密斯先生有兩個(gè)孩子的可能情況進(jìn)行描述,其中函數(shù)隨機(jī)返回或的概率均為用于模擬現(xiàn)實(shí)中生男孩女孩的概率各一半。
??無(wú)意在維基看到了一個(gè)關(guān)于概率悖論的討論Boy or Girl paradox。有爭(zhēng)議的的題目如下:
??史密斯先生有兩個(gè)孩子,至少其中之一是男孩,請(qǐng)問(wèn)兩個(gè)孩子都是男孩的可能性有多大?
??原文如下:
??Mr. Smith has two children. At least one of them is a boy. What is the probability that both children are boys?
??一部分人的答案是1/3,一部分人的答案是1/2.為什么會(huì)產(chǎn)生這樣的結(jié)果呢,文中說(shuō)得很清楚是因?yàn)閱?wèn)題本身存在歧義,對(duì)“至少一個(gè)孩子是男孩”的信息做不同的假設(shè),導(dǎo)致了不同的結(jié)果。問(wèn)題歸根結(jié)底是由于自然語(yǔ)言的二義性,將問(wèn)題轉(zhuǎn)化成了兩個(gè)不同的數(shù)學(xué)模型,從而產(chǎn)生了兩個(gè)不同的結(jié)果。我們知道設(shè)計(jì)一種編程語(yǔ)言的任務(wù)之一就是消除其二義性,因此一般而言編程語(yǔ)言是一種沒(méi)有歧義的語(yǔ)言(所以程序員都喜歡寫(xiě)代碼不喜歡說(shuō)話么),如果用編程語(yǔ)言來(lái)描述這一問(wèn)題,會(huì)不會(huì)好理解點(diǎn)呢?以java為例,我們來(lái)看看。
??以下是對(duì)史密斯先生有兩個(gè)孩子的可能情況進(jìn)行描述,其中random.nextBoolean()函數(shù)隨機(jī)返回true或false的概率均為1/2,用于模擬現(xiàn)實(shí)中生男孩女孩的概率各一半??梢?jiàn)程序不僅描述了所有的組合,還明確了題目中暗含的條件。
class TwoChildren { Child child1; Child child2; public TwoChildren()//一個(gè)孩子是男孩或女孩的概率是50% { child1 = random.nextBoolean()?Child.BOY:Child.GIRL; child2 = random.nextBoolean()?Child.BOY:Child.GIRL; } }
??接著描述“至少一個(gè)孩子是男孩”,因?yàn)檫@里是存在歧義的地方,所以轉(zhuǎn)化成代碼描述時(shí),我們會(huì)根據(jù)兩個(gè)不同的假定,得到不同的代碼。1/3結(jié)果的假定條件:觀察了史密斯的兩個(gè)孩子,其中一個(gè)是男孩:
boolean isObserved(TwoChildren draw) { return draw.child1 == Child.BOY || draw.child2 == Child.BOY; }
熟悉java的程序員會(huì)注意到,如果child1為BOY的話,child2不會(huì)被觀察(||運(yùn)算符后面的代碼不會(huì)被執(zhí)行),是否和自然語(yǔ)言描述不一樣?我們從邏輯或運(yùn)算定義可知二者是等價(jià)的,即使||運(yùn)算符后面的代碼被執(zhí)行,也不影響程序結(jié)果,換成自然語(yǔ)言就是我們觀察史密斯的兩個(gè)孩子時(shí),一個(gè)一個(gè)的觀察,如果發(fā)現(xiàn)其中一個(gè)是男孩,就已經(jīng)保證了“至少一個(gè)是男孩”,就沒(méi)必要接著觀察了。
??接著描述1/2的結(jié)果假定條件:隨機(jī)觀察了史密斯的一個(gè)孩子,其中一個(gè)是男孩:
boolean isObserved(TwoChildren draw) { return random.nextBoolean()?draw.child1 == Child.BOY:draw.child2 == Child.BOY; }
其中random.nextBoolean()函數(shù)隨機(jī)返回true或false的概率均為1/2,就是兩個(gè)孩子被選中觀察的概率是1/2.
最后我們描述問(wèn)題的提出
if(isObserved(draw)) { observedCount ++; if(draw.child1 == Child.BOY && draw.child2 == Child.BOY) {//兩個(gè)孩子都是男孩 matchedCount++; //經(jīng)過(guò)很多次運(yùn)算后,((double)matchedCount/observedCount)最可能的值是多少? } }
??至此我們將一個(gè)以自然語(yǔ)言描述的問(wèn)題,轉(zhuǎn)化成了一個(gè)以程序語(yǔ)言描述的問(wèn)題。這個(gè)轉(zhuǎn)化是否正確呢,我們做10萬(wàn)次測(cè)試,看結(jié)果是否滿足數(shù)學(xué)推導(dǎo)的預(yù)期。以下是一個(gè)完整的測(cè)試代碼:
package hermitdl.test2; import java.util.Random; /** * Test for <> */ public class App { static enum Child { BOY, GIRL }; static Random random = new Random(); static class TwoChildren { Child child1; Child child2; public TwoChildren()//一個(gè)孩子是男孩或女孩的概率是50% { child1 = random.nextBoolean()?Child.BOY:Child.GIRL; child2 = random.nextBoolean()?Child.BOY:Child.GIRL; } } //隨機(jī)檢查一個(gè)孩子的性別是否是男孩 static class PeekOneTest extends ProbabilityTest { @Override boolean isObserved(TwoChildren draw) { return random.nextBoolean()?draw.child1 == Child.BOY:draw.child2 == Child.BOY; } } //檢查兩個(gè)孩子的性別,是否其中之一是男孩 static class PeekTwoTest extends ProbabilityTest { @Override boolean isObserved(TwoChildren draw) { return draw.child1 == Child.BOY || draw.child2 == Child.BOY; } } static abstract class ProbabilityTest { int observedCount = 0; int matchedCount = 0; //在isObserved為真的情況下計(jì)數(shù),以及兩個(gè)孩子均是女孩的情況計(jì)數(shù)。 void test(TwoChildren draw) { if(isObserved(draw)) { observedCount ++; if(draw.child1 == Child.BOY && draw.child2 == Child.BOY) { ////兩個(gè)孩子都是男孩 matchedCount++; } } } abstract boolean isObserved(TwoChildren draw); void printResult() { System.out.printf(this.getClass().getSimpleName() +"=%d/%d=%f " ,matchedCount ,observedCount ,((double)matchedCount/observedCount)); } } public static void main( String[] args ) { PeekOneTest peekOneTest = new PeekOneTest(); PeekTwoTest peekTwoTest = new PeekTwoTest(); TwoChildren draw; for(int i = 0;i < 1000000; i++) { draw = new TwoChildren(); peekOneTest.test(draw); peekTwoTest.test(draw); } peekOneTest.printResult(); peekTwoTest.printResult(); } }
以下為程序的幾次運(yùn)行結(jié)果:
PeekOneTest=249436/499301=0.499570
PeekTwoTest=249436/750234=0.332478
PeekOneTest=250209/500229=0.500189
PeekTwoTest=250209/749846=0.333681
PeekOneTest=249963/500234=0.499692
PeekTwoTest=249963/749712=0.333412
??可見(jiàn)模擬結(jié)果始終分別在1/2與1/3附近波動(dòng),是符合數(shù)學(xué)預(yù)期的。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/19836.html
摘要:以下是對(duì)史密斯先生有兩個(gè)孩子的可能情況進(jìn)行描述,其中函數(shù)隨機(jī)返回或的概率均為用于模擬現(xiàn)實(shí)中生男孩女孩的概率各一半。 ??無(wú)意在維基看到了一個(gè)關(guān)于概率悖論的討論Boy or Girl paradox。有爭(zhēng)議的的題目如下:??史密斯先生有兩個(gè)孩子,至少其中之一是男孩,請(qǐng)問(wèn)兩個(gè)孩子都是男孩的可能性有多大???原文如下:??Mr. Smith has two children. At leas...
摘要:對(duì)于這種會(huì)退出的情況,數(shù)組顯然不能像鏈表一樣直接斷開(kāi),因此采用標(biāo)記法先生成一個(gè)長(zhǎng)度為的布爾型數(shù)組,用填充。中對(duì)整個(gè)進(jìn)行遍歷才能得到此時(shí)數(shù)組中的數(shù)量。 文中的速度測(cè)試部分,時(shí)間是通過(guò)簡(jiǎn)單的 System.currentTimeMillis() 計(jì)算得到的, 又由于 Java 的特性,每次測(cè)試的結(jié)果都不一定相同, 對(duì)于低數(shù)量級(jí)的情況有 ± 20 的浮動(dòng),對(duì)于高數(shù)量級(jí)的情況有的能有 ± 10...
摘要:一般用大寫(xiě)的表示文法的開(kāi)頭,稱為開(kāi)始符號(hào)。更多討論討論地址是精讀手寫(xiě)編譯器文法介紹如果你想?yún)⑴c討論,請(qǐng)點(diǎn)擊這里,每周都有新的主題,周末或周一發(fā)布。 1 引言 文法用來(lái)描述語(yǔ)言的語(yǔ)法規(guī)則,所以不僅可以用在編程語(yǔ)言上,也可用在漢語(yǔ)、英語(yǔ)上。 2 精讀 我們將一塊語(yǔ)法規(guī)則稱為 產(chǎn)生式,使用 Left → Right 表示任意產(chǎn)生式,用 Left => Right 表示產(chǎn)生式的推導(dǎo)過(guò)程,比如對(duì)...
閱讀 2139·2021-11-23 10:06
閱讀 3513·2021-11-11 16:54
閱讀 3366·2019-08-29 17:31
閱讀 3603·2019-08-29 17:05
閱讀 2186·2019-08-26 13:36
閱讀 2181·2019-08-26 12:17
閱讀 548·2019-08-26 12:12
閱讀 1694·2019-08-26 10:19