這是非常簡單的翻譯:
module PNormalDist where
pnormaldist :: (Ord a, Floating a) => a -> Either String a
pnormaldist qn
| qn < 0 || 1 < qn = Left "Error: qn must be in [0,1]"
| qn == 0.5 = Right 0.0
| otherwise = Right $
let w3 = negate . log $ 4 * qn * (1 - qn)
b = [ 1.570796288, 0.03706987906, -0.8364353589e-3,
-0.2250947176e-3, 0.6841218299e-5, 0.5824238515e-5,
-0.104527497e-5, 0.8360937017e-7, -0.3231081277e-8,
0.3657763036e-10, 0.6936233982e-12]
w1 = sum . zipWith (*) b $ iterate (*w3) 1
in (signum $ qn - 0.5) * sqrt (w1 * w3)
首先,讓我們來看看紅寶石 - 它返回一個值,但有時它會打印錯誤消息(給出不正確的參數時)。這不是非常危險,所以 讓我們返回值爲Either String a
- 如果給出不正確的參數,我們將返回一個帶有錯誤消息的Left String
,否則返回Right a
。
現在我們檢查這兩種情況在上面:
qn < 0 || 1 < qn = Left "Error: qn must be in [0,1]"
- 這是出現的錯誤,當qn
超出範圍。
qn == 0.5 = Right 0.0
- 這是紅寶石檢查qn == 0.5 and return * 0.0
接下來,我們定義在Ruby代碼w1
。但是我們在幾行後重新定義了它,這不是很紅寶石。我們在w1
第一次存儲的值 立即在w3
的定義中使用,那麼爲什麼我們不跳過將其存儲在w1
?我們甚至不需要執行qn > 0.5 and w1 = 1.0 - w1
步驟,因爲 我們在w3的定義中使用產品w1 * (1.0 - w1)
。
所以我們跳過所有這些,直接轉到定義w3 = negate . log $ 4 * qn * (1 - qn)
。
接下來是b
的定義,它是ruby代碼的直接提升(ruby的數組字面語法是haskell的列表語法)。
下面是最棘手的一點 - 定義w3
的最終值。 Ruby代碼確實在
w1 = b[0]
1.upto 10 do |i|
w1 += b[i] * w3**i;
end
是所謂的摺疊什麼 - 減少一組值(存儲在陣列紅寶石)爲單精度值。我們可以重申這一點使用Array#reduce
更多功能(但仍紅寶石):
w1 = b.zip(0..10).reduce(0) do |accum, (bval,i)|
accum + bval * w3^i
end
注意我怎麼推b[0]
進入死循環,使用標識b[0] == b[0] * w3^0
。
現在我們可以口這直接哈斯克爾,但它是一個有點難看
w1 = foldl 0 (\accum (bval,i) -> accum + bval * w3**i) $ zip b [0..10]
相反,我把它分成幾個步驟 - 首先,我們並不真正需要i
,我們只需要w3
(從w3^0 == 1
開始)的權力,所以 讓我們用iterate (*w3) 1
來計算那些權力。
然後,我們最終只需要他們的產品,而不是將它們與b中的元素拉在一起,所以我們可以使用zipWith (*) b
將它們壓縮到每個產品對的 。
現在我們的摺疊功能非常簡單 - 我們只需要總結產品,我們可以使用sum
。
最後,根據qn
是大於還是小於0.5(我們知道 已知它不相等),我們決定是否返回正負sqrt (w1 * w3)
。因此,不是像計算紅寶石代碼那樣在兩個分開的位置計算平方根,我計算了一次,並且根據qn - 0.5
(signum
just returns the sign of a value)的符號將其乘以+1
或-1
。
我真的對統計一無所知:P。你知道哪些功能等同於pnormaldist? – 2011-05-24 21:27:41
我不認爲任何這些功能正是你所需要的。如果我沒有弄錯,你需要erf函數的反函數。 – augustss 2011-05-25 00:47:57