Arithmetic/Rational: Difference between revisions
Content added Content deleted
(→{{header|Rust}}: Add Rust example) |
|||
Line 2,324: | Line 2,324: | ||
candidate Num.(to_int !sum) (if Num.(!sum = 1) then "perfect!" else "") |
candidate Num.(to_int !sum) (if Num.(!sum = 1) then "perfect!" else "") |
||
done</lang> |
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}}== |
=={{header|ooRexx}}== |