2016 Update

This commit is contained in:
Tina Müller 2016-12-05 22:15:40 +01:00
parent 948b86eafa
commit dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions

View file

@ -1,6 +1,8 @@
The objective of this task is to create a reasonably complete implementation of rational arithmetic in the particular language using the idioms of the language.
;Task:
Create a reasonably complete implementation of rational arithmetic in the particular language using the idioms of the language.
For example:
;Example:
Define a new type called '''frac''' with binary operator "//" of two integers that returns a '''structure''' made up of the numerator and the denominator (as per a rational number).
Further define the appropriate rational unary '''operators''' '''abs''' and '-', with the binary '''operators''' for addition '+', subtraction '-', multiplication '&times;', division '/', integer division '&divide;', modulo division, the comparison operators (e.g. '<', '&le;', '>', & '&ge;') and equality operators (e.g. '=' & '&ne;').
@ -12,5 +14,7 @@ If space allows, define standard increment and decrement '''operators''' (e.g. '
Finally test the operators:
Use the new type '''frac''' to find all [[Perfect Numbers|perfect numbers]] less than 2<sup>19</sup> by summing the reciprocal of the factors.
'''See also'''
* [[Perfect Numbers]]
;Related task:
* &nbsp; [[Perfect Numbers]]
<br><br>

View file

@ -0,0 +1,66 @@
defmodule Rational do
import Kernel, except: [div: 2]
defstruct numerator: 0, denominator: 1
def new(numerator), do: %Rational{numerator: numerator, denominator: 1}
def new(numerator, denominator) do
sign = if numerator * denominator < 0, do: -1, else: 1
{numerator, denominator} = {abs(numerator), abs(denominator)}
gcd = gcd(numerator, denominator)
%Rational{numerator: sign * Kernel.div(numerator, gcd),
denominator: Kernel.div(denominator, gcd)}
end
def add(a, b) do
{a, b} = convert(a, b)
new(a.numerator * b.denominator + b.numerator * a.denominator,
a.denominator * b.denominator)
end
def sub(a, b) do
{a, b} = convert(a, b)
new(a.numerator * b.denominator - b.numerator * a.denominator,
a.denominator * b.denominator)
end
def mult(a, b) do
{a, b} = convert(a, b)
new(a.numerator * b.numerator, a.denominator * b.denominator)
end
def div(a, b) do
{a, b} = convert(a, b)
new(a.numerator * b.denominator, a.denominator * b.numerator)
end
defp convert(a), do: if is_integer(a), do: new(a), else: a
defp convert(a, b), do: {convert(a), convert(b)}
defp gcd(a, 0), do: a
defp gcd(a, b), do: gcd(b, rem(a, b))
end
defimpl Inspect, for: Rational do
def inspect(r, _opts) do
"%Rational<#{r.numerator}/#{r.denominator}>"
end
end
Enum.each(2..trunc(:math.pow(2,19)), fn candidate ->
sum = 2 .. round(:math.sqrt(candidate))
|> Enum.reduce(Rational.new(1, candidate), fn factor,sum ->
if rem(candidate, factor) == 0 do
Rational.add(sum, Rational.new(1, factor))
|> Rational.add(Rational.new(1, div(candidate, factor)))
else
sum
end
end)
if sum.denominator == 1 do
:io.format "Sum of recipr. factors of ~6w = ~w exactly ~s~n",
[candidate, sum.numerator, (if sum.numerator == 1, do: "perfect!", else: "")]
end
end)

View file

@ -0,0 +1,11 @@
1/2 + 2/3
// 7/6 (approx. 1.1666666666666667)
1/2 + 1/2
// 1
5/sextillion + 3/quadrillion
// 600001/200000000000000000000 (exactly 3.000005e-15)
8^(1/3)
// 2 (note the exact integer result.)

View file

@ -1,2 +1,4 @@
3r4*2r5
3r10
(x: 3) % (x: -4)
_3r4
3 %&x: -4
_3r4

View file

@ -0,0 +1,2 @@
(#~ is_perfect_rational"0) (* <:@+:) 2^i.10x
6 28 496 8128

View file

@ -1 +1,28 @@
is_perfect_rational=: 2 = (1 + i.) +/@:%@([ #~ 0 = |) ]
| _3r4 NB. absolute value
3r4
-2r5 NB. negation
_2r5
3r4+2r5 NB. addition
23r20
3r4-2r5 NB. subtraction
7r20
3r4*2r5 NB. multiplication
3r10
3r4%2r5 NB. division
15r8
3r4 <.@% 2r5 NB. integer division
1
3r4 (-~ <.)@% 2r5 NB. remainder
_7r8
3r4 < 2r5 NB. less than
0
3r4 <: 2r5 NB. less than or equal
0
3r4 > 2r5 NB. greater than
1
3r4 >: 2r5 NB. greater than or equal
1
3r4 = 2r5 NB. equal
0
3r4 ~: 2r5 NB. not equal
1

View file

@ -1,2 +1,4 @@
factors=: */&>@{@((^ i.@>:)&.>/)@q:~&__
is_perfect_rational=: 2= +/@:%@,@factors
x: 3%4
3r4
x:inv 3%4
0.75

View file

@ -1,4 +1,4 @@
I.is_perfect_rational@"0 i.2^19
6 28 496 8128
I.is_perfect_rational@x:@"0 i.2^19x
6 28 496 8128
>: 3r4
7r4
<: 3r4
_1r4

View file

@ -1,2 +1,7 @@
(#~ is_perfect_rational"0) (* <:@+:) 2^i.10x
6 28 496 8128
mutadd=:adverb define
(m)=: (".m)+y
)
mutsub=:adverb define
(m)=: (".m)-y
)

View file

@ -0,0 +1,7 @@
n=: 3r4
'n' mutadd 1
7r4
'n' mutsub 1
3r4
'n' mutsub 1
_1r4

View file

@ -0,0 +1 @@
is_perfect_rational=: 2 = (1 + i.) +/@:%@([ #~ 0 = |) ]

View file

@ -0,0 +1,2 @@
factors=: */&>@{@((^ i.@>:)&.>/)@q:~&__
is_perfect_rational=: 2= +/@:%@,@factors

View file

@ -0,0 +1,4 @@
I.is_perfect_rational@"0 i.2^19
6 28 496 8128
I.is_perfect_rational@x:@"0 i.2^19x
6 28 496 8128

View file

@ -0,0 +1,21 @@
(* 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

View file

@ -0,0 +1,58 @@
(* 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

View file

@ -0,0 +1,14 @@
(* 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

View file

@ -5,7 +5,7 @@ for 2..2**19 -> $candidate {
$sum += 1 / $factor + 1 / ($candidate / $factor);
}
}
if $sum.denominator == 1 {
if $sum.nude[1] == 1 {
say "Sum of reciprocal factors of $candidate = $sum exactly", ($sum == 1 ?? ", perfect!" !! ".");
}
}

View file

@ -0,0 +1,133 @@
use std::cmp::Ordering;
use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Neg};
fn gcd(a: i64, b: i64) -> i64 {
match b {
0 => a,
_ => gcd(b, a % b),
}
}
fn lcm(a: i64, b: i64) -> i64 {
a / gcd(a, b) * b
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord)]
pub struct Rational {
numerator: i64,
denominator: i64,
}
impl Rational {
fn new(numerator: i64, denominator: i64) -> Self {
let divisor = gcd(numerator, denominator);
Rational {
numerator: numerator / divisor,
denominator: denominator / divisor,
}
}
}
impl Add for Rational {
type Output = Self;
fn add(self, other: Self) -> Self {
let multiplier = lcm(self.denominator, other.denominator);
Rational::new(self.numerator * multiplier / self.denominator +
other.numerator * multiplier / other.denominator,
multiplier)
}
}
impl AddAssign for Rational {
fn add_assign(&mut self, other: Self) {
*self = *self + other;
}
}
impl Sub for Rational {
type Output = Self;
fn sub(self, other: Self) -> Self {
self + -other
}
}
impl SubAssign for Rational {
fn sub_assign(&mut self, other: Self) {
*self = *self - other;
}
}
impl Mul for Rational {
type Output = Self;
fn mul(self, other: Self) -> Self {
Rational::new(self.numerator * other.numerator,
self.denominator * other.denominator)
}
}
impl MulAssign for Rational {
fn mul_assign(&mut self, other: Self) {
*self = *self * other;
}
}
impl Div for Rational {
type Output = Self;
fn div(self, other: Self) -> Self {
self *
Rational {
numerator: other.denominator,
denominator: other.numerator,
}
}
}
impl DivAssign for Rational {
fn div_assign(&mut self, other: Self) {
*self = *self / other;
}
}
impl Neg for Rational {
type Output = Self;
fn neg(self) -> Self {
Rational {
numerator: -self.numerator,
denominator: self.denominator,
}
}
}
impl PartialOrd for Rational {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
(self.numerator * other.denominator).partial_cmp(&(self.denominator * other.numerator))
}
}
impl<T: Into<i64>> From<T> for Rational {
fn from(value: T) -> Self {
Rational::new(value.into(), 1)
}
}
fn main() {
let max = 1 << 19;
for candidate in 2..max {
let mut sum = Rational::new(1, candidate);
for factor in 2..(candidate as f64).sqrt().ceil() as i64 {
if candidate % factor == 0 {
sum += Rational::new(1, factor);
sum += Rational::new(1, candidate / factor);
}
}
if sum == 1.into() {
println!("{} is perfect", candidate);
}
}
}