abstype array2 (a:t@ype)
extern fun{a:t@ype}
array2_make_elt (nrow: int, ncol: int, ini: a): array2 a
extern fun{a:t@ype}
array2_get_elt_at (A: array2 a, ncol: int, i: int, j: int): a
extern fun{a:t@ype}
array2_set_elt_at (A: array2 a, ncol: int, i: int, j: int, x: a): void
staload _ = "prelude/DATS/array0.dats"
local
assume array2 (a:t@ype) = array0 (a)
in
implement{a:t@ype} array2_make_elt (nrow, ncol, ini) = let
val asz = nrow * ncol
val asz = int1_of_int asz
val () = assert (asz >= 0)
val asz = size_of_int1 (asz)
in
array0_make_elt (asz, ini)
end
implement{a}
array2_get_elt_at (A, ncol, i, j) = let
val n = i * ncol + j
val n = int1_of_int n
val () = assert (n >= 0)
val n = size_of_int1 (n)
in
array0_get_elt_at<a> (A, n)
end
implement{a}
array2_set_elt_at (A, ncol, i, j, x) = let
val n = i * ncol + j
val n = int1_of_int n
val () = assert (n >= 0)
val n = size_of_int1 (n)
in
array0_set_elt_at<a> (A, n, x)
end
end
staload Math = "libc/SATS/math.sats"
#define DOUBLE_FOR_REAL 1
#if DOUBLE_FOR_REAL #then
typedef real = double
macdef real_of_double(x) = ,(x)
macdef int_of_real(x) = int_of_double ,(x)
macdef sqrt_real(x) = $Math.sqrt ,(x)
#endif
#define FLOAT_FOR_REAL 0
#if FLOAT_FOR_REAL #then
typedef real = float
macdef real_of_double(x) = float_of_double ,(x)
macdef int_of_real(x) = int_of_float ,(x)
macdef sqrt_real(x) = $Math.sqrtf ,(x)
#endif
typedef point = @(real, real)
fun square (x: real): real = x * x
fun dist_pt_pt (pt1: point, pt2: point) = let
val dx = pt1.0 - pt2.0 and dy = pt1.1 - pt2.1
in
sqrt_real (dx * dx + dy * dy)
end
#define N 1000
val NN: int = N * N
val NN_1: double = 1.0 / NN
val epsilon = real_of_double (1.0 / N)
typedef pointlst = list0 (point)
val thePointlstArray = array2_make_elt<pointlst> (N, N, list0_nil)
fun thePointlstArray_clear () = loop1 (0) where {
fn* loop1 (i: int): void = if i < N then loop2 (i, 0) else ()
and loop2 (i: int, j: int): void =
if j < N then let
in
array2_set_elt_at (thePointlstArray, N, i, j, list0_nil); loop2 (i, j+1)
end else loop1 (i+1)
}
staload Rand = "libc/SATS/random.sats"
extern fun rand_real (): real
implement rand_real () = real_of_double ($Rand.drand48 () * (1.0 - NN_1))
extern fun do_one_square
(pt: point, i: int, j: int ): int
implement do_one_square (pt, i, j) = let
val pts = array2_get_elt_at (thePointlstArray, N, i, j)
fun loop (pt0: point, pts: pointlst, res: int): int =
case+ pts of
| list0_cons (pt, pts) => let
val dist = dist_pt_pt (pt, pt0) in
if dist >= epsilon then loop (pt0, pts, res)
else loop (pt0, pts, res+1)
end | list0_nil () => res
in
loop (pt, pts, 0)
end
fun do_all_squares .<>.
(pt: point, Nx: int, Ny: int): int = res where {
var i: int = 0 and j: int = 0; var res: int = 0
val () = for (i := Nx-1; i <= Nx+1; i := i+1) let
val () = if i < 0 then continue else (if i >= N then break else ())
val () = for (j := Ny-1; j <= Ny+1; j := j+1) let
val () = if j < 0 then continue else (if j >= N then break else ())
in
res := res + do_one_square (pt, i, j)
end
in
end
}
fun do_one_round (): int = res where {
val px = rand_real () and py = rand_real ()
val pt = @(px, py)
val Nx: int = int_of_real (N * px)
val Ny: int = int_of_real (N * py)
val res = do_all_squares (pt, Nx, Ny)
val pts =
array2_get_elt_at (thePointlstArray, N, Nx, Ny)
val () = array2_set_elt_at
(thePointlstArray, N, Nx, Ny, list0_cons (pt, pts))
}
fun do_all_rounds (): int = loop (0, 0) where {
fun loop (i: int, res: int): int =
if i < NN then loop (i+1, res + do_one_round ()) else res
val () = thePointlstArray_clear ()
}
implement main () = let
val () = $Rand.srand48_with_time ()
#define TIMES 10
val PI = 2.0 * loop (TIMES, 0) / (TIMES * (NN - N)) where {
fun loop (n: int, res: int): int =
if n > 0 then loop (n-1, res + do_all_rounds ()) else res
}
in
printf ("PI = %.6f\n", @(PI))
end