diff --git a/src/FSharp.Tests/BigRationalTests.fs b/src/FSharp.Tests/BigRationalTests.fs index 1c278958..efcf1d3d 100644 --- a/src/FSharp.Tests/BigRationalTests.fs +++ b/src/FSharp.Tests/BigRationalTests.fs @@ -300,6 +300,27 @@ type public BigRationalTests() = //let powers = [0I .. 100I] //powers |> List.iter (fun i -> test1All "PowN(x,i)" (fun x -> BigRational.PowN(x,int i)) (fun (p,q) -> (BigInteger.Pow(p,i),BigInteger.Pow(q,i))) vector1s) + [] + member this.FromDecimal() = + let pairs = + [ + 1M, 1N + 100000000000000M, 100000000000000N + 10000000000000000000000000000M, 10000000000000000000000000000N + 100000000000000.00000000000000M, 100000000000000N + 1.0000000000000000000000000000M, 1N + 123456789M, 123456789N + 0.123456789M, 123456789N/1000000000N + 0.000000000123456789M, 123456789N/1000000000000000000N + 0.000000000000000000123456789M, 123456789N/1000000000000000000000000000N + 4294967295M, 4294967295N + 18446744073709551615M, 18446744073709551615N + Decimal.MaxValue, 79228162514264337593543950335N + Decimal.MinValue, -79228162514264337593543950335N + -7.9228162514264337593543950335M, -79228162514264337593543950335N/10000000000000000000000000000N + ] + for (decimal, rational) in pairs do + Assert.AreEqual(rational, BigRational.FromDecimal(decimal)) [] diff --git a/src/FSharp/BigRational.fs b/src/FSharp/BigRational.fs index b0b71645..267b07cd 100644 --- a/src/FSharp/BigRational.fs +++ b/src/FSharp/BigRational.fs @@ -276,6 +276,20 @@ type BigRational = static member FromBigIntFraction (numerator: BigInteger, denominator: BigInteger) = Q (BigRationalLarge.Create (numerator, denominator)) + // See https://docs.microsoft.com/en-us/dotnet/api/system.decimal.getbits + static member FromDecimal(n : decimal) = + let parts = Decimal.GetBits(n) + assert(parts.Length = 4) + let toBigInt = uint32 >> bigint + let lo = (toBigInt parts.[0]) <<< 0 + let mid = (toBigInt parts.[1]) <<< 32 + let hi = (toBigInt parts.[2]) <<< 64 + let sign = if (parts.[3] &&& 0x80000000) = 0 then 1I else -1I + let scale = (parts.[3] >>> 16) &&& 0x7F + BigRational.FromBigIntFraction( + sign * (lo + mid + hi), + BigInteger.Pow(10I, scale)) + /// Get zero as a rational number static member Zero = BigRational.FromInt 0 diff --git a/src/FSharp/BigRational.fsi b/src/FSharp/BigRational.fsi index 19eba6e2..78de22a1 100644 --- a/src/FSharp/BigRational.fsi +++ b/src/FSharp/BigRational.fsi @@ -62,6 +62,8 @@ type BigRational = static member FromIntFraction : int * int -> BigRational static member FromBigIntFraction : BigInteger * BigInteger -> BigRational + static member FromDecimal : decimal -> BigRational + static member ToDouble: BigRational -> float static member ToBigInt: BigRational -> BigInteger static member ToInt32 : BigRational -> int