// (c) Microsoft Corporation. All rights reserved #nowarn "44" // OK to use the "compiler only" function RangeGeneric namespace Microsoft.FSharp.Math open Microsoft.FSharp.Collections open Microsoft.FSharp.Core open Microsoft.FSharp.Math open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators open Microsoft.FSharp.Primitives.Basics open Microsoft.FSharp.Core.Operators open System open System.Globalization module BigRationalLargeImpl = let ZeroI = new BigInt(0) let OneI = new BigInt(1) let bigint (x:int) = new BigInt(x) let ToDoubleI (x:bigint) = #if FX_ATLEAST_40 (BigInt.op_Explicit x : double) #else BigInt.ToDouble x #endif let ToInt32I x = #if FX_ATLEAST_40 (BigInt.op_Explicit x : int32) #else BigInt.ToInt32 x #endif open BigRationalLargeImpl [] type BigRationalLarge = | Q of BigInt * BigInt // invariants: (p,q) in lowest form, q >= 0 override n.ToString() = let (Q(p,q)) = n if q.IsOne then p.ToString() else p.ToString() + "/" + q.ToString() static member Hash (Q(ap,aq) as q) = // This hash code must be identical to the hash for BigInt when the numbers coincide. if aq.IsOne then ap.GetHashCode() else (ap.GetHashCode() <<< 3) + aq.GetHashCode() override x.GetHashCode() = BigRationalLarge.Hash(x) static member Equals(Q(ap,aq), Q(bp,bq)) = BigInt.(=) (ap,bp) && BigInt.(=) (aq,bq) // normal form, so structural equality static member LessThan(Q(ap,aq), Q(bp,bq)) = BigInt.(<) (ap * bq,bp * aq) // note: performance improvement possible here static member Compare(p,q) = if BigRationalLarge.LessThan(p,q) then -1 elif BigRationalLarge.LessThan(q,p)then 1 else 0 interface System.IComparable with member this.CompareTo(obj:obj) = match obj with | :? BigRationalLarge as that -> BigRationalLarge.Compare(this,that) | _ -> invalidArg "obj" "the object does not have the correct type" override this.Equals(that:obj) = match that with | :? BigRationalLarge as that -> BigRationalLarge.Equals(this,that) | _ -> false member x.IsNegative = let (Q(ap,aq)) = x in sign ap < 0 member x.IsPositive = let (Q(ap,aq)) = x in sign ap > 0 member x.Numerator = let (Q(p,q)) = x in p member x.Denominator = let (Q(p,q)) = x in q member x.Sign = (let (Q(p,q)) = x in sign p) static member ToDouble (Q(p,q)) = ToDoubleI p / ToDoubleI q static member Normalize (p:BigInt,q:BigInt) = if q.IsZero then raise (System.DivideByZeroException()) (* throw for any x/0 *) elif q.IsOne then Q(p,q) else #if FX_ATLEAST_40 let k = BigInt.GreatestCommonDivisor(p,q) #else let k = BigInt.Gcd(p,q) #endif let p = p / k let q = q / k if sign q < 0 then Q(-p,-q) else Q(p,q) static member Rational (p:int,q:int) = BigRationalLarge.Normalize (bigint p,bigint q) static member RationalZ (p,q) = BigRationalLarge.Normalize (p,q) static member Parse (str:string) = let len = str.Length if len=0 then invalidArg "str" "empty string"; let j = str.IndexOf '/' if j >= 0 then let p = BigInt.Parse (str.Substring(0,j)) let q = BigInt.Parse (str.Substring(j+1,len-j-1)) BigRationalLarge.RationalZ (p,q) else let p = BigInt.Parse str BigRationalLarge.RationalZ (p,OneI) static member (~-) (Q(bp,bq)) = Q(-bp,bq) // still coprime, bq >= 0 static member (+) (Q(ap,aq),Q(bp,bq)) = BigRationalLarge.Normalize ((ap * bq) + (bp * aq),aq * bq) static member (-) (Q(ap,aq),Q(bp,bq)) = BigRationalLarge.Normalize ((ap * bq) - (bp * aq),aq * bq) static member (*) (Q(ap,aq),Q(bp,bq)) = BigRationalLarge.Normalize (ap * bp,aq * bq) static member (/) (Q(ap,aq),Q(bp,bq)) = BigRationalLarge.Normalize (ap * bq,aq * bp) static member ( ~+ )(n1:BigRationalLarge) = n1 (* static member Floor (Q(p,q)) = let d,r = BigInt.DivRem (p,q) // p = d.q + r if sign r < 0 then d - OneI // r -ve, so round down else d static member Ceiling (Q(p,q)) = let d,r = BigInt.DivRem (p,q) // p = d.q + r if sign r > 0 then d + OneI // when r +ve, adjust up else d *) [] module BigRationalLarge = let inv (Q(ap,aq)) = BigRationalLarge.Normalize(aq,ap) #if FX_ATLEAST_40 let pown (Q(p,q)) (n:int) = Q(BigInt.Pow(p,n),BigInt.Pow (q,n)) #else let pow (Q(p,q)) (z:bigint) = Q(BigInt.Pow(p,z),BigInt.Pow (q,z)) // p,q powers still coprime let powi q (n:int) = let z = bigint n in pow q z #endif let equal (Q(ap,aq)) (Q(bp,bq)) = ap=bp && aq=bq // normal form, so structural equality let lt a b = BigRationalLarge.LessThan(a,b) let gt a b = BigRationalLarge.LessThan(b,a) let lte (Q(ap,aq)) (Q(bp,bq)) = BigInt.(<=) (ap * bq,bp * aq) let gte (Q(ap,aq)) (Q(bp,bq)) = BigInt.(>=) (ap * bq,bp * aq) let of_bigint z = BigRationalLarge.RationalZ(z,OneI ) let of_int n = BigRationalLarge.Rational(n,1) // integer part let integer (Q(p,q)) = let d,r = BigInt.DivRem (p,q) // have p = d.q + r, |r| < |q| if r < ZeroI then d - OneI // p = (d-1).q + (r+q) else d // p = d.q + r (* let two = BigInt 2 let round (Q(p,q)) = let d,r = BigInt.DivRem (p,q) // have p = d.q + r for |r| 0 then if BigInt.(<) (q / two,r) then OneI + d // have q/2 < r < q , round up else d // have 0 < r <= q/2, note 1/2 rounds down elif s < 0 then if BigInt.(<=) (q / two, -r) then OneI - d // have -1 < r <= q/2 , round down. note 1/2 rounds down again else d // have -q/2 < r < 0 , rounds up else d // have r=0 *) //---------------------------------------------------------------------------- // BigNum //-------------------------------------------------------------------------- [] [] type BigNum = | Z of BigInt | Q of BigRationalLarge static member ( + )(n1,n2) = match n1,n2 with | Z z ,Z zz -> Z (z + zz) | Q q ,Q qq -> Q (q + qq) | Z z ,Q qq -> Q (BigRationalLarge.of_bigint z + qq) | Q q ,Z zz -> Q (q + BigRationalLarge.of_bigint zz) static member ( * )(n1,n2) = match n1,n2 with | Z z ,Z zz -> Z (z * zz) | Q q ,Q qq -> Q (q * qq) | Z z ,Q qq -> Q (BigRationalLarge.of_bigint z * qq) | Q q ,Z zz -> Q (q * BigRationalLarge.of_bigint zz) static member ( - )(n1,n2) = match n1,n2 with | Z z ,Z zz -> Z (z - zz) | Q q ,Q qq -> Q (q - qq) | Z z ,Q qq -> Q (BigRationalLarge.of_bigint z - qq) | Q q ,Z zz -> Q (q - BigRationalLarge.of_bigint zz) static member ( / )(n1,n2) = match n1,n2 with | Z z ,Z zz -> Q (BigRationalLarge.RationalZ(z,zz)) | Q q ,Q qq -> Q (q / qq) | Z z ,Q qq -> Q (BigRationalLarge.of_bigint z / qq) | Q q ,Z zz -> Q (q / BigRationalLarge.of_bigint zz) static member ( ~- )(n1) = match n1 with | Z z -> Z (-z) | Q q -> Q (-q) static member ( ~+ )(n1:BigNum) = n1 // nb. Q and Z hash codes must match up - see notes above override n.GetHashCode() = match n with | Z z -> z.GetHashCode() | Q q -> q.GetHashCode() override this.Equals(obj:obj) = match obj with | :? BigNum as that -> BigNum.(=)(this, that) | _ -> false interface System.IComparable with member n1.CompareTo(obj:obj) = match obj with | :? BigNum as n2 -> if BigNum.(<)(n1, n2) then -1 elif BigNum.(=)(n1, n2) then 0 else 1 | _ -> invalidArg "obj" "the objects are not comparable" static member FromInt (x:int) = Z (bigint x) static member FromBigInt x = Z x static member Zero = BigNum.FromInt(0) static member One = BigNum.FromInt(1) static member PowN (n,i:int) = match n with #if FX_ATLEAST_40 | Z z -> Z (BigInt.Pow (z,i)) | Q q -> Q (BigRationalLarge.pown q i) #else | Z z -> Z (BigInt.Pow (z,bigint i)) | Q q -> Q (BigRationalLarge.powi q i) #endif static member op_Equality (n,nn) = match n,nn with | Z z ,Z zz -> BigInt.(=) (z,zz) | Q q ,Q qq -> (BigRationalLarge.equal q qq) | Z z ,Q qq -> (BigRationalLarge.equal (BigRationalLarge.of_bigint z) qq) | Q q ,Z zz -> (BigRationalLarge.equal q (BigRationalLarge.of_bigint zz)) static member op_Inequality (n,nn) = not (BigNum.op_Equality(n,nn)) static member op_LessThan (n,nn) = match n,nn with | Z z ,Z zz -> BigInt.(<) (z,zz) | Q q ,Q qq -> (BigRationalLarge.lt q qq) | Z z ,Q qq -> (BigRationalLarge.lt (BigRationalLarge.of_bigint z) qq) | Q q ,Z zz -> (BigRationalLarge.lt q (BigRationalLarge.of_bigint zz)) static member op_GreaterThan (n,nn) = match n,nn with | Z z ,Z zz -> BigInt.(>) (z,zz) | Q q ,Q qq -> (BigRationalLarge.gt q qq) | Z z ,Q qq -> (BigRationalLarge.gt (BigRationalLarge.of_bigint z) qq) | Q q ,Z zz -> (BigRationalLarge.gt q (BigRationalLarge.of_bigint zz)) static member op_LessThanOrEqual (n,nn) = match n,nn with | Z z ,Z zz -> BigInt.(<=) (z,zz) | Q q ,Q qq -> (BigRationalLarge.lte q qq) | Z z ,Q qq -> (BigRationalLarge.lte (BigRationalLarge.of_bigint z) qq) | Q q ,Z zz -> (BigRationalLarge.lte q (BigRationalLarge.of_bigint zz)) static member op_GreaterThanOrEqual (n,nn) = match n,nn with | Z z ,Z zz -> BigInt.(>=) (z,zz) | Q q ,Q qq -> (BigRationalLarge.gte q qq) | Z z ,Q qq -> (BigRationalLarge.gte (BigRationalLarge.of_bigint z) qq) | Q q ,Z zz -> (BigRationalLarge.gte q (BigRationalLarge.of_bigint zz)) member n.IsNegative = match n with | Z z -> sign z < 0 | Q q -> q.IsNegative member n.IsPositive = match n with | Z z -> sign z > 0 | Q q -> q.IsPositive member n.Numerator = match n with | Z z -> z | Q q -> q.Numerator member n.Denominator = match n with | Z z -> OneI | Q q -> q.Denominator member n.Sign = if n.IsNegative then -1 elif n.IsPositive then 1 else 0 static member Abs(n:BigNum) = if n.IsNegative then -n else n static member ToDouble(n:BigNum) = match n with | Z z -> ToDoubleI z | Q q -> BigRationalLarge.ToDouble q static member ToBigInt(n:BigNum) = match n with | Z z -> z | Q q -> BigRationalLarge.integer q static member ToInt32(n:BigNum) = match n with | Z z -> ToInt32I(z) | Q q -> ToInt32I(BigRationalLarge.integer q ) override n.ToString() = match n with | Z z -> z.ToString() | Q q -> q.ToString() member x.StructuredDisplayString = x.ToString() static member Parse(s:string) = Q (BigRationalLarge.Parse s) type BigRational = BigNum type bignum = BigNum namespace Microsoft.FSharp.Core open Microsoft.FSharp.Math type bignum = BigNum // FxCop suppressions open System.Diagnostics.CodeAnalysis [] [] [] [] [] [] [] [] [] [] do() module NumericLiteralN = let FromZero () = BigNum.Zero let FromOne () = BigNum.One let FromInt32 i = BigNum.FromInt i let FromInt64 (i64:int64) = BigNum.FromBigInt (new BigInt(i64)) let FromString s = BigNum.Parse s