提交 31208c1a 编写于 作者: L latkin

Cleanup and fixes for F# BigInteger to bring it closer to BCL BigInteger...

Cleanup and fixes for F# BigInteger to bring it closer to BCL BigInteger behavior. Addresses bugs #105, #106, #107, #108, #109, #111, and #112. (changeset 1304009)
上级 00308350
......@@ -1562,7 +1562,7 @@ module internal BigNatModule =
if 0 <= d && d <= 9 then
build (add (mul ten acc) (embed d)) (i+1)
else
raise (new System.FormatException("The value could not be parsed"))
raise (new System.FormatException(SR.GetString(SR.badFormatString)))
build (embed 0) 0
......
......@@ -19,7 +19,10 @@ namespace System.Numerics
// NOTE: 0 has two repns (+1,0) or (-1,0).
[<Struct>]
[<CustomEquality; CustomComparison>]
#if FX_ATLEAST_PORTABLE
#else
[<StructuredFormatDisplay("{StructuredDisplayString}I")>]
#endif
type BigInteger(signInt:int, v : BigNat) =
static let smallLim = 4096
......@@ -31,13 +34,17 @@ namespace System.Numerics
if BigNatModule.isSmall n && BigNatModule.getSmall n < smallLim
then smallPosTab.[BigNatModule.getSmall n]
else n
static member internal create (s,n) = BigInteger(s,BigInteger.nat n)
static member internal posn n = BigInteger(1,BigInteger.nat n)
static member internal negn n = BigInteger(-1,BigInteger.nat n)
static member internal negn n = BigInteger(-1,BigInteger.nat n)
member x.Sign = if x.IsZero then 0 else signInt
member x.SignInt = signInt
member internal x.V = v
static member op_Equality (x:BigInteger, y:BigInteger) =
......@@ -48,7 +55,12 @@ namespace System.Numerics
| -1, -1 -> BigNatModule.equal x.V y.V // -1.xv = -1.yv iff xv = yv
| 1,-1 -> BigNatModule.isZero x.V && BigNatModule.isZero y.V // 1.xv = -1.yv iff xv=0 and yv=0
| -1, 1 -> BigNatModule.isZero x.V && BigNatModule.isZero y.V // -1.xv = 1.yv iff xv=0 and yv=0
| _ -> invalidArg "x" "signs should be +/- 1"
| 0, 0 -> true
| 0, 1 -> BigNatModule.isZero y.V
| 0, -1 -> BigNatModule.isZero y.V
| 1, 0 -> BigNatModule.isZero x.V
| -1, 0 -> BigNatModule.isZero x.V
| _ -> invalidArg "x" "signs should be +/- 1 or 0"
static member op_Inequality (x:BigInteger, y:BigInteger) = not (BigInteger.op_Equality(x,y)) // CA2226: OperatorsShouldHaveSymmetricalOverloads
......@@ -62,7 +74,12 @@ namespace System.Numerics
// (a) xv=0 and yv=0, then false
// (b) xv<>0, -1.xv < 0 <= 1.yv, so true
// (c) yv<>0, -1.xv <= 0 < 1.yv, so true
| _ -> invalidArg "x" "signs should be +/- 1"
| 0, 0 -> false
| 0, 1 -> not (BigNatModule.isZero y.V)
| 0,-1 -> false
| 1, 0 -> false
| -1, 0 -> not (BigNatModule.isZero x.V)
| _ -> invalidArg "x" "signs should be +/- 1 or 0"
static member op_GreaterThan (x:BigInteger, y:BigInteger) = // Follow lt by +/- symmetry
match x.SignInt,y.SignInt with
......@@ -70,10 +87,18 @@ namespace System.Numerics
| -1,-1 -> BigNatModule.gt y.V x.V
| 1,-1 -> not (BigNatModule.isZero x.V) || not (BigNatModule.isZero y.V)
| -1, 1 -> false
| _ -> invalidArg "x" "signs should be +/- 1"
| 0, 0 -> false
| 0, 1 -> false
| 0,-1 -> not (BigNatModule.isZero y.V)
| 1, 0 -> not (BigNatModule.isZero x.V)
| -1, 0 -> false
| _ -> invalidArg "x" "signs should be +/- 1 or 0"
static member internal compare(n,nn) = if BigInteger.op_LessThan(n,nn) then -1 elif BigInteger.op_Equality(n,nn) then 0 else 1
static member internal hash (z:BigInteger) = z.SignInt + BigNatModule.hash(z.V)
static member internal hash (z:BigInteger) =
if z.SignInt = 0 then 1 // 1 is hashcode for initialized BigInteger.Zero
else z.SignInt + BigNatModule.hash(z.V)
override x.ToString() =
match x.SignInt with
......@@ -81,8 +106,9 @@ namespace System.Numerics
| -1 ->
if BigNatModule.isZero x.V
then "0" // not negative infact, but zero.
else "-" + BigNatModule.toString x.V // negative
| _ -> invalidOp "signs should be +/- 1"
else "-" + BigNatModule.toString x.V // negative
| 0 -> "0"
| _ -> invalidOp "signs should be +/- 1 or 0"
member x.StructuredDisplayString = x.ToString()
......@@ -99,7 +125,6 @@ namespace System.Numerics
override x.GetHashCode() = BigInteger.hash(x)
new (n:int) =
if n>=0
then BigInteger (1,BigInteger.nat(BigNatModule.ofInt32 n))
......@@ -107,7 +132,6 @@ namespace System.Numerics
then BigInteger(-1,BigInteger.nat(BigNatModule.ofInt64 (-(int64 n))))
else BigInteger(-1,BigInteger.nat(BigNatModule.ofInt32 (-n)))
new (n:int64) =
if n>=0L
then BigInteger(1,BigInteger.nat (BigNatModule.ofInt64 n))
......@@ -116,9 +140,16 @@ namespace System.Numerics
else BigInteger(-1,BigInteger.nat (BigNatModule.ofInt64 (-n)))
static member One = one
static member Zero = zero
static member (~-) (z:BigInteger) = BigInteger.create(-1 * z.SignInt,z.V)
static member Scale(k,z:BigInteger) =
static member (~-) (z:BigInteger) =
match z.SignInt with
| 0 -> BigInteger.Zero
| i -> BigInteger.create(-i, z.V)
static member Scale(k, z:BigInteger) =
if z.SignInt = 0 then BigInteger.Zero else
if k<0
then BigInteger.create(-z.SignInt, (BigNatModule.scale (-k) z.V)) // k.zsign.zv = -zsign.(-k.zv)
else BigInteger.create(z.SignInt, (BigNatModule.scale k z.V)) // k.zsign.zv = zsign.k.zv
......@@ -132,8 +163,10 @@ namespace System.Numerics
static member internal addnn (nx,ny) =
BigInteger.posn (BigNatModule.add nx ny) // Compute "nx + ny" to be integer
member x.IsZero = BigNatModule.isZero x.V // signx.xv = 0 iff xv=0, since signx is +1,-1
member x.IsZero = x.SignInt = 0 || BigNatModule.isZero x.V
member x.IsOne = (x.SignInt = 1) && BigNatModule.isOne x.V // signx.xv = 1 iff signx = +1 and xv = 1
static member (+) (x:BigInteger,y:BigInteger) =
if y.IsZero then x else
if x.IsZero then y else
......@@ -146,6 +179,7 @@ namespace System.Numerics
static member (-) (x:BigInteger,y:BigInteger) =
if y.IsZero then x else
if x.IsZero then -y else
match x.SignInt,y.SignInt with
| 1, 1 -> BigInteger.subnn(x.V,y.V) // 1.xv - 1.yv = (xv - yv)
| -1,-1 -> BigInteger.subnn(y.V,x.V) // -1.xv - -1.yv = (yv - xv)
......@@ -162,7 +196,12 @@ namespace System.Numerics
let m = (BigNatModule.mul x.V y.V)
BigInteger.create (x.SignInt * y.SignInt,m) // xsign.xv * ysign.yv = (xsign.ysign).(xv.yv)
static member DivRem (x:BigInteger,y:BigInteger,rem:BigInteger byref) =
static member DivRem (x:BigInteger, y:BigInteger, [<System.Runtime.InteropServices.Out>]rem:BigInteger byref) =
if y.IsZero then raise (new System.DivideByZeroException())
if x.IsZero then
rem <- BigInteger.Zero
BigInteger.Zero
else
let d,r = BigNatModule.divmod x.V y.V
// HAVE: |x| = d.|y| + r and 0 <= r < |y|
// HAVE: xv = d.yv + r and 0 <= r < yv
......@@ -176,13 +215,22 @@ namespace System.Numerics
static member (/) (x:BigInteger,y:BigInteger) =
let mutable rem = new BigInteger(0)
BigInteger.DivRem(x,y,&rem)
static member (%) (x:BigInteger,y:BigInteger) =
let mutable rem = new BigInteger(0)
BigInteger.DivRem(x,y,&rem) |> ignore ; rem
static member GreatestCommonDivisor (x:BigInteger,y:BigInteger) = BigInteger.posn (BigNatModule.hcf x.V y.V) // hcf (xsign.xv,ysign.yv) = hcf (xv,yv)
static member GreatestCommonDivisor (x:BigInteger,y:BigInteger) =
match x.SignInt,y.SignInt with
| 0, 0 -> BigInteger.Zero
| 0, _ -> BigInteger.posn y.V
| _, 0 -> BigInteger.posn x.V
| _ -> BigInteger.posn (BigNatModule.hcf x.V y.V) // hcf (xsign.xv,ysign.yv) = hcf (xv,yv)
member x.IsNegative = x.SignInt = -1 && not (x.IsZero) // signx.xv < 0 iff signx = -1 and xv<>0
member x.IsPositive = x.SignInt = 1 && not (x.IsZero) // signx.xv > 0 iff signx = +1 and xv<>0
static member Abs (x:BigInteger) = if x.SignInt = -1 then -x else x
static member op_LessThanOrEqual (x:BigInteger,y:BigInteger) =
......@@ -192,9 +240,14 @@ namespace System.Numerics
| 1,-1 -> BigNatModule.isZero x.V && BigNatModule.isZero y.V // 1.xv <= -1.yv,
// (a) if xv=0 and yv=0 then true
// (b) otherwise false, only meet at zero.
| -1, 1 -> true // -1.xv <= 1.yv, true
| _ -> invalidArg "x" "signs should be +/- 1"
| 0, 0 -> true
| 1, 0 -> BigNatModule.isZero x.V
| -1, 0 -> true
| 0, 1 -> true
| 0,-1 -> BigNatModule.isZero y.V
| _ -> invalidArg "x" "signs should be +/- 1 or 0"
static member op_GreaterThanOrEqual (x:BigInteger,y:BigInteger) = // Follow lte by +/- symmetry
match x.SignInt,y.SignInt with
......@@ -202,15 +255,24 @@ namespace System.Numerics
| -1,-1 -> BigNatModule.gte y.V x.V
| 1,-1 -> true
| -1, 1 -> BigNatModule.isZero x.V && BigNatModule.isZero y.V
| _ -> invalidArg "x" "signs should be +/- 1"
| 0, 0 -> true
| 1, 0 -> true
| -1, 0 -> BigNatModule.isZero x.V
| 0, 1 -> BigNatModule.isZero y.V
| 0,-1 -> true
| _ -> invalidArg "x" "signs should be +/- 1 or 0"
static member Pow (x:BigInteger,y:int32) =
if y < 0 then invalidArg "y" (SR.GetString(SR.inputMustBeNonNegative))
let yval = BigInteger(y)
BigInteger.create ((if BigNatModule.isZero (BigNatModule.rem yval.V BigNatModule.two) then 1 else x.SignInt), BigNatModule.pow x.V yval.V)
if y < 0 then raise (new System.ArgumentOutOfRangeException("y", (SR.GetString(SR.inputMustBeNonNegative))))
match x.IsZero, y with
| true, 0 -> BigInteger.One
| true, _ -> BigInteger.Zero
| _ ->
let yval = BigInteger(y)
BigInteger.create ((if BigNatModule.isZero (BigNatModule.rem yval.V BigNatModule.two) then 1 else x.SignInt), BigNatModule.pow x.V yval.V)
static member op_Explicit (x:BigInteger) =
if x.IsZero then 0 else
let u = BigNatModule.toUInt32 x.V
if u <= uint32 System.Int32.MaxValue then
// Handle range [-MaxValue,MaxValue]
......@@ -222,7 +284,8 @@ namespace System.Numerics
else
raise (System.OverflowException())
static member op_Explicit (x:BigInteger) =
static member op_Explicit (x:BigInteger) =
if x.IsZero then 0L else
let u = BigNatModule.toUInt64 x.V
if u <= uint64 System.Int64.MaxValue then
(* Handle range [-MaxValue,MaxValue] *)
......@@ -238,17 +301,23 @@ namespace System.Numerics
match x.SignInt with
| 1 -> BigNatModule.toFloat x.V // float (1.xv) = float (xv)
| -1 -> - (BigNatModule.toFloat x.V) // float (-1.xv) = - float (xv)
| _ -> invalidArg "x" "signs should be +/- 1"
| 0 -> 0.
| _ -> invalidArg "x" "signs should be +/- 1 or 0"
static member Parse(text:string) =
if text = null then raise (new ArgumentNullException("text"))
let text = text.Trim()
let len = text.Length
if len = 0 then raise (new System.FormatException("The value could not be parsed"))
if text.[0..0] = "-" then
BigInteger.negn (BigNatModule.ofString text.[1..len-1])
else
BigInteger.posn (BigNatModule.ofString text)
member internal x.IsSmall = BigNatModule.isSmall (x.V)
if len = 0 then raise (new System.FormatException(SR.GetString(SR.badFormatString)))
match text.[0], len with
| '-', 1 -> raise (new System.FormatException(SR.GetString(SR.badFormatString)))
| '-', _ -> BigInteger.negn (BigNatModule.ofString text.[1..len-1])
| '+', 1 -> raise (new System.FormatException(SR.GetString(SR.badFormatString)))
| '+', _ -> BigInteger.posn (BigNatModule.ofString text.[1..len-1])
| _ -> BigInteger.posn (BigNatModule.ofString text)
member internal x.IsSmall = x.IsZero || BigNatModule.isSmall (x.V)
static member Factorial (x:BigInteger) =
if x.IsNegative then invalidArg "x" (SR.GetString(SR.inputMustBeNonNegative))
if x.IsPositive then BigInteger.posn (BigNatModule.factorial x.V)
......@@ -257,6 +326,7 @@ namespace System.Numerics
static member ( ~+ )(n1:BigInteger) = n1
static member FromInt64(x:int64) = new BigInteger(x)
static member FromInt32(x:int32) = new BigInteger(x)
#endif
......
......@@ -36,7 +36,7 @@ namespace System.Numerics
/// Return the sign of a big integer: 0, +1 or -1
member Sign : int
/// Compute the ratio and remainder of two big integers
static member DivRem : x:BigInteger * y:BigInteger * rem:BigInteger byref -> BigInteger
static member DivRem : x:BigInteger * y:BigInteger * [<System.Runtime.InteropServices.Out>]rem:BigInteger byref -> BigInteger
/// This operator is for consistency when this type be used from other CLI languages
static member op_LessThan : x:BigInteger * y:BigInteger -> bool
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册