Reputation: 35
I'm currently trying to get into programming with F#. Therefore I wrote a simple F# script to calculate PI in a very silly way. I've written this algorithm in many programming languages but this time it is pretty slow in execution and I don't know what I'm doing wrong. Compared to my Java Version this here is about 10-20 times slower (about 10-15 sek on my machine running in VS Code by pressing Alt+Enter) which is a lot (in my opinion).
The algorithms idea is to throw darts at an 1 by 1 square with an circle in it. The circle touches the edges of the square. If a dart hits the circle it gets counted. After all darts are thrown you just divide the dart hit count by the total number of darts and multiply by 4 to get PI.
I've tried many things to get my error but couldn't find it.
PS: I know that this method to calc Pi sucks. But this is not the point I try to make here.
open System
let random = Random(DateTime.Now.Millisecond)
let throwDart i = (random.NextDouble(), random.NextDouble())
let distance dart point = let (x1, y1), (x2, y2) = dart, point
(x2 - x1, y2 - y1)
let length distance = let (x, y) = distance
Math.Sqrt(x * x + y * y)
let isInside circle dartHit =
let (center, radius) = circle
distance center dartHit |> length |> (fun x -> x < radius)
let circle = ((0.5, 0.5), 0.5)
let dartCount = 100000000
let dartSeqence = Seq.init dartCount throwDart
let pi = float(dartSeqence |> Seq.filter (isInside circle) |> Seq.length) / float(dartCount) * 4.0
Maybe someone has an idea what I am doing wrong. I hoped that F# would do well in this task because its a pretty simple and straight algorithm.
Thanks for the help in advance.
Update 1:
Hi after running my Java code again I was a bit disappointed, because I thought it was faster. This is the code running for approx. 4.4 sec on my machine:
import java.util.Random;
public class DartThrower{
Random random;
public DartThrower(){
random = new Random();
}
public boolean throwDart(){
double x = random.nextDouble();
double y = random.nextDouble();
// wenn Entfernung des Punktes vom Mittelpunkt (0.5|0.5) größer als 0.5 ist wird false ausgegeben
boolean inTheCircle = Math.sqrt((0.5 - x) * (0.5 - x) + (0.5 - y) * (0.5 - y)) <= 0.5;
return inTheCircle;
}
}
class PiCalculator{
public static void main(String[] args){
long start = System.currentTimeMillis();
double hitCount = 0.0;
double throwCount = 100000000L;
DartThrower thrower = new DartThrower();
for (long i = 0; i < throwCount; i++){
boolean hit = thrower.throwDart();
hitCount += hit ? 1 : 0;
}
double a = hitCount / throwCount;
double pi = a * 4.0;
System.out.println("Pi= " + pi);
System.out.println("took " + (System.currentTimeMillis() - start) + "ms");
}
}
I'm sorry, but I thought the time was under 1s - thats why I was talking about a 10-20 times faster execution. That's not correct! After I had relaized how wrong I was in the timing, I decided to add some Timestamps for both and got
So factor 3-4 between those two. This difference might by obsolete if I try to use @Tomas Petricek's performance updates. I'll try that and tell you the results.
Thanks for your help so far.
Upvotes: 1
Views: 213
Reputation: 243051
You can make this about 2x faster by replacing the lazy sequence with a simple mutable variable and a for
loop (there is nothing bad about this in performance critical F# code):
let mutable count = 0
for i in 0 .. dartCount do
if isInside circle (throwDart i) then count <- count + 1
let pi = float count / float dartCount * 4.0
You can add a bit more performance (about 30% in my rough tests) by making the functions inline
, which may eliminate some boxing of values as tuples:
let inline distance dart point =
let (x1, y1), (x2, y2) = dart, point
(x2 - x1, y2 - y1)
let inline length distance =
let (x, y) = distance
Math.Sqrt(x * x + y * y)
let inline isInside circle dartHit =
let (center, radius) = circle
length (distance center dartHit) < radius
With this, I do not see any obvious issues (but I may be missing something). It would be good to see your Java code for comparison, because there may be some subtle logic change that affects the performance.
Upvotes: 6