Scala中Pi的Monte Carlo计算
假设我想用蒙特卡洛模拟作为练习来计算Pi.
Suppose I would like to calculate Pi with Monte Carlo simulation as an exercise.
我正在编写一个函数,该函数随机选择正方形(0, 1), (1, 0)
中的一个点,并测试该点是否在圆内.
I am writing a function, which picks a point in a square (0, 1), (1, 0)
at random and tests if the point is inside the circle.
import scala.math._
import scala.util.Random
def circleTest() = {
val (x, y) = (Random.nextDouble, Random.nextDouble)
sqrt(x*x + y*y) <= 1
}
然后我正在编写一个函数,该函数将测试函数和试验次数作为参数,并返回其中发现测试为真的试验分数.
Then I am writing a function, which takes as arguments the test function and the number of trials and returns the fraction of the trials in which the test was found to be true.
def monteCarlo(trials: Int, test: () => Boolean) =
(1 to trials).map(_ => if (test()) 1 else 0).sum * 1.0 / trials
...我可以计算出Pi
... and I can calculate Pi
monteCarlo(100000, circleTest) * 4
现在,我想知道是否可以改善monteCarlo
功能.您将如何高效且易读地编写monteCarlo
?
Now I wonder if monteCarlo
function can be improved. How would you write monteCarlo
efficient and readable ?
例如,由于试验次数很多,是否值得使用view
或iterator
代替Range(1, trials)
和reduce
代替map
和sum
?
For example, since the number of trials is large is it worth using a view
or iterator
instead of Range(1, trials)
and reduce
instead of map
and sum
?
基于流的版本,作为另一种选择.我认为这很清楚.
Stream based version, for another alternative. I think this is quite clear.
def monteCarlo(trials: Int, test: () => Boolean) =
Stream
.continually(if (test()) 1.0 else 0.0)
.take(trials)
.sum / trials
(sum
不是专用于流的,但是实现(在TraversableOnce中)只是调用专用的foldLeft
,并且允许GC进行收集."因此,.sum不会强制该流.进行评估,因此不会一次将所有试验保存在内存中
(the sum
isn't specialised for streams but the implementation (in TraversableOnce) just calls foldLeft
that is specialised and "allows GC to collect along the way." So the .sum won't force the stream to be evaluated and so won't keep all the trials in memory at once)