Запуск кода на моем компьютере и времени я получаю:
seconds: 68.481918
result: 0.47570994
Запуск мой код на моем компьютере и времени я получаю:
seconds: 14.003861
vOne: 0.498963
vRnd: 0.499793
vMin: 0.037675
с Vmin быть ближе всего к правильному ответу b
являющееся 0.01
Это почти 5x
быстрее.
Я не возился с каждым методом и структурой данных, чтобы выяснить, почему и что сработало, я просто использовал многолетний опыт, чтобы вести меня. Очевидно, что не сохранение промежуточных значений, а просто результаты являются большим улучшением. В частности, coinTest
просто возвращает количество головок, которое является int
, а не список результатов. Также вместо того, чтобы получать случайное число для каждого переворота монетки, но получая случайное число для каждой монеты, а затем использовать каждую часть этого случайного числа в качестве переворота монет выгодно. Это экономит number of flips - 1
вызовов функции. Также я избегал использовать значения float
до самого конца; Я не считаю, что экономия времени на процессоре, но это упростило мыслительный процесс мышления только в int
, что позволило мне сосредоточиться на других эффектах. Я знаю, что это может показаться странным, но чем меньше я должен думать о лучших ответах, которые получаю. Я также только побежал coinTest
, когда это было необходимо, например. только первая монета, только случайная монета, и искал все хвосты в качестве условия выхода.
namespace Workspace
module main =
[<EntryPoint>]
let main argv =
let rnd = System.Random()
let randomPick (limit : int) : int = rnd.Next(limit) // [0 .. limit) it's a Python habit
let numberOfCoins = 1000
let numberOfFlips = 10
let numberOfExperiements = 100000
let coinTest (numberOfFlips : int) : int =
let rec countHeads (flips : int) bitIndex (headCount : int) : int =
if bitIndex < 0 then headCount
else countHeads (flips >>> 1) (bitIndex-1) (headCount + (flips &&& 0x01))
countHeads (randomPick ((pown 2 numberOfFlips) - 1)) numberOfFlips 0
let runExperiement (numberOfCoins : int) (numberOfFlips : int) : (int * int * int) =
let (randomCoin : int) = randomPick numberOfCoins
let rec testCoin coinIndex (cFirst, cRnd, cMin, cFirstDone, cRanDone, cMinDone) : (int * int * int) =
if (coinIndex < numberOfCoins) then
if (not cFirstDone || not cRanDone || not cMinDone) then
if (cFirstDone && cMinDone && (coinIndex <> randomCoin)) then
testCoin (coinIndex+1) (cFirst, cRnd, cMin, cFirstDone, cRanDone, cMinDone)
else
let headsTotal = coinTest numberOfFlips
let (cFirst, cRnd, cMin, cFirstDone, cRanDone, cMinDone) =
let cFirst = if coinIndex = 0 then headsTotal else cFirst
let cRnd = if coinIndex = randomCoin then headsTotal else cRnd
let cMin = if headsTotal < cMin then headsTotal else cMin
let cRanDone = if (coinIndex >= randomCoin) then true else cRanDone
let cMinDone = if (headsTotal = 0) then true else cMinDone
(cFirst, cRnd, cMin, true, cRanDone, cMinDone)
testCoin (coinIndex+1) (cFirst, cRnd, cMin, cFirstDone, cRanDone, cMinDone)
else
(cFirst, cRnd, cMin)
else
(cFirst, cRnd, cMin)
testCoin 0 (-1,-1,10, false, false, false)
let runExperiements (numberOfExperiements : int) (numberOfCoins : int) (numberOfFlips : int) =
let rec accumateExperiements index aOne aRnd aMin : (int * int * int) =
let (cOne,cRnd,cMin) = runExperiement numberOfCoins numberOfFlips
if index > numberOfExperiements then (aOne, aRnd, aMin)
else accumateExperiements (index + 1) (aOne + cOne) (aRnd + cRnd) (aMin + cMin)
let (aOne, aRnd, aMin) = accumateExperiements 0 0 0 0
let (vOne : double) = (double)(aOne)/(double)numberOfExperiements/(double)numberOfFlips
let (vRnd : double) = (double)(aRnd)/(double)numberOfExperiements/(double)numberOfFlips
let (vMin : double) = (double)(aMin)/(double)numberOfExperiements/(double)numberOfFlips
(vOne, vRnd, vMin)
let timeIt() =
let stopWatch = System.Diagnostics.Stopwatch.StartNew()
let (vOne, vRnd, vMin) = runExperiements numberOfExperiements numberOfCoins numberOfFlips
stopWatch.Stop()
printfn "seconds: %f" (stopWatch.Elapsed.TotalMilliseconds/1000.0)
printfn "vOne: %A" vOne
printfn "vRnd: %A" vRnd
printfn "vMin: %A" vMin
timeIt()
printf "Press any key to exit: "
System.Console.ReadKey() |> ignore
printfn ""
0 // return an integer exit code
=========================================== =============================
Это лишь промежуточный ответ, потому что я спросил, если ОП рассматривается с использованием Mathnet Числовой идиоматическим F # и OP хотели посмотреть, как это выглядит. После запуска его версии и этой первой версии на моей машине версия OP работает быстрее. OP: 75 сек, шахта: 84 сек
namespace Workspace
open MathNet.Numerics.LinearAlgebra
module main =
[<EntryPoint>]
let main argv =
let rnd = System.Random()
let flipCoin() =
let head = rnd.NextDouble() > 0.5
if head then 1.0 else 0.0
let numberOfCoins = 1000
let numberOfFlips = 10
let numberOfExperiements = 100000
let numberOfValues = 3
let randomPick (limit : int) : int = rnd.Next(limit) // [0 .. limit) it's a Python habit
let headCount (m : Matrix<float>) (coinIndex : int) : int =
System.Convert.ToInt32((m.Row coinIndex).Sum())
let minHeads (m : Matrix<float>) (numberOfCoins : int) (numberOfFlips : int) : int =
let rec findMinHeads currentCoinIndex minHeadsCount minHeadsIndex =
match currentCoinIndex,minHeadsCount with
| -1,_ -> minHeadsCount
| _,0 -> minHeadsCount // Can't get less than zero so stop searching.
| _ ->
let currentMinHeadCount = (headCount m currentCoinIndex)
let nextIndex = currentCoinIndex - 1
if currentMinHeadCount < minHeadsCount
then findMinHeads nextIndex currentMinHeadCount currentCoinIndex
else findMinHeads nextIndex minHeadsCount minHeadsIndex
findMinHeads (numberOfCoins - 1) numberOfFlips -1
// Return the values for cOne, cRnd, and cMin as int values.
// Will do division on final sum of experiments instead of after each experiment.
let runExperiement (numberOfCoins : int) (numberOfFlips : int) : (int * int * int) =
let (flips : Matrix<float>) = DenseMatrix.init numberOfCoins numberOfFlips (fun i j -> flipCoin())
let cOne = headCount flips 0
let cRnd = headCount flips (randomPick numberOfCoins)
let cMin = minHeads flips numberOfCoins numberOfFlips
(cOne,cRnd,cMin)
let runExperiements (numberOfExperiements : int) (numberOfCoins : int) (numberOfFlips : int) : (int [] * int [] * int []) =
let (cOneArray : int[]) = Array.create numberOfExperiements 0
let (cRndArray : int[]) = Array.create numberOfExperiements 0
let (cMinArray : int[]) = Array.create numberOfExperiements 0
for i = 0 to (numberOfExperiements - 1) do
let (cOne,cRnd,cMin) = runExperiement numberOfCoins numberOfFlips
cOneArray.[i] <- cOne
cRndArray.[i] <- cRnd
cMinArray.[i] <- cMin
(cOneArray, cRndArray, cMinArray)
let (cOneArray, cRndArray, cMinArray) = runExperiements numberOfExperiements numberOfCoins numberOfFlips
let (vOne : double) = (double)(Array.sum cOneArray)/(double)numberOfExperiements/(double)numberOfFlips
let (vRnd : double) = (double)(Array.sum cRndArray)/(double)numberOfExperiements/(double)numberOfFlips
let (vMin : double) = (double)(Array.sum cMinArray)/(double)numberOfExperiements/(double)numberOfFlips
printfn "vOne: %A" vOne
printfn "vRnd: %A" vRnd
printfn "vMin: %A" vMin
Хафвей через кодированию, я понял, что я мог сделать все расчеты с использованием только int
, это было только последние расчеты, сгенерированные проценты, которые должны быть float
или double
, и даже тогда это только потому, что список ответов - это процент; в теории числа можно сравнить как int
, чтобы получить то же понимание. Если я использую только int
, тогда мне нужно будет создать тип матрицы int
, и это больше, чем я хочу. Когда я получу время, я переключу MathNet Matrix на F # Array2D или что-то подобное и проверьте это. Обратите внимание, что если вы пометили его MathNet
, то ответственный за MathNet
может ответить (Christoph Rüegg)
Я внесла изменения в этот метод, и он быстрее на 5 секунд.
// faster
let minHeads (m : Matrix<float>) (numberOfCoins : int) (numberOfFlips : int) : int =
let (mins : float[]) = m.FoldByRow((fun (x : float) y -> x + y), 0.0)
let (minHead : float) = Array.min mins
System.Convert.ToInt32(minHead)
Это первое упражнение с домашней работы на 2-й неделе. –
Я скопировал в свой вопрос полную формулировку упражнения! Во всяком случае, вот ссылка: http://work.caltech.edu/homework/hw2.pdf –
Вы просили об идиоматическом F #, позволяет ли это использовать библиотеки, обычно используемые с F #, и которые имеют функции для использования с F # такими как [MathNet Numerics] (http://numerics.mathdotnet.com/)? Если нет, то я, вероятно, перейду к этому вопросу. –