From fa67ff3ab40be66d278d254eb65e5b154a8e0c9a Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Mon, 31 Mar 2014 20:12:59 +0200 Subject: [PATCH] BigRational: fix pow to support negative integer exponents --- src/FSharp/BigRational.fs | 13 +++++++++---- src/FSharpUnitTests/BigRationalTests.fs | 21 ++++++++++++--------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/FSharp/BigRational.fs b/src/FSharp/BigRational.fs index e80515b6..725e2e0b 100644 --- a/src/FSharp/BigRational.fs +++ b/src/FSharp/BigRational.fs @@ -115,7 +115,8 @@ type BigRationalLarge (p : BigInteger, q : BigInteger) = // static member Pow (num : BigRationalLarge, n : int) = // p,q powers still coprime - BigRationalLarge (BigInteger.Pow (num.Numerator, n), BigInteger.Pow (num.Denominator, n)) + if n < 0 then BigRationalLarge.Normalize (BigInteger.Pow (num.Denominator, -n), BigInteger.Pow (num.Numerator, -n)) + else BigRationalLarge (BigInteger.Pow (num.Numerator, n), BigInteger.Pow (num.Denominator, n)) // static member FromBigInteger z = @@ -414,14 +415,18 @@ type BigRational = /// Returns the multiplicative inverse of a rational number static member Reciprocal (n) = match n with - | Z z -> Q (BigRationalLarge.Create (BigInteger.One, z)) - | Q q -> Q (BigRationalLarge.Reciprocal q) + | Z z -> + Q (BigRationalLarge.Create (BigInteger.One, z)) + | Q q -> + Q (BigRationalLarge.Reciprocal q) /// Return the result of raising the given rational number to the given power static member Pow (n, i : int) = match n with - | Z z -> + | Z z when i > 0 -> Z (BigInteger.Pow (z, i)) + | Z z -> + Q (BigRationalLarge.Pow (BigRationalLarge.FromBigInteger z, i)) | Q q -> Q (BigRationalLarge.Pow (q, i)) diff --git a/src/FSharpUnitTests/BigRationalTests.fs b/src/FSharpUnitTests/BigRationalTests.fs index 0eb11d34..50141c3c 100644 --- a/src/FSharpUnitTests/BigRationalTests.fs +++ b/src/FSharpUnitTests/BigRationalTests.fs @@ -286,10 +286,15 @@ type public BigRationalTests() = test1All "Abs" (BigRational.Abs) (fun (p,q) -> (abs p,abs q)) vector1s testR1All "Sign" (fun (x:BigRational) -> x.Sign) (fun (p,q) -> check "NonZeroDenom" (sign q <> 0I) true; (sign p * sign q) |> int32) vector1s - // Test: PowN - test1All "PowN(x,2)" (fun x -> BigRational.PowN(x,2)) (fun (p,q) -> (p*p,q*q)) vector1s - test1All "PowN(x,1)" (fun x -> BigRational.PowN(x,1)) (fun (p,q) -> (p,q)) vector1s - test1All "PowN(x,0)" (fun x -> BigRational.PowN(x,0)) (fun (p,q) -> (1I,1I)) vector1s + // Test: Pow + test1All "Pow(x,2)" (fun x -> BigRational.Pow(x,2)) (fun (p,q) -> (p*p,q*q)) vector1s + test1All "Pow(x,1)" (fun x -> BigRational.Pow(x,1)) (fun (p,q) -> (p,q)) vector1s + test1All "Pow(x,0)" (fun x -> BigRational.Pow(x,0)) (fun (p,q) -> (1I,1I)) vector1s + test1All "Pow(x,-1)" (fun x -> BigRational.Pow(x,-1)) (fun (p,q) -> (q,p)) (vector1s |> List.filter (fun (p,_) -> p <> 0I)) + test1All "Pow(x,-2)" (fun x -> BigRational.Pow(x,-2)) (fun (p,q) -> (q*q,p*p)) (vector1s |> List.filter (fun (p,_) -> p <> 0I)) + + testR1One "Pow(0,-1)" (fun x -> throws (fun () -> BigRational.PowN(x,-1))) (fun (p,q) -> true) (0I, -1I) + testR1One "Pow(0,-2)" (fun x -> throws (fun () -> BigRational.PowN(x,-2))) (fun (p,q) -> true) (0I, -2I) // MatteoT: moved to numbersVS2008\test.ml //test1All "PowN(x,200)" (fun x -> BigRational.PowN(x,200)) (fun (p,q) -> (BigInteger.Pow(p,200I),BigInteger.Pow(q,200I))) vector1s @@ -298,10 +303,6 @@ 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) - // Test: PowN with negative powers - expect exception - testR1All "PowN(x,-1)" (fun x -> throws (fun () -> BigRational.PowN(x,-1))) (fun (p,q) -> true) vector1s - testR1All "PowN(x,-4)" (fun x -> throws (fun () -> BigRational.PowN(x,-4))) (fun (p,q) -> true) vector1s - [] @@ -387,8 +388,10 @@ type BigNumType() = member this.Pow() = Assert.AreEqual(bignum.Pow(100N,2), 10000N) Assert.AreEqual(bignum.Pow(-3N,3), -27N) + Assert.AreEqual(bignum.Pow(2N,-2), 1N/4N) + Assert.AreEqual(bignum.Pow(2N/3N,-2), 9N/4N) Assert.AreEqual(bignum.Pow(g_zero,2147483647), 0N) - Assert.AreEqual(bignum.Pow(g_normal,0), 1N) + Assert.AreEqual(bignum.Pow(g_normal,0), 1N) () []