Arithmetic/Rational: Difference between revisions

(→‎{{header|Rust}}: Add Rust example)
Line 2,324:
candidate Num.(to_int !sum) (if Num.(!sum = 1) then "perfect!" else "")
done</lang>
It might be implemented like this:
 
A type for rational numbers might be implemented like this:
[insert implementation here]
 
First define the interface, hiding implementation details:
<lang ocaml>(* interface *)
module type RATIO =
sig
type t
(* construct *)
val frac : int -> int -> t
val from_int : int -> t
 
(* integer test *)
val is_int : t -> bool
 
(* output *)
val to_string : t -> string
 
(* arithmetic *)
val cmp : t -> t -> int
val ( +/ ) : t -> t -> t
val ( -/ ) : t -> t -> t
val ( */ ) : t -> t -> t
val ( // ) : t -> t -> t
end</lang>
 
then implement the module:
<lang ocaml>(* implementation conforming to signature *)
module Frac : RATIO =
struct
open Big_int
 
type t = { num : big_int; den : big_int }
(* short aliases for big_int values and functions *)
let zero, one = zero_big_int, unit_big_int
let big, to_int, eq = big_int_of_int, int_of_big_int, eq_big_int
let (+~), (-~), ( *~) = add_big_int, sub_big_int, mult_big_int
(* helper function *)
let rec norm ({num=n;den=d} as k) =
if lt_big_int d zero then
norm {num=minus_big_int n;den=minus_big_int d}
else
let rec hcf a b =
let q,r = quomod_big_int a b in
if eq r zero then b else hcf b r in
let f = hcf n d in
if eq f one then k else
let div = div_big_int in
{ num=div n f; den = div d f } (* inefficient *)
(* public functions *)
let frac a b = norm { num=big a; den=big b }
let from_int a = norm { num=big a; den=one }
 
let is_int {num=n; den=d} =
eq d one ||
eq (mod_big_int n d) zero
let to_string ({num=n; den=d} as r) =
let r1 = norm r in
let str = string_of_big_int in
if is_int r1 then
str (r1.num)
else
str (r1.num) ^ "/" ^ str (r1.den)
let cmp a b =
let a1 = norm a and b1 = norm b in
compare_big_int (a1.num*~b1.den) (b1.num*~a1.den)
 
let ( */ ) {num=n1; den=d1} {num=n2; den=d2} =
norm { num = n1*~n2; den = d1*~d2 }
 
let ( // ) {num=n1; den=d1} {num=n2; den=d2} =
norm { num = n1*~d2; den = d1*~n2 }
let ( +/ ) {num=n1; den=d1} {num=n2; den=d2} =
norm { num = n1*~d2 +~ n2*~d1; den = d1*~d2 }
let ( -/ ) {num=n1; den=d1} {num=n2; den=d2} =
norm { num = n1*~d2 -~ n2*~d1; den = d1*~d2 }
end</lang>
 
Finally the use type defined by the module to perform the perfect number calculation:
<lang ocaml>(* use the module to calculate perfect numbers *)
let () =
for i = 2 to 1 lsl 19 do
let sum = ref (Frac.frac 1 i) in
for factor = 2 to truncate (sqrt (float i)) do
if i mod factor = 0 then
Frac.(
sum := !sum +/ frac 1 factor +/ frac 1 (i / factor)
)
done;
if Frac.is_int !sum then
Printf.printf "Sum of reciprocal factors of %d = %s exactly %s\n%!"
i (Frac.to_string !sum) (if Frac.to_string !sum = "1" then "perfect!" else "")
done</lang>
which produces this output:
 
Sum of reciprocal factors of 6 = 1 exactly perfect!
Sum of reciprocal factors of 28 = 1 exactly perfect!
Sum of reciprocal factors of 120 = 2 exactly
Sum of reciprocal factors of 496 = 1 exactly perfect!
Sum of reciprocal factors of 672 = 2 exactly
Sum of reciprocal factors of 8128 = 1 exactly perfect!
Sum of reciprocal factors of 30240 = 3 exactly
Sum of reciprocal factors of 32760 = 3 exactly
Sum of reciprocal factors of 523776 = 2 exactly
 
=={{header|ooRexx}}==
Anonymous user