RosettaCodeData/Task/Least-common-multiple/ATS/least-common-multiple.ats
2023-07-01 13:44:08 -04:00

102 lines
3.3 KiB
Text
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#define ATS_DYNLOADFLAG 0 (* No initialization is needed. *)
#include "share/atspre_define.hats"
#include "share/atspre_staload.hats"
(********************************************************************)
(* *)
(* Declarations. *)
(* *)
(* (These could be ported to a .sats file.) *)
(* *)
(* lcm for unsigned integer types without constraints. *)
extern fun {tk : tkind}
g0uint_lcm (u : g0uint tk,
v : g0uint tk) :<>
g0uint tk
(* The gcd template function to be expanded when g0uint_lcm is
expanded. Set it to your favorite gcd function. *)
extern fun {tk : tkind}
g0uint_lcm$gcd (u : g0uint tk,
v : g0uint tk) :<>
g0uint tk
(* lcm for signed integer types, giving unsigned results. *)
extern fun {tk_signed, tk_unsigned : tkind}
g0int_lcm (u : g0int tk_signed,
v : g0int tk_signed) :<>
g0uint tk_unsigned
overload lcm with g0uint_lcm
overload lcm with g0int_lcm
(********************************************************************)
(* *)
(* The implementations. *)
(* *)
implement {tk}
g0uint_lcm (u, v) =
let
val d = g0uint_lcm$gcd<tk> (u, v)
in
(* There is no need to take the absolute value, because this
implementation is strictly for unsigned integers. *)
(u * v) / d
end
implement {tk_signed, tk_unsigned}
g0int_lcm (u, v) =
let
extern castfn
unsigned :
g0int tk_signed -<> g0uint tk_unsigned
in
g0uint_lcm (unsigned (abs u), unsigned (abs v))
end
(********************************************************************)
(* *)
(* A test that it actually works. *)
(* *)
implement
main0 () =
let
implement {tk}
g0uint_lcm$gcd (u, v) =
(* An ugly gcd for the sake of demonstrating that it can be done
this way: Euclids algorithm written an the Algol style,
which is not a natural style in ATS. Almost always you want
to write a tail-recursive function, instead. I did, however
find the Algol style very useful when I was migrating
matrix routines from Fortran.
In reality, you would implement g0uint_lcm$gcd by having it
simply call whatever gcd template function you are using in
your program. *)
$effmask_all
begin
let
var x : g0uint tk = u
var y : g0uint tk = v
in
while (y <> 0)
let
val z = y
in
y := x mod z;
x := z
end;
x
end
end
in
assertloc (lcm (~6, 14) = 42U);
assertloc (lcm (2L, 0L) = 0ULL);
assertloc (lcm (12UL, 18UL) = 36UL);
assertloc (lcm (12, 22) = 132ULL);
assertloc (lcm (7ULL, 31ULL) = 217ULL)
end