@ -15,131 +15,147 @@ open System.Numerics
open S y s t e m . G l o b a l i z a t i o n
[ < A u t o O p e n > ]
module private BigRationalLargeImpl =
let ZeroI = BigInteger ( 0 )
let OneI = BigInteger ( 1 )
let bigint (x : int) = BigInteger ( x )
let ToDoubleI (x : BigInteger) = float x
let ToInt32I (x : BigInteger) = int32 x
[<CustomEquality; C u s t o m C o m p a r i s o n > ]
type BigRationalLarge =
// invariants: (p,q) in lowest form, q >= 0
| Q of BigInteger * B i g I n t e g e r
member x.IsNegative =
let (Q (ap, _)) = x
sign ap < 0
// invariants: (p,q) in lowest form, q >= 0
[ < S e a l e d > ]
type BigRationalLarge (p : BigInteger, q : BigInteger) =
/ /
member __.IsNegative =
sign p < 0
member x.IsPositive =
let (Q (ap, _)) = x
sign a p > 0
/ /
member __.IsPositive =
sign p > 0
member x.Numerator =
let (Q (p, _)) = x in p
/ /
member __.Numerator = p
member x.Denominator =
let (Q (_, q)) = x in q
/ /
member __.Denominator = q
member x.Sign =
let (Q (p,_) ) = x
/ /
member __.Sign =
sign p
override this.GetHashCode () =
BigRationalLarge.Hash t h i s
override __.GetHashCode () =
// This hash code must be identical to the hash for BigInteger when the numbers c o i n c i d e .
if q.IsOne then p.GetHashCode ( )
else (p.GetHashCode () <<< 3 ) + q.GetHashCode ( )
override this.ToString () =
let (Q (p, q)) = t h i s
override __.ToString () =
if q.IsOne t h e n
p . T o S t r i n g ( )
p.ToString ( )
e l s e
p.ToString() + "/" + q . T o S t r i n g ( )
static member Hash (Q (ap, aq)) =
// This hash code must be identical to the hash for BigInteger when the numbers c o i n c i d e .
if aq.IsOne then ap.GetHashCode ( )
else (ap.GetHashCode () <<< 3 ) + aq.GetHashCode ( )
p.ToString () + "/" + q.ToString ( )
static member Equals(Q (ap, aq), Q (bp, bq)) =
/ /
static member Equals (x : BigRationalLarge, y : BigRationalLarge) =
// normal form, so structural e q u a l i t y
BigInteger.(=) (ap, bp) && BigInteger.(=) (aq, b q )
static member LessThan (Q (ap, aq), Q (bp, bq)) =
BigInteger.(<) (ap * bq, bp * a q )
x.Numerator = y.Numerator && x.Denominator = y . D e n o m i n a t o r
// TODO: performance improvement possible h e r e
static member Compare (p, q) =
if BigRationalLarge.LessThan (p, q) then -1
elif BigRationalLarge.LessThan (q, p)then 1
else 0
/ /
static member Compare (x : BigRationalLarge, y : BigRationalLarge) =
compare (x.Numerator * y.Denominator) (y.Numerator * x . D e n o m i n a t o r )
static member ToDouble (Q (p, q)) =
ToDoubleI p / ToDoubleI q
/ /
static member ToDouble (num : BigRationalLarge) =
float num.Numerator / float n u m . D e n o m i n a t o r
/ /
static member Normalize (p : BigInteger, q : BigInteger) =
if q.IsZero t h e n
(* throw for any x/0 * )
raise <| System.DivideByZeroException ( )
elif q.IsOne t h e n
Q (p, q )
BigRationalLarge (p, q )
e l s e
let k = BigInteger.GreatestCommonDivisor (p, q )
let p = p / k
let q = q / k
if sign q < 0 t h e n
Q (-p, - q )
else Q (p, q )
BigRationalLarge (-p, - q )
e l s e
BigRationalLarge (p, q )
static member Rational (p : int, q : int) =
/ /
static member Create (p : int, q : int) =
BigRationalLarge.Normalize (bigint p, bigint q )
// TODO : Rename to Rational? It doesn't seem like we need to force the overload resolution here with a separate n a m e ...
static member RationalZ (p, q) =
/ /
static member Create (p, q) =
BigRationalLarge.Normalize (p, q )
/// Return the given rational n u m b e r
static member (~+) (n1 : BigRationalLarge) = n 1
/// Return the negation of a rational n u m b e r
static member (~-) (Q (bp, bq)) =
static member (~-) (num : BigRationalLarge ) =
// still coprime, bq >= 0
Q(-bp, b q )
BigRationalLarge (-num.Numerator, n u m . D e n o m i n a t o r )
/// Return the sum of two rational n u m b e r s
static member (+) (Q (ap, aq), Q (bp, bq) ) =
BigRationalLarge.Normalize ((ap * bq) + (bp * aq), aq * b q )
static member (+) (x : BigRationalLarge, y : BigRationalLarge ) =
BigRationalLarge.Normalize ((x.Numerator * y.Denominator) + (y.Numerator * x.Denominator), x.Denominator * y . D e n o m i n a t o r )
/// Return the difference of two rational n u m b e r s
static member (-) (Q (ap, aq), Q (bp, bq) ) =
BigRationalLarge.Normalize ((ap * bq) - (bp * aq), aq * b q )
static member (-) (x : BigRationalLarge, y : BigRationalLarge ) =
BigRationalLarge.Normalize ((x.Numerator * y.Denominator) - (y.Numerator * x.Denominator), x.Denominator * y . D e n o m i n a t o r )
/// Return the product of two rational n u m b e r s
static member (*) (Q (ap, aq), Q (bp, bq) ) =
BigRationalLarge.Normalize (ap * bp, aq * b q )
static member (*) (x : BigRationalLarge, y : BigRationalLarge ) =
BigRationalLarge.Normalize (x.Numerator * y.Numerator, x.Denominator * y . D e n o m i n a t o r )
/// Return the ratio of two rational n u m b e r s
static member (/) (Q (ap, aq), Q (bp, bq) ) =
BigRationalLarge.Normalize (ap * bq, aq * b p )
static member (/) (x : BigRationalLarge, y : BigRationalLarge ) =
BigRationalLarge.Normalize (x.Numerator * y.Denominator, x.Denominator * y . N u m e r a t o r )
/// Return the given rational n u m b e r
static member ( ~+ ) (n1 : BigRationalLarge) = n 1
/ /
static member Reciprocal (num : BigRationalLarge) =
BigRationalLarge.Normalize (num.Denominator, n u m . N u m e r a t o r )
/ /
static member PowN (num : BigRationalLarge, n : int) =
// p,q powers still c o p r i m e
BigRationalLarge (BigInteger.Pow (num.Numerator, n), BigInteger.Pow (num.Denominator, n ) )
/ /
static member FromBigInteger z =
BigRationalLarge.Create (z, B i g I n t e g e r . O n e )
/ /
static member FromInt32 n =
BigRationalLarge.Create (n, 1 )
/// Returns the integer part of a rational n u m b e r .
static member ToBigInteger (num : BigRationalLarge) =
// have p = d.q + r, |r| < | q |
let d, r = BigInteger.DivRem (num.Numerator, n u m . D e n o m i n a t o r )
if r < BigInteger.Zero t h e n
// p = (d-1).q + ( r + q )
d - B i g I n t e g e r . O n e
e l s e
// p = d.q + r
d
/ /
static member Parse (str : string) =
let len = s t r . L e n g t h
if len=0 then invalidArg "str" "empty s t r i n g " ;
if len = 0 t h e n
invalidArg "str" "empty s t r i n g "
let j = str.IndexOf ' / '
if j >= 0 t h e n
let p = BigInteger.Parse ( s t r . S u b s t r i n g ( 0 , j ) )
let q = BigInteger.Parse ( s t r . S u b s t r i n g ( j +1 , l e n - j -1 ) )
BigRationalLarge.RationalZ ( p , q )
let p = BigInteger.Parse (str.Substring (0, j ) )
let q = BigInteger.Parse (str.Substring (j + 1 , len - j - 1 ) )
BigRationalLarge.Create (p, q )
e l s e
let p = BigInteger.Parse s t r
BigRationalLarge.RationalZ ( p , O n e I )
BigRationalLarge.Create (p, B i g I n t e g e r . O n e )
override this.Equals(that : obj) =
override this.Equals (that : obj) =
match that w i t h
| :? BigRationalLarge as that - >
B i g R a t i o n a l L a r g e . E q u a l s ( t h i s , t h a t )
BigRationalLarge.Equals (this, t h a t )
| _ -> f a l s e
interface System.IComparable w i t h
@ -150,67 +166,15 @@ type BigRationalLarge =
| _ - >
invalidArg "obj" "the object does not have the correct t y p e "
/ /
[<RequireQualifiedAccess; C o m p i l a t i o n R e p r e s e n t a t i o n ( C o m p i l a t i o n R e p r e s e n t a t i o n F l a g s . M o d u l e S u f f i x ) > ]
module private BigRationalLarge =
/ /
let inv (Q (ap, aq)) =
BigRationalLarge.Normalize (aq, a p )
/ /
let pown (Q (p, q)) (n:int) =
// p,q powers still c o p r i m e
Q (BigInteger.Pow (p, n), BigInteger.Pow (q, n ) )
/ /
let equal (Q (ap, aq)) (Q (bp, bq)) =
// normal form, so structural e q u a l i t y
ap = bp && aq = b q
/ /
let lt a b =
BigRationalLarge.LessThan (a, b )
/ /
let gt a b =
BigRationalLarge.LessThan (b, a )
/ /
let lte (Q(ap, aq)) (Q(bp, bq)) =
BigInteger.(<=) (ap * bq,bp * a q )
/ /
let gte (Q(ap, aq)) (Q(bp, bq)) =
BigInteger.(>=) (ap * bq, bp * a q )
/ /
let of_bigint z =
B i g R a t i o n a l L a r g e . R a t i o n a l Z ( z , O n e I )
/ /
let of_int n =
B i g R a t i o n a l L a r g e . R a t i o n a l ( n , 1 )
// integer p a r t
let integer (Q (p, q)) =
let mutable r = B i g I n t e g e r ( 0 )
// have p = d.q + r, |r| < | q |
let d = BigInteger.DivRem (p, q, & r )
if r < ZeroI t h e n
// p = (d-1).q + ( r + q )
d - O n e I
e l s e
// p = d.q + r
d
interface System.IComparable<BigRationalLarge> w i t h
member this.CompareTo other =
BigRationalLarge.Compare (this, o t h e r )
/// The type of arbitrary-sized rational n u m b e r s .
[<CustomEquality; C u s t o m C o m p a r i s o n > ]
[ < S t r u c t u r e d F o r m a t D i s p l a y ( " { S t r u c t u r e d D i s p l a y S t r i n g } N " ) > ]
type BigRational =
p r i v a t e
/ /
| Z of B i g I n t e g e r
/ /
@ -225,7 +189,7 @@ type BigRational =
/// Return the denominator of the normalized rational n u m b e r
member this.Denominator =
match this w i t h
| Z _ -> O n e I
| Z _ -> B i g I n t e g e r . O n e
| Q q -> q . D e n o m i n a t o r
/// Return a boolean indicating if this rational number is strictly n e g a t i v e
@ -261,9 +225,9 @@ type BigRational =
override this.ToString () =
match this w i t h
| Z z - >
z . T o S t r i n g ( )
z.ToString ( )
| Q q - >
q . T o S t r i n g ( )
q.ToString ( )
member this.StructuredDisplayString =
this.ToString ( )
@ -272,6 +236,7 @@ type BigRational =
static member Parse (str : string) =
Q (BigRationalLarge.Parse s t r )
// TODO : Optimize this by implementing a proper comparison function (so we only do one comparison instead of t w o ) .
interface System.IComparable w i t h
member this.CompareTo (obj : obj) =
match obj w i t h
@ -305,9 +270,9 @@ type BigRational =
| Q q, Q qq - >
Q (q + q q )
| Z z, Q qq - >
Q (BigRationalLarge.of_bigint z + q q )
Q (BigRationalLarge.FromBigInteger z + q q )
| Q q, Z zz - >
Q (q + BigRationalLarge.of_bigint z z )
Q (q + BigRationalLarge.FromBigInteger z z )
/// Return the difference of two rational n u m b e r s
static member ( - ) (n1, n2) =
@ -317,33 +282,33 @@ type BigRational =
| Q q, Q qq - >
Q (q - q q )
| Z z, Q qq - >
Q (BigRationalLarge.of_bigint z - q q )
Q (BigRationalLarge.FromBigInteger z - q q )
| Q q, Z zz - >
Q (q - BigRationalLarge.of_bigint z z )
Q (q - BigRationalLarge.FromBigInteger z z )
/// Return the product of two rational n u m b e r s
static member ( * ) (n1, n2) =
match n1,n2 w i t h
match n1, n2 w i t h
| Z z, Z zz - >
Z (z * z z )
| Q q, Q qq - >
Q (q * q q )
| Z z, Q qq - >
Q (BigRationalLarge.of_bigint z * q q )
Q (BigRationalLarge.FromBigInteger z * q q )
| Q q, Z zz - >
Q (q * BigRationalLarge.of_bigint z z )
Q (q * BigRationalLarge.FromBigInteger z z )
/// Return the ratio of two rational n u m b e r s
static member ( / ) (n1, n2) =
match n1, n2 w i t h
| Z z, Z zz - >
Q ( B i g R a t i o n a l L a r g e . R a t i o n a l Z ( z , z z ) )
Q (BigRationalLarge.Create (z, z z ) )
| Q q, Q qq - >
Q (q / q q )
| Z z, Q qq - >
Q (BigRationalLarge.of_bigint z / q q )
Q (BigRationalLarge.FromBigInteger z / q q )
| Q q, Z zz - >
Q (q / BigRationalLarge.of_bigint z z )
Q (q / BigRationalLarge.FromBigInteger z z )
/// Return the negation of a rational n u m b e r
static member ( ~- ) n =
@ -360,11 +325,11 @@ type BigRational =
| Z z, Z zz - >
BigInteger.(=) ( z , z z )
| Q q, Q qq - >
(BigRationalLarge.equal q q q )
BigRationalLarge.Equals (q, q q )
| Z z, Q qq - >
(BigRationalLarge.equal (BigRationalLarge.of_bigint z) q q )
BigRationalLarge.Equals (BigRationalLarge.FromBigInteger z, q q )
| Q q, Z zz - >
(BigRationalLarge.equal q (BigRationalLarge.of_bigint z z ) )
BigRationalLarge.Equals (q, BigRationalLarge.FromBigInteger z z )
/// This operator is for use from other . NET l a n g u a g e s
static member op_Inequality (n, nn) =
@ -374,49 +339,49 @@ type BigRational =
static member op_LessThan (n, nn) =
match n, nn w i t h
| Z z, Z zz - >
BigInteger.(<) ( z , z z )
z < z z
| Q q, Q qq - >
(BigRationalLarge.lt q q q )
q < q q
| Z z, Q qq - >
(BigRationalLarge.lt (BigRationalLarge.of_bigint z) q q )
BigRationalLarge.FromBigInteger z < q q
| Q q, Z zz - >
(BigRationalLarge.lt q (BigRationalLarge.of_bigint z z ) )
q < BigRationalLarge.FromBigInteger z z
/// This operator is for use from other . NET l a n g u a g e s
static member op_LessThanOrEqual (n, nn) =
match n, nn w i t h
| Z z, Z zz - >
BigInteger.(<=) ( z , z z )
z <= z z
| Q q, Q qq - >
(BigRationalLarge.lte q q q )
q <= q q
| Z z, Q qq - >
(BigRationalLarge.lte (BigRationalLarge.of_bigint z) q q )
BigRationalLarge.FromBigInteger z <= q q
| Q q, Z zz - >
(BigRationalLarge.lte q (BigRationalLarge.of_bigint z z ) )
q <= BigRationalLarge.FromBigInteger z z
/// This operator is for use from other . NET l a n g u a g e s
static member op_GreaterThan (n, nn) =
match n, nn w i t h
| Z z, Z zz - >
BigInteger.(>) ( z , z z )
z > z z
| Q q, Q qq - >
(BigRationalLarge.gt q q q )
q > q q
| Z z, Q qq - >
(BigRationalLarge.gt (BigRationalLarge.of_bigint z) q q )
BigRationalLarge.FromBigInteger z > q q
| Q q, Z zz - >
(BigRationalLarge.gt q (BigRationalLarge.of_bigint z z ) )
q > BigRationalLarge.FromBigInteger z z
/// This operator is for use from other . NET l a n g u a g e s
static member op_GreaterThanOrEqual (n, nn) =
match n, nn w i t h
| Z z, Z zz - >
BigInteger.(>=) ( z , z z )
z >= z z
| Q q, Q qq - >
(BigRationalLarge.gte q q q )
q >= q q
| Z z, Q qq - >
(BigRationalLarge.gte (BigRationalLarge.of_bigint z) q q )
BigRationalLarge.FromBigInteger z >= q q
| Q q, Z zz - >
(BigRationalLarge.gte q (BigRationalLarge.of_bigint z z ) )
q >= BigRationalLarge.FromBigInteger z z
/// Return the absolute value of a rational n u m b e r
static member Abs (n : BigRational) =
@ -428,13 +393,13 @@ type BigRational =
| Z z - >
Z (BigInteger.Pow (z, i ) )
| Q q - >
Q (BigRationalLarge.pown q i )
Q (BigRationalLarge.PowN (q, i ) )
/// Return the result of converting the given rational number to a floating point n u m b e r
static member ToDouble (n : BigRational) =
match n w i t h
| Z z - >
ToDoubleI z
float z
| Q q - >
BigRationalLarge.ToDouble q
@ -443,15 +408,15 @@ type BigRational =
match n w i t h
| Z z -> z
| Q q - >
BigRationalLarge.integer q
BigRationalLarge.ToB igI nteger q
/// Return the result of converting the given rational number to an i n t e g e r
static member ToInt32 (n : BigRational) =
match n w i t h
| Z z - >
ToInt32I z
int z
| Q q - >
ToInt32I (BigRationalLarge.i nteger q )
int (BigRationalLarge.ToBigI nteger q )
/// Return the result of converting the given rational number to an i n t e g e r
static member op_Explicit (n : BigRational) =