diff options
author | Ian Lance Taylor <iant@google.com> | 2016-02-03 21:58:02 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2016-02-03 21:58:02 +0000 |
commit | f98dd1a338867a408f7c72d73fbad7fe7fc93e3a (patch) | |
tree | 2f8da9862a9c1fe0df138917f997b03439c02773 /libgo/go/math | |
parent | b081ed4efc144da0c45a6484aebfd10e0eb9fda3 (diff) | |
download | gcc-f98dd1a338867a408f7c72d73fbad7fe7fc93e3a.zip gcc-f98dd1a338867a408f7c72d73fbad7fe7fc93e3a.tar.gz gcc-f98dd1a338867a408f7c72d73fbad7fe7fc93e3a.tar.bz2 |
libgo: Update to go1.6rc1.
Reviewed-on: https://go-review.googlesource.com/19200
From-SVN: r233110
Diffstat (limited to 'libgo/go/math')
40 files changed, 1743 insertions, 804 deletions
diff --git a/libgo/go/math/abs.go b/libgo/go/math/abs.go index 433d0f7..1b7c7c1 100644 --- a/libgo/go/math/abs.go +++ b/libgo/go/math/abs.go @@ -18,10 +18,13 @@ func Abs(x float64) float64 { } func abs(x float64) float64 { - switch { - case x < 0: + // TODO: once golang.org/issue/13095 is fixed, change this to: + // return Float64frombits(Float64bits(x) &^ (1 << 63)) + // But for now, this generates better code and can also be inlined: + if x < 0 { return -x - case x == 0: + } + if x == 0 { return 0 // return correctly abs(-0) } return x diff --git a/libgo/go/math/all_test.go b/libgo/go/math/all_test.go index e18e45e..968a7b1 100644 --- a/libgo/go/math/all_test.go +++ b/libgo/go/math/all_test.go @@ -234,6 +234,18 @@ var expm1 = []float64{ 1.842068661871398836913874273e-02, -8.3193870863553801814961137573e-02, } +var expm1Large = []float64{ + 4.2031418113550844e+21, + 4.0690789717473863e+33, + -0.9372627915981363e+00, + -1.0, + 7.077694784145933e+41, + 5.117936223839153e+12, + 5.124137759001189e+22, + 7.03546003972584e+11, + 8.456921800389698e+07, + -1.0, +} var exp2 = []float64{ 3.1537839463286288034313104e+01, 2.1361549283756232296144849e+02, @@ -447,7 +459,7 @@ var log2 = []float64{ var modf = [][2]float64{ {4.0000000000000000e+00, 9.7901192488367350108546816e-01}, {7.0000000000000000e+00, 7.3887247457810456552351752e-01}, - {0.0000000000000000e+00, -2.7688005719200159404635997e-01}, + {Copysign(0, -1), -2.7688005719200159404635997e-01}, {-5.0000000000000000e+00, -1.060361827107492160848778e-02}, {9.0000000000000000e+00, 6.3629370719841737980004837e-01}, {2.0000000000000000e+00, 9.2637723924396464525443662e-01}, @@ -1356,12 +1368,14 @@ var log1pSC = []float64{ var vfmodfSC = []float64{ Inf(-1), + Copysign(0, -1), Inf(1), NaN(), } var modfSC = [][2]float64{ {Inf(-1), NaN()}, // [2]float64{Copysign(0, -1), Inf(-1)}, - {Inf(1), NaN()}, // [2]float64{0, Inf(1)}, + {Copysign(0, -1), Copysign(0, -1)}, + {Inf(1), NaN()}, // [2]float64{0, Inf(1)}, {NaN(), NaN()}, } @@ -1609,6 +1623,7 @@ var vfsqrtSC = []float64{ 0, Inf(1), NaN(), + Float64frombits(2), // subnormal; see https://golang.org/issue/13013 } var sqrtSC = []float64{ NaN(), @@ -1617,6 +1632,7 @@ var sqrtSC = []float64{ 0, Inf(1), NaN(), + 3.1434555694052576e-162, } var vftanhSC = []float64{ @@ -1983,6 +1999,12 @@ func TestExpm1(t *testing.T) { t.Errorf("Expm1(%g) = %g, want %g", a, f, expm1[i]) } } + for i := 0; i < len(vf); i++ { + a := vf[i] * 10 + if f := Expm1(a); !close(expm1Large[i], f) { + t.Errorf("Expm1(%g) = %g, want %g", a, f, expm1Large[i]) + } + } for i := 0; i < len(vfexpm1SC); i++ { if f := Expm1(vfexpm1SC[i]); !alike(expm1SC[i], f) { t.Errorf("Expm1(%g) = %g, want %g", vfexpm1SC[i], f, expm1SC[i]) diff --git a/libgo/go/math/big/decimal.go b/libgo/go/math/big/decimal.go index 2595e5f..2c0c9da 100644 --- a/libgo/go/math/big/decimal.go +++ b/libgo/go/math/big/decimal.go @@ -20,7 +20,7 @@ package big // A decimal represents an unsigned floating-point number in decimal representation. -// The value of a non-zero decimal x is x.mant * 10 ** x.exp with 0.5 <= x.mant < 1, +// The value of a non-zero decimal d is d.mant * 10**d.exp with 0.5 <= d.mant < 1, // with the most-significant mantissa digit at index 0. For the zero decimal, the // mantissa length and exponent are 0. // The zero value for decimal represents a ready-to-use 0.0. @@ -29,6 +29,14 @@ type decimal struct { exp int // exponent } +// at returns the i'th mantissa digit, starting with the most significant digit at 0. +func (d *decimal) at(i int) byte { + if 0 <= i && i < len(d.mant) { + return d.mant[i] + } + return '0' +} + // Maximum shift amount that can be done in one pass without overflow. // A Word has _W bits and (1<<maxShift - 1)*10 + 9 must fit into Word. const maxShift = _W - 4 @@ -72,7 +80,7 @@ func (x *decimal) init(m nat, shift int) { } // Convert mantissa into decimal representation. - s := m.decimalString() // TODO(gri) avoid string conversion here + s := m.utoa(10) n := len(s) x.exp = n // Trim trailing zeros; instead the exponent is tracking @@ -92,12 +100,6 @@ func (x *decimal) init(m nat, shift int) { } } -// Possibly optimization: The current implementation of nat.string takes -// a charset argument. When a right shift is needed, we could provide -// "\x00\x01...\x09" instead of "012..9" (as in nat.decimalString) and -// avoid the repeated +'0' and -'0' operations in decimal.shr (and do a -// single +'0' pass at the end). - // shr implements x >> s, for s <= maxShift. func shr(x *decimal, s uint) { // Division by 1<<s using shift-and-subtract algorithm. diff --git a/libgo/go/math/big/decimal_test.go b/libgo/go/math/big/decimal_test.go index 81e022a..15bdb18 100644 --- a/libgo/go/math/big/decimal_test.go +++ b/libgo/go/math/big/decimal_test.go @@ -104,3 +104,13 @@ func TestDecimalRounding(t *testing.T) { } } } + +func BenchmarkDecimalConversion(b *testing.B) { + for i := 0; i < b.N; i++ { + for shift := -100; shift <= +100; shift++ { + var d decimal + d.init(natOne, shift) + d.String() + } + } +} diff --git a/libgo/go/math/big/doc.go b/libgo/go/math/big/doc.go new file mode 100644 index 0000000..a3c2375 --- /dev/null +++ b/libgo/go/math/big/doc.go @@ -0,0 +1,99 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package big implements arbitrary-precision arithmetic (big numbers). +The following numeric types are supported: + + Int signed integers + Rat rational numbers + Float floating-point numbers + +The zero value for an Int, Rat, or Float correspond to 0. Thus, new +values can be declared in the usual ways and denote 0 without further +initialization: + + var x Int // &x is an *Int of value 0 + var r = &Rat{} // r is a *Rat of value 0 + y := new(Float) // y is a *Float of value 0 + +Alternatively, new values can be allocated and initialized with factory +functions of the form: + + func NewT(v V) *T + +For instance, NewInt(x) returns an *Int set to the value of the int64 +argument x, NewRat(a, b) returns a *Rat set to the fraction a/b where +a and b are int64 values, and NewFloat(f) returns a *Float initialized +to the float64 argument f. More flexibility is provided with explicit +setters, for instance: + + var z1 Int + z1.SetUint64(123) // z1 := 123 + z2 := new(Rat).SetFloat64(1.2) // z2 := 6/5 + z3 := new(Float).SetInt(z1) // z3 := 123.0 + +Setters, numeric operations and predicates are represented as methods of +the form: + + func (z *T) SetV(v V) *T // z = v + func (z *T) Unary(x *T) *T // z = unary x + func (z *T) Binary(x, y *T) *T // z = x binary y + func (x *T) Pred() P // p = pred(x) + +with T one of Int, Rat, or Float. For unary and binary operations, the +result is the receiver (usually named z in that case; see below); if it +is one of the operands x or y it may be safely overwritten (and its memory +reused). + +Arithmetic expressions are typically written as a sequence of individual +method calls, with each call corresponding to an operation. The receiver +denotes the result and the method arguments are the operation's operands. +For instance, given three *Int values a, b and c, the invocation + + c.Add(a, b) + +computes the sum a + b and stores the result in c, overwriting whatever +value was held in c before. Unless specified otherwise, operations permit +aliasing of parameters, so it is perfectly ok to write + + sum.Add(sum, x) + +to accumulate values x in a sum. + +(By always passing in a result value via the receiver, memory use can be +much better controlled. Instead of having to allocate new memory for each +result, an operation can reuse the space allocated for the result value, +and overwrite that value with the new result in the process.) + +Notational convention: Incoming method parameters (including the receiver) +are named consistently in the API to clarify their use. Incoming operands +are usually named x, y, a, b, and so on, but never z. A parameter specifying +the result is named z (typically the receiver). + +For instance, the arguments for (*Int).Add are named x and y, and because +the receiver specifies the result destination, it is called z: + + func (z *Int) Add(x, y *Int) *Int + +Methods of this form typically return the incoming receiver as well, to +enable simple call chaining. + +Methods which don't require a result value to be passed in (for instance, +Int.Sign), simply return the result. In this case, the receiver is typically +the first operand, named x: + + func (x *Int) Sign() int + +Various methods support conversions between strings and corresponding +numeric values, and vice versa: *Int, *Rat, and *Float values implement +the Stringer interface for a (default) string representation of the value, +but also provide SetString methods to initialize a value from a string in +a variety of supported formats (see the respective SetString documentation). + +Finally, *Int, *Rat, and *Float satisfy the fmt package's Scanner interface +for scanning and (except for *Rat) the Formatter interface for formatted +printing. +*/ +package big diff --git a/libgo/go/math/big/example_rat_test.go b/libgo/go/math/big/example_rat_test.go new file mode 100644 index 0000000..f3127bb --- /dev/null +++ b/libgo/go/math/big/example_rat_test.go @@ -0,0 +1,67 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package big_test + +import ( + "fmt" + "math/big" +) + +// Use the classic continued fraction for e +// e = [1; 0, 1, 1, 2, 1, 1, ... 2n, 1, 1, ...] +// i.e., for the nth term, use +// 1 if n mod 3 != 1 +// (n-1)/3 * 2 if n mod 3 == 1 +func recur(n, lim int64) *big.Rat { + term := new(big.Rat) + if n%3 != 1 { + term.SetInt64(1) + } else { + term.SetInt64((n - 1) / 3 * 2) + } + + if n > lim { + return term + } + + // Directly initialize frac as the fractional + // inverse of the result of recur. + frac := new(big.Rat).Inv(recur(n+1, lim)) + + return term.Add(term, frac) +} + +// This example demonstrates how to use big.Rat to compute the +// first 15 terms in the sequence of rational convergents for +// the constant e (base of natural logarithm). +func Example_eConvergents() { + for i := 1; i <= 15; i++ { + r := recur(0, int64(i)) + + // Print r both as a fraction and as a floating-point number. + // Since big.Rat implements fmt.Formatter, we can use %-13s to + // get a left-aligned string representation of the fraction. + fmt.Printf("%-13s = %s\n", r, r.FloatString(8)) + } + + // Output: + // 2/1 = 2.00000000 + // 3/1 = 3.00000000 + // 8/3 = 2.66666667 + // 11/4 = 2.75000000 + // 19/7 = 2.71428571 + // 87/32 = 2.71875000 + // 106/39 = 2.71794872 + // 193/71 = 2.71830986 + // 1264/465 = 2.71827957 + // 1457/536 = 2.71828358 + // 2721/1001 = 2.71828172 + // 23225/8544 = 2.71828184 + // 25946/9545 = 2.71828182 + // 49171/18089 = 2.71828183 + // 517656/190435 = 2.71828183 +} diff --git a/libgo/go/math/big/float.go b/libgo/go/math/big/float.go index d7aa895..b1c748c 100644 --- a/libgo/go/math/big/float.go +++ b/libgo/go/math/big/float.go @@ -124,7 +124,7 @@ const ( // rounding error is described by the Float's Accuracy. type RoundingMode byte -// The following rounding modes are supported. +// These constants define supported rounding modes. const ( ToNearestEven RoundingMode = iota // == IEEE 754-2008 roundTiesToEven ToNearestAway // == IEEE 754-2008 roundTiesToAway @@ -298,7 +298,7 @@ func (z *Float) setExpAndRound(exp int64, sbit uint) { // not require 0.5 <= |mant| < 1.0. Specifically: // // mant := new(Float) -// new(Float).SetMantExp(mant, x.SetMantExp(mant)).Cmp(x).Eql() is true +// new(Float).SetMantExp(mant, x.MantExp(mant)).Cmp(x) == 0 // // Special cases are: // @@ -1123,7 +1123,7 @@ func (x *Float) Int(z *Int) (*Int, Accuracy) { // Rat returns the rational number corresponding to x; // or nil if x is an infinity. -// The result is Exact is x is not an Inf. +// The result is Exact if x is not an Inf. // If a non-nil *Rat argument z is provided, Rat stores // the result in z instead of allocating a new Rat. func (x *Float) Rat(z *Rat) (*Rat, Accuracy) { @@ -1272,7 +1272,7 @@ func (z *Float) usub(x, y *Float) { ex = ey } - // operands may have cancelled each other out + // operands may have canceled each other out if len(z.mant) == 0 { z.acc = Exact z.form = zero diff --git a/libgo/go/math/big/floatconv.go b/libgo/go/math/big/floatconv.go index 4a070ca..37d5c06 100644 --- a/libgo/go/math/big/floatconv.go +++ b/libgo/go/math/big/floatconv.go @@ -72,37 +72,46 @@ func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) { // ebase**exp. Finally, mantissa normalization (shift left) requires // a correcting multiplication by 2**(-shiftcount). Multiplications // are commutative, so we can apply them in any order as long as there - // is no loss of precision. We only have powers of 2 and 10; keep - // track via separate exponents exp2 and exp10. + // is no loss of precision. We only have powers of 2 and 10, and + // we split powers of 10 into the product of the same powers of + // 2 and 5. This reduces the size of the multiplication factor + // needed for base-10 exponents. - // normalize mantissa and get initial binary exponent - var exp2 = int64(len(z.mant))*_W - fnorm(z.mant) + // normalize mantissa and determine initial exponent contributions + exp2 := int64(len(z.mant))*_W - fnorm(z.mant) + exp5 := int64(0) // determine binary or decimal exponent contribution of decimal point - var exp10 int64 if fcount < 0 { // The mantissa has a "decimal" point ddd.dddd; and // -fcount is the number of digits to the right of '.'. // Adjust relevant exponent accodingly. + d := int64(fcount) switch b { - case 16: - fcount *= 4 // hexadecimal digits are 4 bits each - fallthrough + case 10: + exp5 = d + fallthrough // 10**e == 5**e * 2**e case 2: - exp2 += int64(fcount) - default: // b == 10 - exp10 = int64(fcount) + exp2 += d + case 16: + exp2 += d * 4 // hexadecimal digits are 4 bits each + default: + panic("unexpected mantissa base") } - // we don't need fcount anymore + // fcount consumed - not needed anymore } // take actual exponent into account - if ebase == 2 { + switch ebase { + case 10: + exp5 += exp + fallthrough + case 2: exp2 += exp - } else { // ebase == 10 - exp10 += exp + default: + panic("unexpected exponent base") } - // we don't need exp anymore + // exp consumed - not needed anymore // apply 2**exp2 if MinExp <= exp2 && exp2 <= MaxExp { @@ -115,49 +124,76 @@ func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) { return } - if exp10 == 0 { - // no decimal exponent to consider + if exp5 == 0 { + // no decimal exponent contribution z.round(0) return } - // exp10 != 0 + // exp5 != 0 - // apply 10**exp10 + // apply 5**exp5 p := new(Float).SetPrec(z.Prec() + 64) // use more bits for p -- TODO(gri) what is the right number? - if exp10 < 0 { - z.uquo(z, p.pow10(-exp10)) + if exp5 < 0 { + z.Quo(z, p.pow5(uint64(-exp5))) } else { - z.umul(z, p.pow10(exp10)) + z.Mul(z, p.pow5(uint64(exp5))) } return } -// These powers of 10 can be represented exactly as a float64. -var pow10tab = [...]float64{ - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, +// These powers of 5 fit into a uint64. +// +// for p, q := uint64(0), uint64(1); p < q; p, q = q, q*5 { +// fmt.Println(q) +// } +// +var pow5tab = [...]uint64{ + 1, + 5, + 25, + 125, + 625, + 3125, + 15625, + 78125, + 390625, + 1953125, + 9765625, + 48828125, + 244140625, + 1220703125, + 6103515625, + 30517578125, + 152587890625, + 762939453125, + 3814697265625, + 19073486328125, + 95367431640625, + 476837158203125, + 2384185791015625, + 11920928955078125, + 59604644775390625, + 298023223876953125, + 1490116119384765625, + 7450580596923828125, } -// pow10 sets z to 10**n and returns z. +// pow5 sets z to 5**n and returns z. // n must not be negative. -func (z *Float) pow10(n int64) *Float { - if n < 0 { - panic("pow10 called with negative argument") - } - - const m = int64(len(pow10tab) - 1) +func (z *Float) pow5(n uint64) *Float { + const m = uint64(len(pow5tab) - 1) if n <= m { - return z.SetFloat64(pow10tab[n]) + return z.SetUint64(pow5tab[n]) } // n > m - z.SetFloat64(pow10tab[m]) + z.SetUint64(pow5tab[m]) n -= m // use more bits for f than for z // TODO(gri) what is the right number? - f := new(Float).SetPrec(z.Prec() + 64).SetInt64(10) + f := new(Float).SetPrec(z.Prec() + 64).SetUint64(5) for n > 0 { if n&1 != 0 { diff --git a/libgo/go/math/big/floatconv_test.go b/libgo/go/math/big/floatconv_test.go index 4f23953..b6f9993 100644 --- a/libgo/go/math/big/floatconv_test.go +++ b/libgo/go/math/big/floatconv_test.go @@ -139,6 +139,8 @@ func TestFloatSetFloat64String(t *testing.T) { } } +func fdiv(a, b float64) float64 { return a / b } + const ( below1e23 = 99999999999999974834176 above1e23 = 100000000000000008388608 @@ -187,11 +189,11 @@ func TestFloat64Text(t *testing.T) { {1, 'e', 5, "1.00000e+00"}, {1, 'f', 5, "1.00000"}, {1, 'g', 5, "1"}, - // {1, 'g', -1, "1"}, - // {20, 'g', -1, "20"}, - // {1234567.8, 'g', -1, "1.2345678e+06"}, - // {200000, 'g', -1, "200000"}, - // {2000000, 'g', -1, "2e+06"}, + {1, 'g', -1, "1"}, + {20, 'g', -1, "20"}, + {1234567.8, 'g', -1, "1.2345678e+06"}, + {200000, 'g', -1, "200000"}, + {2000000, 'g', -1, "2e+06"}, // g conversion and zero suppression {400, 'g', 2, "4e+02"}, @@ -207,22 +209,22 @@ func TestFloat64Text(t *testing.T) { {0, 'e', 5, "0.00000e+00"}, {0, 'f', 5, "0.00000"}, {0, 'g', 5, "0"}, - // {0, 'g', -1, "0"}, + {0, 'g', -1, "0"}, {-1, 'e', 5, "-1.00000e+00"}, {-1, 'f', 5, "-1.00000"}, {-1, 'g', 5, "-1"}, - // {-1, 'g', -1, "-1"}, + {-1, 'g', -1, "-1"}, {12, 'e', 5, "1.20000e+01"}, {12, 'f', 5, "12.00000"}, {12, 'g', 5, "12"}, - // {12, 'g', -1, "12"}, + {12, 'g', -1, "12"}, {123456700, 'e', 5, "1.23457e+08"}, {123456700, 'f', 5, "123456700.00000"}, {123456700, 'g', 5, "1.2346e+08"}, - // {123456700, 'g', -1, "1.234567e+08"}, + {123456700, 'g', -1, "1.234567e+08"}, {1.2345e6, 'e', 5, "1.23450e+06"}, {1.2345e6, 'f', 5, "1234500.00000"}, @@ -232,36 +234,38 @@ func TestFloat64Text(t *testing.T) { {1e23, 'f', 17, "99999999999999991611392.00000000000000000"}, {1e23, 'g', 17, "9.9999999999999992e+22"}, - // {1e23, 'e', -1, "1e+23"}, - // {1e23, 'f', -1, "100000000000000000000000"}, - // {1e23, 'g', -1, "1e+23"}, + {1e23, 'e', -1, "1e+23"}, + {1e23, 'f', -1, "100000000000000000000000"}, + {1e23, 'g', -1, "1e+23"}, {below1e23, 'e', 17, "9.99999999999999748e+22"}, {below1e23, 'f', 17, "99999999999999974834176.00000000000000000"}, {below1e23, 'g', 17, "9.9999999999999975e+22"}, - // {below1e23, 'e', -1, "9.999999999999997e+22"}, - // {below1e23, 'f', -1, "99999999999999970000000"}, - // {below1e23, 'g', -1, "9.999999999999997e+22"}, + {below1e23, 'e', -1, "9.999999999999997e+22"}, + {below1e23, 'f', -1, "99999999999999970000000"}, + {below1e23, 'g', -1, "9.999999999999997e+22"}, {above1e23, 'e', 17, "1.00000000000000008e+23"}, {above1e23, 'f', 17, "100000000000000008388608.00000000000000000"}, - // {above1e23, 'g', 17, "1.0000000000000001e+23"}, + {above1e23, 'g', 17, "1.0000000000000001e+23"}, - // {above1e23, 'e', -1, "1.0000000000000001e+23"}, - // {above1e23, 'f', -1, "100000000000000010000000"}, - // {above1e23, 'g', -1, "1.0000000000000001e+23"}, + {above1e23, 'e', -1, "1.0000000000000001e+23"}, + {above1e23, 'f', -1, "100000000000000010000000"}, + {above1e23, 'g', -1, "1.0000000000000001e+23"}, - // {fdiv(5e-304, 1e20), 'g', -1, "5e-324"}, - // {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"}, + {5e-304 / 1e20, 'g', -1, "5e-324"}, + {-5e-304 / 1e20, 'g', -1, "-5e-324"}, + {fdiv(5e-304, 1e20), 'g', -1, "5e-324"}, // avoid constant arithmetic + {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"}, // avoid constant arithmetic - // {32, 'g', -1, "32"}, - // {32, 'g', 0, "3e+01"}, + {32, 'g', -1, "32"}, + {32, 'g', 0, "3e+01"}, - // {100, 'x', -1, "%x"}, + {100, 'x', -1, "%x"}, - // {math.NaN(), 'g', -1, "NaN"}, - // {-math.NaN(), 'g', -1, "NaN"}, + // {math.NaN(), 'g', -1, "NaN"}, // Float doesn't support NaNs + // {-math.NaN(), 'g', -1, "NaN"}, // Float doesn't support NaNs {math.Inf(0), 'g', -1, "+Inf"}, {math.Inf(-1), 'g', -1, "-Inf"}, {-math.Inf(0), 'g', -1, "-Inf"}, @@ -279,18 +283,24 @@ func TestFloat64Text(t *testing.T) { {1.5, 'f', 0, "2"}, // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ - // {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"}, + {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"}, // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ - // {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"}, + {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"}, // Issue 2625. {383260575764816448, 'f', 0, "383260575764816448"}, - // {383260575764816448, 'g', -1, "3.8326057576481645e+17"}, + {383260575764816448, 'g', -1, "3.8326057576481645e+17"}, } { - f := new(Float).SetFloat64(test.x) + // The test cases are from the strconv package which tests float64 values. + // When formatting values with prec = -1 (shortest representation), + // the actually available mantissa precision matters. + // For denormalized values, that precision is < 53 (SetFloat64 default). + // Compute and set the actual precision explicitly. + f := new(Float).SetPrec(actualPrec(test.x)).SetFloat64(test.x) got := f.Text(test.format, test.prec) if got != test.want { t.Errorf("%v: got %s; want %s", test, got, test.want) + continue } if test.format == 'b' && test.x == 0 { @@ -308,6 +318,15 @@ func TestFloat64Text(t *testing.T) { } } +// actualPrec returns the number of actually used mantissa bits. +func actualPrec(x float64) uint { + if bits := math.Float64bits(x); x != 0 && bits&(0x7ff<<52) == 0 { + // x is denormalized + return 64 - nlz64(bits&(1<<52-1)) + } + return 53 +} + func TestFloatText(t *testing.T) { for _, test := range []struct { x string @@ -367,9 +386,19 @@ func TestFloatText(t *testing.T) { // make sure "stupid" exponents don't stall the machine {"1e1000000", 64, 'p', 0, "0x.88b3a28a05eade3ap+3321929"}, - {"1e1000000000", 64, 'p', 0, "0x.ecc5f45aa573d3p+1538481529"}, + {"1e646456992", 64, 'p', 0, "0x.e883a0c5c8c7c42ap+2147483644"}, + {"1e646456993", 64, 'p', 0, "+Inf"}, + {"1e1000000000", 64, 'p', 0, "+Inf"}, {"1e-1000000", 64, 'p', 0, "0x.efb4542cc8ca418ap-3321928"}, - {"1e-1000000000", 64, 'p', 0, "0x.8a64dd983a4c7dabp-1538481528"}, + {"1e-646456993", 64, 'p', 0, "0x.e17c8956983d9d59p-2147483647"}, + {"1e-646456994", 64, 'p', 0, "0"}, + {"1e-1000000000", 64, 'p', 0, "0"}, + + // minimum and maximum values + {"1p2147483646", 64, 'p', 0, "0x.8p+2147483647"}, + {"0x.8p2147483647", 64, 'p', 0, "0x.8p+2147483647"}, + {"0x.8p-2147483647", 64, 'p', 0, "0x.8p-2147483647"}, + {"1p-2147483649", 64, 'p', 0, "0x.8p-2147483648"}, // TODO(gri) need tests for actual large Floats @@ -438,9 +467,6 @@ func TestFloatFormat(t *testing.T) { value interface{} // float32, float64, or string (== 512bit *Float) want string }{ - // TODO(gri) uncomment the disabled 'g'/'G' formats - // below once (*Float).Text supports prec < 0 - // from fmt/fmt_test.go {"%+.3e", 0.0, "+0.000e+00"}, {"%+.3e", 1.0, "+1.000e+00"}, @@ -471,9 +497,9 @@ func TestFloatFormat(t *testing.T) { {"%f", 1234.5678e-8, "0.000012"}, {"%f", -7.0, "-7.000000"}, {"%f", -1e-9, "-0.000000"}, - // {"%g", 1234.5678e3, "1.2345678e+06"}, - // {"%g", float32(1234.5678e3), "1.2345678e+06"}, - // {"%g", 1234.5678e-8, "1.2345678e-05"}, + {"%g", 1234.5678e3, "1.2345678e+06"}, + {"%g", float32(1234.5678e3), "1.2345678e+06"}, + {"%g", 1234.5678e-8, "1.2345678e-05"}, {"%g", -7.0, "-7"}, {"%g", -1e-9, "-1e-09"}, {"%g", float32(-1e-9), "-1e-09"}, @@ -482,9 +508,9 @@ func TestFloatFormat(t *testing.T) { {"%E", 1234.5678e-8, "1.234568E-05"}, {"%E", -7.0, "-7.000000E+00"}, {"%E", -1e-9, "-1.000000E-09"}, - // {"%G", 1234.5678e3, "1.2345678E+06"}, - // {"%G", float32(1234.5678e3), "1.2345678E+06"}, - // {"%G", 1234.5678e-8, "1.2345678E-05"}, + {"%G", 1234.5678e3, "1.2345678E+06"}, + {"%G", float32(1234.5678e3), "1.2345678E+06"}, + {"%G", 1234.5678e-8, "1.2345678E-05"}, {"%G", -7.0, "-7"}, {"%G", -1e-9, "-1E-09"}, {"%G", float32(-1e-9), "-1E-09"}, @@ -500,9 +526,9 @@ func TestFloatFormat(t *testing.T) { {"%-20f", 1.23456789e3, "1234.567890 "}, {"%20.8f", 1.23456789e3, " 1234.56789000"}, {"%20.8f", 1.23456789e-3, " 0.00123457"}, - // {"%g", 1.23456789e3, "1234.56789"}, - // {"%g", 1.23456789e-3, "0.00123456789"}, - // {"%g", 1.23456789e20, "1.23456789e+20"}, + {"%g", 1.23456789e3, "1234.56789"}, + {"%g", 1.23456789e-3, "0.00123456789"}, + {"%g", 1.23456789e20, "1.23456789e+20"}, {"%20e", math.Inf(1), " +Inf"}, {"%-20f", math.Inf(-1), "-Inf "}, @@ -541,7 +567,6 @@ func TestFloatFormat(t *testing.T) { {"%v", -1e-9, "-1e-09"}, {"%v", float32(-1e-9), "-1e-09"}, {"%010v", 0.0, "0000000000"}, - {"%010v", 0.0, "0000000000"}, // *Float cases {"%.20f", "1e-20", "0.00000000000000000001"}, @@ -571,3 +596,67 @@ func TestFloatFormat(t *testing.T) { } } } + +func BenchmarkParseFloatSmallExp(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, s := range []string{ + "1e0", + "1e-1", + "1e-2", + "1e-3", + "1e-4", + "1e-5", + "1e-10", + "1e-20", + "1e-50", + "1e1", + "1e2", + "1e3", + "1e4", + "1e5", + "1e10", + "1e20", + "1e50", + } { + var x Float + _, _, err := x.Parse(s, 0) + if err != nil { + b.Fatalf("%s: %v", s, err) + } + } + } +} + +func BenchmarkParseFloatLargeExp(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, s := range []string{ + "1e0", + "1e-10", + "1e-20", + "1e-30", + "1e-40", + "1e-50", + "1e-100", + "1e-500", + "1e-1000", + "1e-5000", + "1e-10000", + "1e10", + "1e20", + "1e30", + "1e40", + "1e50", + "1e100", + "1e500", + "1e1000", + "1e5000", + "1e10000", + } { + var x Float + _, _, err := x.Parse(s, 0) + if err != nil { + b.Fatalf("%s: %v", s, err) + } + } + } +} diff --git a/libgo/go/math/big/floatexample_test.go b/libgo/go/math/big/floatexample_test.go index 69686b7..05bce61 100644 --- a/libgo/go/math/big/floatexample_test.go +++ b/libgo/go/math/big/floatexample_test.go @@ -111,3 +111,33 @@ func ExampleFloat_Cmp() { // +Inf 1.2 1 // +Inf +Inf 0 } + +func ExampleRoundingMode() { + operands := []float64{2.6, 2.5, 2.1, -2.1, -2.5, -2.6} + + fmt.Print(" x") + for mode := big.ToNearestEven; mode <= big.ToPositiveInf; mode++ { + fmt.Printf(" %s", mode) + } + fmt.Println() + + for _, f64 := range operands { + fmt.Printf("%4g", f64) + for mode := big.ToNearestEven; mode <= big.ToPositiveInf; mode++ { + // sample operands above require 2 bits to represent mantissa + // set binary precision to 2 to round them to integer values + f := new(big.Float).SetPrec(2).SetMode(mode).SetFloat64(f64) + fmt.Printf(" %*g", len(mode.String()), f) + } + fmt.Println() + } + + // Output: + // x ToNearestEven ToNearestAway ToZero AwayFromZero ToNegativeInf ToPositiveInf + // 2.6 3 3 2 3 2 3 + // 2.5 2 3 2 3 2 3 + // 2.1 2 2 2 3 2 3 + // -2.1 -2 -2 -2 -3 -3 -2 + // -2.5 -2 -3 -2 -3 -3 -2 + // -2.6 -3 -3 -2 -3 -3 -2 +} diff --git a/libgo/go/math/big/floatmarsh.go b/libgo/go/math/big/floatmarsh.go new file mode 100644 index 0000000..44987ee --- /dev/null +++ b/libgo/go/math/big/floatmarsh.go @@ -0,0 +1,33 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements encoding/decoding of Floats. + +package big + +import "fmt" + +// MarshalText implements the encoding.TextMarshaler interface. +// Only the Float value is marshaled (in full precision), other +// attributes such as precision or accuracy are ignored. +func (x *Float) MarshalText() (text []byte, err error) { + if x == nil { + return []byte("<nil>"), nil + } + var buf []byte + return x.Append(buf, 'g', -1), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +// The result is rounded per the precision and rounding mode of z. +// If z's precision is 0, it is changed to 64 before rounding takes +// effect. +func (z *Float) UnmarshalText(text []byte) error { + // TODO(gri): get rid of the []byte/string conversion + _, _, err := z.Parse(string(text), 0) + if err != nil { + err = fmt.Errorf("math/big: cannot unmarshal %q into a *big.Float (%v)", text, err) + } + return err +} diff --git a/libgo/go/math/big/floatmarsh_test.go b/libgo/go/math/big/floatmarsh_test.go new file mode 100644 index 0000000..d7ef2fc --- /dev/null +++ b/libgo/go/math/big/floatmarsh_test.go @@ -0,0 +1,54 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package big + +import ( + "encoding/json" + "testing" +) + +var floatVals = []string{ + "0", + "1", + "0.1", + "2.71828", + "1234567890", + "3.14e1234", + "3.14e-1234", + "0.738957395793475734757349579759957975985497e100", + "0.73895739579347546656564656573475734957975995797598589749859834759476745986795497e100", + "inf", + "Inf", +} + +func TestFloatJSONEncoding(t *testing.T) { + for _, test := range floatVals { + for _, sign := range []string{"", "+", "-"} { + for _, prec := range []uint{0, 1, 2, 10, 53, 64, 100, 1000} { + x := sign + test + var tx Float + _, _, err := tx.SetPrec(prec).Parse(x, 0) + if err != nil { + t.Errorf("parsing of %s (prec = %d) failed (invalid test case): %v", x, prec, err) + continue + } + b, err := json.Marshal(&tx) + if err != nil { + t.Errorf("marshaling of %v (prec = %d) failed: %v", &tx, prec, err) + continue + } + var rx Float + rx.SetPrec(prec) + if err := json.Unmarshal(b, &rx); err != nil { + t.Errorf("unmarshaling of %v (prec = %d) failed: %v", &tx, prec, err) + continue + } + if rx.Cmp(&tx) != 0 { + t.Errorf("JSON encoding of %v (prec = %d) failed: got %v want %v", &tx, prec, &rx, &tx) + } + } + } + } +} diff --git a/libgo/go/math/big/ftoa.go b/libgo/go/math/big/ftoa.go index 5c5f2ce..c5cdb5e 100644 --- a/libgo/go/math/big/ftoa.go +++ b/libgo/go/math/big/ftoa.go @@ -9,9 +9,9 @@ package big import ( + "bytes" "fmt" "strconv" - "strings" ) // Text converts the floating-point number x to a string according @@ -37,16 +37,16 @@ import ( // printed by the 'e', 'E', 'f', 'g', and 'G' formats. For 'e', 'E', and 'f' // it is the number of digits after the decimal point. For 'g' and 'G' it is // the total number of digits. A negative precision selects the smallest -// number of digits necessary to identify the value x uniquely. +// number of decimal digits necessary to identify the value x uniquely using +// x.Prec() mantissa bits. // The prec value is ignored for the 'b' or 'p' format. -// -// BUG(gri) Float.Text does not accept negative precisions (issue #10991). func (x *Float) Text(format byte, prec int) string { const extra = 10 // TODO(gri) determine a good/better value here return string(x.Append(make([]byte, 0, prec+extra), format, prec)) } // String formats x like x.Text('g', 10). +// (String must be called explicitly, Float.Format does not support %s verb.) func (x *Float) String() string { return x.Text('g', 10) } @@ -83,6 +83,7 @@ func (x *Float) Append(buf []byte, fmt byte, prec int) []byte { // 1) convert Float to multiprecision decimal var d decimal // == 0.0 if x.form == finite { + // x != 0 d.init(x.mant, int(x.exp)-x.mant.bitLen()) } @@ -90,9 +91,7 @@ func (x *Float) Append(buf []byte, fmt byte, prec int) []byte { shortest := false if prec < 0 { shortest = true - panic("unimplemented") - // TODO(gri) complete this - // roundShortest(&d, f.mant, int(f.exp)) + roundShortest(&d, x) // Precision for shortest representation mode. switch fmt { case 'e', 'E': @@ -158,6 +157,80 @@ func (x *Float) Append(buf []byte, fmt byte, prec int) []byte { return append(buf, '%', fmt) } +func roundShortest(d *decimal, x *Float) { + // if the mantissa is zero, the number is zero - stop now + if len(d.mant) == 0 { + return + } + + // Approach: All numbers in the interval [x - 1/2ulp, x + 1/2ulp] + // (possibly exclusive) round to x for the given precision of x. + // Compute the lower and upper bound in decimal form and find the + // shortest decimal number d such that lower <= d <= upper. + + // TODO(gri) strconv/ftoa.do describes a shortcut in some cases. + // See if we can use it (in adjusted form) here as well. + + // 1) Compute normalized mantissa mant and exponent exp for x such + // that the lsb of mant corresponds to 1/2 ulp for the precision of + // x (i.e., for mant we want x.prec + 1 bits). + mant := nat(nil).set(x.mant) + exp := int(x.exp) - mant.bitLen() + s := mant.bitLen() - int(x.prec+1) + switch { + case s < 0: + mant = mant.shl(mant, uint(-s)) + case s > 0: + mant = mant.shr(mant, uint(+s)) + } + exp += s + // x = mant * 2**exp with lsb(mant) == 1/2 ulp of x.prec + + // 2) Compute lower bound by subtracting 1/2 ulp. + var lower decimal + var tmp nat + lower.init(tmp.sub(mant, natOne), exp) + + // 3) Compute upper bound by adding 1/2 ulp. + var upper decimal + upper.init(tmp.add(mant, natOne), exp) + + // The upper and lower bounds are possible outputs only if + // the original mantissa is even, so that ToNearestEven rounding + // would round to the original mantissa and not the neighbors. + inclusive := mant[0]&2 == 0 // test bit 1 since original mantissa was shifted by 1 + + // Now we can figure out the minimum number of digits required. + // Walk along until d has distinguished itself from upper and lower. + for i, m := range d.mant { + l := lower.at(i) + u := upper.at(i) + + // Okay to round down (truncate) if lower has a different digit + // or if lower is inclusive and is exactly the result of rounding + // down (i.e., and we have reached the final digit of lower). + okdown := l != m || inclusive && i+1 == len(lower.mant) + + // Okay to round up if upper has a different digit and either upper + // is inclusive or upper is bigger than the result of rounding up. + okup := m != u && (inclusive || m+1 < u || i+1 < len(upper.mant)) + + // If it's okay to do either, then round to the nearest one. + // If it's okay to do only one, do it. + switch { + case okdown && okup: + d.round(i + 1) + return + case okdown: + d.roundDown(i + 1) + return + case okup: + d.roundUp(i + 1) + return + } + } +} + // %e: d.ddddde±dd func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte { // first digit @@ -219,11 +292,7 @@ func fmtF(buf []byte, prec int, d decimal) []byte { if prec > 0 { buf = append(buf, '.') for i := 0; i < prec; i++ { - ch := byte('0') - if j := d.exp + i; 0 <= j && j < len(d.mant) { - ch = d.mant[j] - } - buf = append(buf, ch) + buf = append(buf, d.at(d.exp+i)) } } @@ -255,7 +324,7 @@ func (x *Float) fmtB(buf []byte) []byte { m = nat(nil).shr(m, uint(w-x.prec)) } - buf = append(buf, m.decimalString()...) + buf = append(buf, m.utoa(10)...) buf = append(buf, 'p') e := int64(x.exp) - int64(x.prec) if e >= 0 { @@ -289,7 +358,7 @@ func (x *Float) fmtP(buf []byte) []byte { m = m[i:] buf = append(buf, "0x."...) - buf = append(buf, strings.TrimRight(m.hexString(), "0")...) + buf = append(buf, bytes.TrimRight(m.utoa(16), "0")...) buf = append(buf, 'p') if x.exp >= 0 { buf = append(buf, '+') @@ -314,10 +383,6 @@ func min(x, y int) int { // '+' and ' ' for sign control, '0' for space or zero padding, // and '-' for left or right justification. See the fmt package // for details. -// -// BUG(gri) A missing precision for the 'g' format, or a negative -// (via '*') precision is not yet supported. Instead the -// default precision (6) is used in that case (issue #10991). func (x *Float) Format(s fmt.State, format rune) { prec, hasPrec := s.Precision() if !hasPrec { @@ -336,8 +401,7 @@ func (x *Float) Format(s fmt.State, format rune) { fallthrough case 'g', 'G': if !hasPrec { - // TODO(gri) uncomment once (*Float).Text handles prec < 0 - // prec = -1 // default precision for 'g', 'G' + prec = -1 // default precision for 'g', 'G' } default: fmt.Fprintf(s, "%%!%c(*big.Float=%s)", format, x.String()) diff --git a/libgo/go/math/big/int.go b/libgo/go/math/big/int.go index 65334e0..67ab704 100644 --- a/libgo/go/math/big/int.go +++ b/libgo/go/math/big/int.go @@ -273,7 +273,7 @@ func (z *Int) Mod(x, y *Int) *Int { // DivMod implements Euclidean division and modulus (unlike Go): // // q = x div y such that -// m = x - y*q with 0 <= m < |q| +// m = x - y*q with 0 <= m < |y| // // (See Raymond T. Boute, ``The Euclidean definition of the functions // div and mod''. ACM Transactions on Programming Languages and @@ -551,8 +551,11 @@ func (z *Int) binaryGCD(a, b *Int) *Int { } // ProbablyPrime performs n Miller-Rabin tests to check whether x is prime. -// If it returns true, x is prime with probability 1 - 1/4^n. -// If it returns false, x is not prime. n must be > 0. +// If x is prime, it returns true. +// If x is not prime, it returns false with probability at least 1 - ¼ⁿ. +// +// It is not suitable for judging primes that an adversary may have crafted +// to fool this test. func (x *Int) ProbablyPrime(n int) bool { if n <= 0 { panic("non-positive n for ProbablyPrime") @@ -640,23 +643,23 @@ func Jacobi(x, y *Int) int { } } -// ModSqrt sets z to a square root of x mod p if such a square root exists, and -// returns z. The modulus p must be an odd prime. If x is not a square mod p, -// ModSqrt leaves z unchanged and returns nil. This function panics if p is -// not an odd integer. -func (z *Int) ModSqrt(x, p *Int) *Int { - switch Jacobi(x, p) { - case -1: - return nil // x is not a square mod p - case 0: - return z.SetInt64(0) // sqrt(0) mod p = 0 - case 1: - break - } - if x.neg || x.Cmp(p) >= 0 { // ensure 0 <= x < p - x = new(Int).Mod(x, p) - } +// modSqrt3Mod4 uses the identity +// (a^((p+1)/4))^2 mod p +// == u^(p+1) mod p +// == u^2 mod p +// to calculate the square root of any quadratic residue mod p quickly for 3 +// mod 4 primes. +func (z *Int) modSqrt3Mod4Prime(x, p *Int) *Int { + z.Set(p) // z = p + z.Add(z, intOne) // z = p + 1 + z.Rsh(z, 2) // z = (p + 1) / 4 + z.Exp(x, z, p) // z = x^z mod p + return z +} +// modSqrtTonelliShanks uses the Tonelli-Shanks algorithm to find the square +// root of a quadratic residue modulo any prime. +func (z *Int) modSqrtTonelliShanks(x, p *Int) *Int { // Break p-1 into s*2^e such that s is odd. var s Int s.Sub(p, intOne) @@ -703,6 +706,31 @@ func (z *Int) ModSqrt(x, p *Int) *Int { } } +// ModSqrt sets z to a square root of x mod p if such a square root exists, and +// returns z. The modulus p must be an odd prime. If x is not a square mod p, +// ModSqrt leaves z unchanged and returns nil. This function panics if p is +// not an odd integer. +func (z *Int) ModSqrt(x, p *Int) *Int { + switch Jacobi(x, p) { + case -1: + return nil // x is not a square mod p + case 0: + return z.SetInt64(0) // sqrt(0) mod p = 0 + case 1: + break + } + if x.neg || x.Cmp(p) >= 0 { // ensure 0 <= x < p + x = new(Int).Mod(x, p) + } + + // Check whether p is 3 mod 4, and if so, use the faster algorithm. + if len(p.abs) > 0 && p.abs[0]%4 == 3 { + return z.modSqrt3Mod4Prime(x, p) + } + // Otherwise, use Tonelli-Shanks. + return z.modSqrtTonelliShanks(x, p) +} + // Lsh sets z = x << n and returns z. func (z *Int) Lsh(x *Int, n uint) *Int { z.abs = z.abs.shl(x.abs, n) @@ -904,65 +932,3 @@ func (z *Int) Not(x *Int) *Int { z.neg = true // z cannot be zero if x is positive return z } - -// Gob codec version. Permits backward-compatible changes to the encoding. -const intGobVersion byte = 1 - -// GobEncode implements the gob.GobEncoder interface. -func (x *Int) GobEncode() ([]byte, error) { - if x == nil { - return nil, nil - } - buf := make([]byte, 1+len(x.abs)*_S) // extra byte for version and sign bit - i := x.abs.bytes(buf) - 1 // i >= 0 - b := intGobVersion << 1 // make space for sign bit - if x.neg { - b |= 1 - } - buf[i] = b - return buf[i:], nil -} - -// GobDecode implements the gob.GobDecoder interface. -func (z *Int) GobDecode(buf []byte) error { - if len(buf) == 0 { - // Other side sent a nil or default value. - *z = Int{} - return nil - } - b := buf[0] - if b>>1 != intGobVersion { - return fmt.Errorf("Int.GobDecode: encoding version %d not supported", b>>1) - } - z.neg = b&1 != 0 - z.abs = z.abs.setBytes(buf[1:]) - return nil -} - -// MarshalJSON implements the json.Marshaler interface. -func (z *Int) MarshalJSON() ([]byte, error) { - // TODO(gri): get rid of the []byte/string conversions - return []byte(z.String()), nil -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -func (z *Int) UnmarshalJSON(text []byte) error { - // TODO(gri): get rid of the []byte/string conversions - if _, ok := z.SetString(string(text), 0); !ok { - return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text) - } - return nil -} - -// MarshalText implements the encoding.TextMarshaler interface. -func (z *Int) MarshalText() (text []byte, err error) { - return []byte(z.String()), nil -} - -// UnmarshalText implements the encoding.TextUnmarshaler interface. -func (z *Int) UnmarshalText(text []byte) error { - if _, ok := z.SetString(string(text), 0); !ok { - return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text) - } - return nil -} diff --git a/libgo/go/math/big/int_test.go b/libgo/go/math/big/int_test.go index 88c8c2b..45a3765 100644 --- a/libgo/go/math/big/int_test.go +++ b/libgo/go/math/big/int_test.go @@ -6,10 +6,7 @@ package big import ( "bytes" - "encoding/gob" "encoding/hex" - "encoding/json" - "encoding/xml" "fmt" "math/rand" "testing" @@ -387,6 +384,11 @@ func TestSetBytes(t *testing.T) { } func checkBytes(b []byte) bool { + // trim leading zero bytes since Bytes() won't return them + // (was issue 12231) + for len(b) > 0 && b[0] == 0 { + b = b[1:] + } b2 := new(Int).SetBytes(b).Bytes() return bytes.Equal(b, b2) } @@ -542,6 +544,9 @@ var expTests = []struct { {"0x8000000000000000", "1000", "6719", "1603"}, {"0x8000000000000000", "1000000", "6719", "3199"}, {"0x8000000000000000", "-1000000", "6719", "1"}, + + {"0xffffffffffffffffffffffffffffffff", "0x12345678123456781234567812345678123456789", "0x01112222333344445555666677778889", "0x36168FA1DB3AAE6C8CE647E137F97A"}, + { "2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347", "298472983472983471903246121093472394872319615612417471234712061", @@ -550,11 +555,23 @@ var expTests = []struct { }, // test case for issue 8822 { + "11001289118363089646017359372117963499250546375269047542777928006103246876688756735760905680604646624353196869572752623285140408755420374049317646428185270079555372763503115646054602867593662923894140940837479507194934267532831694565516466765025434902348314525627418515646588160955862839022051353653052947073136084780742729727874803457643848197499548297570026926927502505634297079527299004267769780768565695459945235586892627059178884998772989397505061206395455591503771677500931269477503508150175717121828518985901959919560700853226255420793148986854391552859459511723547532575574664944815966793196961286234040892865", + "0xB08FFB20760FFED58FADA86DFEF71AD72AA0FA763219618FE022C197E54708BB1191C66470250FCE8879487507CEE41381CA4D932F81C2B3F1AB20B539D50DCD", + "0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", + "21484252197776302499639938883777710321993113097987201050501182909581359357618579566746556372589385361683610524730509041328855066514963385522570894839035884713051640171474186548713546686476761306436434146475140156284389181808675016576845833340494848283681088886584219750554408060556769486628029028720727393293111678826356480455433909233520504112074401376133077150471237549474149190242010469539006449596611576612573955754349042329130631128234637924786466585703488460540228477440853493392086251021228087076124706778899179648655221663765993962724699135217212118535057766739392069738618682722216712319320435674779146070442", + }, + { "-0x1BCE04427D8032319A89E5C4136456671AC620883F2C4139E57F91307C485AD2D6204F4F87A58262652DB5DBBAC72B0613E51B835E7153BEC6068F5C8D696B74DBD18FEC316AEF73985CF0475663208EB46B4F17DD9DA55367B03323E5491A70997B90C059FB34809E6EE55BCFBD5F2F52233BFE62E6AA9E4E26A1D4C2439883D14F2633D55D8AA66A1ACD5595E778AC3A280517F1157989E70C1A437B849F1877B779CC3CDDEDE2DAA6594A6C66D181A00A5F777EE60596D8773998F6E988DEAE4CCA60E4DDCF9590543C89F74F603259FCAD71660D30294FBBE6490300F78A9D63FA660DC9417B8B9DDA28BEB3977B621B988E23D4D954F322C3540541BC649ABD504C50FADFD9F0987D58A2BF689313A285E773FF02899A6EF887D1D4A0D2", "0xB08FFB20760FFED58FADA86DFEF71AD72AA0FA763219618FE022C197E54708BB1191C66470250FCE8879487507CEE41381CA4D932F81C2B3F1AB20B539D50DCD", "0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", "21484252197776302499639938883777710321993113097987201050501182909581359357618579566746556372589385361683610524730509041328855066514963385522570894839035884713051640171474186548713546686476761306436434146475140156284389181808675016576845833340494848283681088886584219750554408060556769486628029028720727393293111678826356480455433909233520504112074401376133077150471237549474149190242010469539006449596611576612573955754349042329130631128234637924786466585703488460540228477440853493392086251021228087076124706778899179648655221663765993962724699135217212118535057766739392069738618682722216712319320435674779146070442", }, + + // test cases for issue 13907 + {"0xffffffff00000001", "0xffffffff00000001", "0xffffffff00000001", "0"}, + {"0xffffffffffffffff00000001", "0xffffffffffffffff00000001", "0xffffffffffffffff00000001", "0"}, + {"0xffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffff00000001", "0"}, + {"0xffffffffffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffffffffffff00000001", "0"}, } func TestExp(t *testing.T) { @@ -582,7 +599,7 @@ func TestExp(t *testing.T) { t.Errorf("#%d: %v is not normalized", i, *z1) } if z1.Cmp(out) != 0 { - t.Errorf("#%d: got %s want %s", i, z1, out) + t.Errorf("#%d: got %x want %x", i, z1, out) } if m == nil { @@ -591,7 +608,7 @@ func TestExp(t *testing.T) { m = &Int{abs: nat{}} // m != nil && len(m.abs) == 0 z2 := new(Int).Exp(x, y, m) if z2.Cmp(z1) != 0 { - t.Errorf("#%d: got %s want %s", i, z2, z1) + t.Errorf("#%d: got %x want %x", i, z2, z1) } } } @@ -693,7 +710,9 @@ func TestGcd(t *testing.T) { testGcd(t, d, x, y, a, b) } - quick.Check(checkGcd, nil) + if err := quick.Check(checkGcd, nil); err != nil { + t.Error(err) + } } var primes = []string{ @@ -1180,6 +1199,53 @@ func BenchmarkBitsetNegOrig(b *testing.B) { } } +// tri generates the trinomial 2**(n*2) - 2**n - 1, which is always 3 mod 4 and +// 7 mod 8, so that 2 is always a quadratic residue. +func tri(n uint) *Int { + x := NewInt(1) + x.Lsh(x, n) + x2 := new(Int).Lsh(x, n) + x2.Sub(x2, x) + x2.Sub(x2, intOne) + return x2 +} + +func BenchmarkModSqrt225_Tonelli(b *testing.B) { + p := tri(225) + x := NewInt(2) + for i := 0; i < b.N; i++ { + x.SetUint64(2) + x.modSqrtTonelliShanks(x, p) + } +} + +func BenchmarkModSqrt224_3Mod4(b *testing.B) { + p := tri(225) + x := new(Int).SetUint64(2) + for i := 0; i < b.N; i++ { + x.SetUint64(2) + x.modSqrt3Mod4Prime(x, p) + } +} + +func BenchmarkModSqrt5430_Tonelli(b *testing.B) { + p := tri(5430) + x := new(Int).SetUint64(2) + for i := 0; i < b.N; i++ { + x.SetUint64(2) + x.modSqrtTonelliShanks(x, p) + } +} + +func BenchmarkModSqrt5430_3Mod4(b *testing.B) { + p := tri(5430) + x := new(Int).SetUint64(2) + for i := 0; i < b.N; i++ { + x.SetUint64(2) + x.modSqrt3Mod4Prime(x, p) + } +} + func TestBitwise(t *testing.T) { x := new(Int) y := new(Int) @@ -1318,6 +1384,14 @@ func TestModSqrt(t *testing.T) { t.Errorf("#%d: failed (sqrt(e) = %s)", i, &sqrt) } } + + if testing.Short() && i > 2 { + break + } + } + + if testing.Short() { + return } // exhaustive test for small values @@ -1401,138 +1475,6 @@ func TestJacobiPanic(t *testing.T) { panic(failureMsg) } -var encodingTests = []string{ - "-539345864568634858364538753846587364875430589374589", - "-678645873", - "-100", - "-2", - "-1", - "0", - "1", - "2", - "10", - "42", - "1234567890", - "298472983472983471903246121093472394872319615612417471234712061", -} - -func TestIntGobEncoding(t *testing.T) { - var medium bytes.Buffer - enc := gob.NewEncoder(&medium) - dec := gob.NewDecoder(&medium) - for _, test := range encodingTests { - medium.Reset() // empty buffer for each test case (in case of failures) - var tx Int - tx.SetString(test, 10) - if err := enc.Encode(&tx); err != nil { - t.Errorf("encoding of %s failed: %s", &tx, err) - } - var rx Int - if err := dec.Decode(&rx); err != nil { - t.Errorf("decoding of %s failed: %s", &tx, err) - } - if rx.Cmp(&tx) != 0 { - t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx) - } - } -} - -// Sending a nil Int pointer (inside a slice) on a round trip through gob should yield a zero. -// TODO: top-level nils. -func TestGobEncodingNilIntInSlice(t *testing.T) { - buf := new(bytes.Buffer) - enc := gob.NewEncoder(buf) - dec := gob.NewDecoder(buf) - - var in = make([]*Int, 1) - err := enc.Encode(&in) - if err != nil { - t.Errorf("gob encode failed: %q", err) - } - var out []*Int - err = dec.Decode(&out) - if err != nil { - t.Fatalf("gob decode failed: %q", err) - } - if len(out) != 1 { - t.Fatalf("wrong len; want 1 got %d", len(out)) - } - var zero Int - if out[0].Cmp(&zero) != 0 { - t.Errorf("transmission of (*Int)(nill) failed: got %s want 0", out) - } -} - -func TestIntJSONEncoding(t *testing.T) { - for _, test := range encodingTests { - var tx Int - tx.SetString(test, 10) - b, err := json.Marshal(&tx) - if err != nil { - t.Errorf("marshaling of %s failed: %s", &tx, err) - } - var rx Int - if err := json.Unmarshal(b, &rx); err != nil { - t.Errorf("unmarshaling of %s failed: %s", &tx, err) - } - if rx.Cmp(&tx) != 0 { - t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx) - } - } -} - -var intVals = []string{ - "-141592653589793238462643383279502884197169399375105820974944592307816406286", - "-1415926535897932384626433832795028841971", - "-141592653589793", - "-1", - "0", - "1", - "141592653589793", - "1415926535897932384626433832795028841971", - "141592653589793238462643383279502884197169399375105820974944592307816406286", -} - -func TestIntJSONEncodingTextMarshaller(t *testing.T) { - for _, num := range intVals { - var tx Int - tx.SetString(num, 0) - b, err := json.Marshal(&tx) - if err != nil { - t.Errorf("marshaling of %s failed: %s", &tx, err) - continue - } - var rx Int - if err := json.Unmarshal(b, &rx); err != nil { - t.Errorf("unmarshaling of %s failed: %s", &tx, err) - continue - } - if rx.Cmp(&tx) != 0 { - t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx) - } - } -} - -func TestIntXMLEncodingTextMarshaller(t *testing.T) { - for _, num := range intVals { - var tx Int - tx.SetString(num, 0) - b, err := xml.Marshal(&tx) - if err != nil { - t.Errorf("marshaling of %s failed: %s", &tx, err) - continue - } - var rx Int - if err := xml.Unmarshal(b, &rx); err != nil { - t.Errorf("unmarshaling of %s failed: %s", &tx, err) - continue - } - if rx.Cmp(&tx) != 0 { - t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx) - } - } -} - func TestIssue2607(t *testing.T) { // This code sequence used to hang. n := NewInt(10) diff --git a/libgo/go/math/big/intconv.go b/libgo/go/math/big/intconv.go index 9c68a22..56a75f8 100644 --- a/libgo/go/math/big/intconv.go +++ b/libgo/go/math/big/intconv.go @@ -12,30 +12,34 @@ import ( "io" ) -func (x *Int) String() string { - switch { - case x == nil: +// TODO(gri) Should rename itoa to utoa (there's no sign). That +// would permit the introduction of itoa which is like utoa but +// reserves a byte for a possible sign that's passed in. That +// would permit Int.Text to be implemented w/o the need for +// string copy if the number is negative. + +// Text returns the string representation of x in the given base. +// Base must be between 2 and 36, inclusive. The result uses the +// lower-case letters 'a' to 'z' for digit values >= 10. No base +// prefix (such as "0x") is added to the string. +func (x *Int) Text(base int) string { + if x == nil { return "<nil>" - case x.neg: - return "-" + x.abs.decimalString() } - return x.abs.decimalString() + return string(x.abs.itoa(x.neg, base)) } -func charset(ch rune) string { - switch ch { - case 'b': - return lowercaseDigits[0:2] - case 'o': - return lowercaseDigits[0:8] - case 'd', 's', 'v': - return lowercaseDigits[0:10] - case 'x': - return lowercaseDigits[0:16] - case 'X': - return uppercaseDigits[0:16] +// Append appends the string representation of x, as generated by +// x.Text(base), to buf and returns the extended buffer. +func (x *Int) Append(buf []byte, base int) []byte { + if x == nil { + return append(buf, "<nil>"...) } - return "" // unknown format + return append(buf, x.abs.itoa(x.neg, base)...) +} + +func (x *Int) String() string { + return x.Text(10) } // write count copies of text to s @@ -60,15 +64,24 @@ func writeMultiple(s fmt.State, text string, count int) { // right justification. // func (x *Int) Format(s fmt.State, ch rune) { - cs := charset(ch) - - // special cases - switch { - case cs == "": + // determine base + var base int + switch ch { + case 'b': + base = 2 + case 'o': + base = 8 + case 'd', 's', 'v': + base = 10 + case 'x', 'X': + base = 16 + default: // unknown format fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String()) return - case x == nil: + } + + if x == nil { fmt.Fprint(s, "<nil>") return } @@ -97,35 +110,42 @@ func (x *Int) Format(s fmt.State, ch rune) { } } - // determine digits with base set by len(cs) and digit characters from cs - digits := x.abs.string(cs) + digits := x.abs.utoa(base) + if ch == 'X' { + // faster than bytes.ToUpper + for i, d := range digits { + if 'a' <= d && d <= 'z' { + digits[i] = 'A' + (d - 'a') + } + } + } // number of characters for the three classes of number padding - var left int // space characters to left of digits for right justification ("%8d") - var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d") - var right int // space characters to right of digits for left justification ("%-8d") + var left int // space characters to left of digits for right justification ("%8d") + var zeros int // zero characters (actually cs[0]) as left-most digits ("%.8d") + var right int // space characters to right of digits for left justification ("%-8d") // determine number padding from precision: the least number of digits to output precision, precisionSet := s.Precision() if precisionSet { switch { case len(digits) < precision: - zeroes = precision - len(digits) // count of zero padding - case digits == "0" && precision == 0: + zeros = precision - len(digits) // count of zero padding + case len(digits) == 1 && digits[0] == '0' && precision == 0: return // print nothing if zero value (x == 0) and zero precision ("." or ".0") } } // determine field pad from width: the least number of characters to output - length := len(sign) + len(prefix) + zeroes + len(digits) + length := len(sign) + len(prefix) + zeros + len(digits) if width, widthSet := s.Width(); widthSet && length < width { // pad as specified switch d := width - length; { case s.Flag('-'): // pad on the right with spaces; supersedes '0' when both specified right = d case s.Flag('0') && !precisionSet: - // pad with zeroes unless precision also specified - zeroes = d + // pad with zeros unless precision also specified + zeros = d default: // pad on the left with spaces left = d @@ -136,8 +156,8 @@ func (x *Int) Format(s fmt.State, ch rune) { writeMultiple(s, " ", left) writeMultiple(s, sign, 1) writeMultiple(s, prefix, 1) - writeMultiple(s, "0", zeroes) - writeMultiple(s, digits, 1) + writeMultiple(s, "0", zeros) + s.Write(digits) writeMultiple(s, " ", right) } diff --git a/libgo/go/math/big/intconv_test.go b/libgo/go/math/big/intconv_test.go index 2deb84b..5142081 100644 --- a/libgo/go/math/big/intconv_test.go +++ b/libgo/go/math/big/intconv_test.go @@ -17,19 +17,19 @@ var stringTests = []struct { val int64 ok bool }{ - {in: "", ok: false}, - {in: "a", ok: false}, - {in: "z", ok: false}, - {in: "+", ok: false}, - {in: "-", ok: false}, - {in: "0b", ok: false}, - {in: "0x", ok: false}, - {in: "2", base: 2, ok: false}, - {in: "0b2", base: 0, ok: false}, - {in: "08", ok: false}, - {in: "8", base: 8, ok: false}, - {in: "0xg", base: 0, ok: false}, - {in: "g", base: 16, ok: false}, + {in: ""}, + {in: "a"}, + {in: "z"}, + {in: "+"}, + {in: "-"}, + {in: "0b"}, + {in: "0x"}, + {in: "2", base: 2}, + {in: "0b2", base: 0}, + {in: "08"}, + {in: "8", base: 8}, + {in: "0xg", base: 0}, + {in: "g", base: 16}, {"0", "0", 0, 0, true}, {"0", "0", 10, 0, true}, {"0", "0", 16, 0, true}, @@ -41,7 +41,7 @@ var stringTests = []struct { {"-10", "-10", 16, -16, true}, {"+10", "10", 16, 16, true}, {"0x10", "16", 0, 16, true}, - {in: "0x10", base: 16, ok: false}, + {in: "0x10", base: 16}, {"-0x10", "-16", 0, -16, true}, {"+0x10", "16", 0, 16, true}, {"00", "0", 0, 0, true}, @@ -58,6 +58,57 @@ var stringTests = []struct { {"1001010111", "1001010111", 2, 0x257, true}, } +func TestIntText(t *testing.T) { + z := new(Int) + for _, test := range stringTests { + if !test.ok { + continue + } + + _, ok := z.SetString(test.in, test.base) + if !ok { + t.Errorf("%v: failed to parse", test) + continue + } + + base := test.base + if base == 0 { + base = 10 + } + + if got := z.Text(base); got != test.out { + t.Errorf("%v: got %s; want %s", test, got, test.out) + } + } +} + +func TestAppendText(t *testing.T) { + z := new(Int) + var buf []byte + for _, test := range stringTests { + if !test.ok { + continue + } + + _, ok := z.SetString(test.in, test.base) + if !ok { + t.Errorf("%v: failed to parse", test) + continue + } + + base := test.base + if base == 0 { + base = 10 + } + + i := len(buf) + buf = z.Append(buf, base) + if got := string(buf[i:]); got != test.out { + t.Errorf("%v: got %s; want %s", test, got, test.out) + } + } +} + func format(base int) string { switch base { case 2: @@ -79,15 +130,13 @@ func TestGetString(t *testing.T) { z.SetInt64(test.val) if test.base == 10 { - s := z.String() - if s != test.out { - t.Errorf("#%da got %s; want %s", i, s, test.out) + if got := z.String(); got != test.out { + t.Errorf("#%da got %s; want %s", i, got, test.out) } } - s := fmt.Sprintf(format(test.base), z) - if s != test.out { - t.Errorf("#%db got %s; want %s", i, s, test.out) + if got := fmt.Sprintf(format(test.base), z); got != test.out { + t.Errorf("#%db got %s; want %s", i, got, test.out) } } } diff --git a/libgo/go/math/big/intmarsh.go b/libgo/go/math/big/intmarsh.go new file mode 100644 index 0000000..4ff57b6 --- /dev/null +++ b/libgo/go/math/big/intmarsh.go @@ -0,0 +1,74 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements encoding/decoding of Ints. + +package big + +import "fmt" + +// Gob codec version. Permits backward-compatible changes to the encoding. +const intGobVersion byte = 1 + +// GobEncode implements the gob.GobEncoder interface. +func (x *Int) GobEncode() ([]byte, error) { + if x == nil { + return nil, nil + } + buf := make([]byte, 1+len(x.abs)*_S) // extra byte for version and sign bit + i := x.abs.bytes(buf) - 1 // i >= 0 + b := intGobVersion << 1 // make space for sign bit + if x.neg { + b |= 1 + } + buf[i] = b + return buf[i:], nil +} + +// GobDecode implements the gob.GobDecoder interface. +func (z *Int) GobDecode(buf []byte) error { + if len(buf) == 0 { + // Other side sent a nil or default value. + *z = Int{} + return nil + } + b := buf[0] + if b>>1 != intGobVersion { + return fmt.Errorf("Int.GobDecode: encoding version %d not supported", b>>1) + } + z.neg = b&1 != 0 + z.abs = z.abs.setBytes(buf[1:]) + return nil +} + +// MarshalText implements the encoding.TextMarshaler interface. +func (x *Int) MarshalText() (text []byte, err error) { + if x == nil { + return []byte("<nil>"), nil + } + return x.abs.itoa(x.neg, 10), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +func (z *Int) UnmarshalText(text []byte) error { + // TODO(gri): get rid of the []byte/string conversion + if _, ok := z.SetString(string(text), 0); !ok { + return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text) + } + return nil +} + +// The JSON marshallers are only here for API backward compatibility +// (programs that explicitly look for these two methods). JSON works +// fine with the TextMarshaler only. + +// MarshalJSON implements the json.Marshaler interface. +func (x *Int) MarshalJSON() ([]byte, error) { + return x.MarshalText() +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (z *Int) UnmarshalJSON(text []byte) error { + return z.UnmarshalText(text) +} diff --git a/libgo/go/math/big/intmarsh_test.go b/libgo/go/math/big/intmarsh_test.go new file mode 100644 index 0000000..f82956c --- /dev/null +++ b/libgo/go/math/big/intmarsh_test.go @@ -0,0 +1,121 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package big + +import ( + "bytes" + "encoding/gob" + "encoding/json" + "encoding/xml" + "testing" +) + +var encodingTests = []string{ + "0", + "1", + "2", + "10", + "1000", + "1234567890", + "298472983472983471903246121093472394872319615612417471234712061", +} + +func TestIntGobEncoding(t *testing.T) { + var medium bytes.Buffer + enc := gob.NewEncoder(&medium) + dec := gob.NewDecoder(&medium) + for _, test := range encodingTests { + for _, sign := range []string{"", "+", "-"} { + x := sign + test + medium.Reset() // empty buffer for each test case (in case of failures) + var tx Int + tx.SetString(x, 10) + if err := enc.Encode(&tx); err != nil { + t.Errorf("encoding of %s failed: %s", &tx, err) + continue + } + var rx Int + if err := dec.Decode(&rx); err != nil { + t.Errorf("decoding of %s failed: %s", &tx, err) + continue + } + if rx.Cmp(&tx) != 0 { + t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx) + } + } + } +} + +// Sending a nil Int pointer (inside a slice) on a round trip through gob should yield a zero. +// TODO: top-level nils. +func TestGobEncodingNilIntInSlice(t *testing.T) { + buf := new(bytes.Buffer) + enc := gob.NewEncoder(buf) + dec := gob.NewDecoder(buf) + + var in = make([]*Int, 1) + err := enc.Encode(&in) + if err != nil { + t.Errorf("gob encode failed: %q", err) + } + var out []*Int + err = dec.Decode(&out) + if err != nil { + t.Fatalf("gob decode failed: %q", err) + } + if len(out) != 1 { + t.Fatalf("wrong len; want 1 got %d", len(out)) + } + var zero Int + if out[0].Cmp(&zero) != 0 { + t.Fatalf("transmission of (*Int)(nil) failed: got %s want 0", out) + } +} + +func TestIntJSONEncoding(t *testing.T) { + for _, test := range encodingTests { + for _, sign := range []string{"", "+", "-"} { + x := sign + test + var tx Int + tx.SetString(x, 10) + b, err := json.Marshal(&tx) + if err != nil { + t.Errorf("marshaling of %s failed: %s", &tx, err) + continue + } + var rx Int + if err := json.Unmarshal(b, &rx); err != nil { + t.Errorf("unmarshaling of %s failed: %s", &tx, err) + continue + } + if rx.Cmp(&tx) != 0 { + t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx) + } + } + } +} + +func TestIntXMLEncoding(t *testing.T) { + for _, test := range encodingTests { + for _, sign := range []string{"", "+", "-"} { + x := sign + test + var tx Int + tx.SetString(x, 0) + b, err := xml.Marshal(&tx) + if err != nil { + t.Errorf("marshaling of %s failed: %s", &tx, err) + continue + } + var rx Int + if err := xml.Unmarshal(b, &rx); err != nil { + t.Errorf("unmarshaling of %s failed: %s", &tx, err) + continue + } + if rx.Cmp(&tx) != 0 { + t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx) + } + } + } +} diff --git a/libgo/go/math/big/nat.go b/libgo/go/math/big/nat.go index 6545bc1..79cf6e07 100644 --- a/libgo/go/math/big/nat.go +++ b/libgo/go/math/big/nat.go @@ -2,31 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package big implements multi-precision arithmetic (big numbers). -// The following numeric types are supported: -// -// Int signed integers -// Rat rational numbers -// Float floating-point numbers -// -// Methods are typically of the form: -// -// func (z *T) Unary(x *T) *T // z = op x -// func (z *T) Binary(x, y *T) *T // z = x op y -// func (x *T) M() T1 // v = x.M() -// -// with T one of Int, Rat, or Float. For unary and binary operations, the -// result is the receiver (usually named z in that case); if it is one of -// the operands x or y it may be overwritten (and its memory reused). -// To enable chaining of operations, the result is also returned. Methods -// returning a result other than *Int, *Rat, or *Float take an operand as -// the receiver (usually named x in that case). -// -package big +// This file implements unsigned multi-precision integers (natural +// numbers). They are the building blocks for the implementation +// of signed integers, rationals, and floating-point numbers. -// This file contains operations on unsigned multi-precision integers. -// These are the building blocks for the operations on signed integers -// and rationals. +package big import "math/rand" @@ -216,29 +196,42 @@ func basicMul(z, x, y nat) { } } -// montgomery computes x*y*2^(-n*_W) mod m, -// assuming k = -1/m mod 2^_W. +// montgomery computes z mod m = x*y*2**(-n*_W) mod m, +// assuming k = -1/m mod 2**_W. // z is used for storing the result which is returned; // z must not alias x, y or m. +// See Gueron, "Efficient Software Implementations of Modular Exponentiation". +// https://eprint.iacr.org/2011/239.pdf +// In the terminology of that paper, this is an "Almost Montgomery Multiplication": +// x and y are required to satisfy 0 <= z < 2**(n*_W) and then the result +// z is guaranteed to satisfy 0 <= z < 2**(n*_W), but it may not be < m. func (z nat) montgomery(x, y, m nat, k Word, n int) nat { - var c1, c2 Word + // This code assumes x, y, m are all the same length, n. + // (required by addMulVVW and the for loop). + // It also assumes that x, y are already reduced mod m, + // or else the result will not be properly reduced. + if len(x) != n || len(y) != n || len(m) != n { + panic("math/big: mismatched montgomery number lengths") + } z = z.make(n) z.clear() + var c Word for i := 0; i < n; i++ { d := y[i] - c1 += addMulVVW(z, x, d) + c2 := addMulVVW(z, x, d) t := z[0] * k - c2 = addMulVVW(z, m, t) - + c3 := addMulVVW(z, m, t) copy(z, z[1:]) - z[n-1] = c1 + c2 - if z[n-1] < c1 { - c1 = 1 + cx := c + c2 + cy := cx + c3 + z[n-1] = cy + if cx < c2 || cy < c3 { + c = 1 } else { - c1 = 0 + c = 0 } } - if c1 != 0 { + if c != 0 { subVV(z, z, m) } return z @@ -1063,26 +1056,22 @@ func (z nat) expNNWindowed(x, y, m nat) nat { // expNNMontgomery calculates x**y mod m using a fixed, 4-bit window. // Uses Montgomery representation. func (z nat) expNNMontgomery(x, y, m nat) nat { - var zz, one, rr, RR nat - numWords := len(m) // We want the lengths of x and m to be equal. + // It is OK if x >= m as long as len(x) == len(m). if len(x) > numWords { - _, rr = rr.div(rr, x, m) - } else if len(x) < numWords { - rr = rr.make(numWords) - rr.clear() - for i := range x { - rr[i] = x[i] - } - } else { - rr = x + _, x = nat(nil).div(nil, x, m) + // Note: now len(x) <= numWords, not guaranteed ==. + } + if len(x) < numWords { + rr := make(nat, numWords) + copy(rr, x) + x = rr } - x = rr // Ideally the precomputations would be performed outside, and reused - // k0 = -mˆ-1 mod 2ˆ_W. Algorithm from: Dumas, J.G. "On Newton–Raphson + // k0 = -m**-1 mod 2**_W. Algorithm from: Dumas, J.G. "On Newton–Raphson // Iteration for Multiplicative Inverses Modulo Prime Powers". k0 := 2 - m[0] t := m[0] - 1 @@ -1092,9 +1081,9 @@ func (z nat) expNNMontgomery(x, y, m nat) nat { } k0 = -k0 - // RR = 2ˆ(2*_W*len(m)) mod m - RR = RR.setWord(1) - zz = zz.shl(RR, uint(2*numWords*_W)) + // RR = 2**(2*_W*len(m)) mod m + RR := nat(nil).setWord(1) + zz := nat(nil).shl(RR, uint(2*numWords*_W)) _, RR = RR.div(RR, zz, m) if len(RR) < numWords { zz = zz.make(numWords) @@ -1102,8 +1091,7 @@ func (z nat) expNNMontgomery(x, y, m nat) nat { RR = zz } // one = 1, with equal length to that of m - one = one.make(numWords) - one.clear() + one := make(nat, numWords) one[0] = 1 const n = 4 @@ -1138,12 +1126,32 @@ func (z nat) expNNMontgomery(x, y, m nat) nat { } // convert to regular number zz = zz.montgomery(z, one, m, k0, numWords) + + // One last reduction, just in case. + // See golang.org/issue/13907. + if zz.cmp(m) >= 0 { + // Common case is m has high bit set; in that case, + // since zz is the same length as m, there can be just + // one multiple of m to remove. Just subtract. + // We think that the subtract should be sufficient in general, + // so do that unconditionally, but double-check, + // in case our beliefs are wrong. + // The div is not expected to be reached. + zz = zz.sub(zz, m) + if zz.cmp(m) >= 0 { + _, zz = nat(nil).div(nil, zz, m) + } + } + return zz.norm() } -// probablyPrime performs reps Miller-Rabin tests to check whether n is prime. -// If it returns true, n is prime with probability 1 - 1/4^reps. -// If it returns false, n is not prime. +// probablyPrime performs n Miller-Rabin tests to check whether x is prime. +// If x is prime, it returns true. +// If x is not prime, it returns false with probability at least 1 - ¼ⁿ. +// +// It is not suitable for judging primes that an adversary may have crafted +// to fool this test. func (n nat) probablyPrime(reps int) bool { if len(n) == 0 { return false diff --git a/libgo/go/math/big/nat_test.go b/libgo/go/math/big/nat_test.go index 7ac3cb8..563ccb3 100644 --- a/libgo/go/math/big/nat_test.go +++ b/libgo/go/math/big/nat_test.go @@ -158,7 +158,7 @@ var mulRangesN = []struct { func TestMulRangeN(t *testing.T) { for i, r := range mulRangesN { - prod := nat(nil).mulRange(r.a, r.b).decimalString() + prod := string(nat(nil).mulRange(r.a, r.b).utoa(10)) if prod != r.prod { t.Errorf("#%d: got %s; want %s", i, prod, r.prod) } @@ -326,7 +326,7 @@ func TestTrailingZeroBits(t *testing.T) { for i := uint(0); i <= 3*_W; i++ { n := y.trailingZeroBits() if n != i { - t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.hexString(), n, i) + t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.utoa(16), n, i) } y = y.shl(y, 1) } @@ -341,25 +341,57 @@ var montgomeryTests = []struct { "0xffffffffffffffffffffffffffffffffffffffffffffffffe", "0xffffffffffffffffffffffffffffffffffffffffffffffffe", "0xfffffffffffffffffffffffffffffffffffffffffffffffff", - 0x0000000000000000, - "0xffffffffffffffffffffffffffffffffffffffffff", - "0xffffffffffffffffffffffffffffffffff", + 1, + "0x1000000000000000000000000000000000000000000", + "0x10000000000000000000000000000000000", }, { - "0x0000000080000000", - "0x00000000ffffffff", + "0x000000000ffffff5", + "0x000000000ffffff0", "0x0000000010000001", 0xff0000000fffffff, - "0x0000000088000000", - "0x0000000007800001", + "0x000000000bfffff4", + "0x0000000003400001", + }, + { + "0x0000000080000000", + "0x00000000ffffffff", + "0x1000000000000001", + 0xfffffffffffffff, + "0x0800000008000001", + "0x0800000008000001", + }, + { + "0x0000000080000000", + "0x0000000080000000", + "0xffffffff00000001", + 0xfffffffeffffffff, + "0xbfffffff40000001", + "0xbfffffff40000001", + }, + { + "0x0000000080000000", + "0x0000000080000000", + "0x00ffffff00000001", + 0xfffffeffffffff, + "0xbfffff40000001", + "0xbfffff40000001", + }, + { + "0x0000000080000000", + "0x0000000080000000", + "0x0000ffff00000001", + 0xfffeffffffff, + "0xbfff40000001", + "0xbfff40000001", }, { - "0xffffffffffffffffffffffffffffffff00000000000022222223333333333444444444", - "0xffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc", + "0x3321ffffffffffffffffffffffffffff00000000000022222623333333332bbbb888c0", + "0x3321ffffffffffffffffffffffffffff00000000000022222623333333332bbbb888c0", "0x33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1", 0xdecc8f1249812adf, - "0x22bb05b6d95eaaeca2bb7c05e51f807bce9064b5fbad177161695e4558f9474e91cd79", - "0x14beb58d230f85b6d95eaaeca2bb7c05e51f807bce9064b5fb45669afa695f228e48cd", + "0x04eb0e11d72329dc0915f86784820fc403275bf2f6620a20e0dd344c5cd0875e50deb5", + "0x0d7144739a7d8e11d72329dc0915f86784820fc403275bf2f61ed96f35dd34dbb3d6a0", }, { "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000022222223333333333444444444", @@ -372,10 +404,27 @@ var montgomeryTests = []struct { } func TestMontgomery(t *testing.T) { + one := NewInt(1) + _B := new(Int).Lsh(one, _W) for i, test := range montgomeryTests { x := natFromString(test.x) y := natFromString(test.y) m := natFromString(test.m) + for len(x) < len(m) { + x = append(x, 0) + } + for len(y) < len(m) { + y = append(y, 0) + } + + if x.cmp(m) > 0 { + _, r := nat(nil).div(nil, x, m) + t.Errorf("#%d: x > m (0x%s > 0x%s; use 0x%s)", i, x.utoa(16), m.utoa(16), r.utoa(16)) + } + if y.cmp(m) > 0 { + _, r := nat(nil).div(nil, x, m) + t.Errorf("#%d: y > m (0x%s > 0x%s; use 0x%s)", i, y.utoa(16), m.utoa(16), r.utoa(16)) + } var out nat if _W == 32 { @@ -384,11 +433,31 @@ func TestMontgomery(t *testing.T) { out = natFromString(test.out64) } - k0 := Word(test.k0 & _M) // mask k0 to ensure that it fits for 32-bit systems. + // t.Logf("#%d: len=%d\n", i, len(m)) + + // check output in table + xi := &Int{abs: x} + yi := &Int{abs: y} + mi := &Int{abs: m} + p := new(Int).Mod(new(Int).Mul(xi, new(Int).Mul(yi, new(Int).ModInverse(new(Int).Lsh(one, uint(len(m))*_W), mi))), mi) + if out.cmp(p.abs.norm()) != 0 { + t.Errorf("#%d: out in table=0x%s, computed=0x%s", i, out.utoa(16), p.abs.norm().utoa(16)) + } + + // check k0 in table + k := new(Int).Mod(&Int{abs: m}, _B) + k = new(Int).Sub(_B, k) + k = new(Int).Mod(k, _B) + k0 := Word(new(Int).ModInverse(k, _B).Uint64()) + if k0 != Word(test.k0) { + t.Errorf("#%d: k0 in table=%#x, computed=%#x\n", i, test.k0, k0) + } + + // check montgomery with correct k0 produces correct output z := nat(nil).montgomery(x, y, m, k0, len(m)) z = z.norm() if z.cmp(out) != 0 { - t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString()) + t.Errorf("#%d: got 0x%s want 0x%s", i, z.utoa(16), out.utoa(16)) } } } @@ -414,6 +483,12 @@ var expNNTests = []struct { "29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464", "23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291", }, + { + "11521922904531591643048817447554701904414021819823889996244743037378330903763518501116638828335352811871131385129455853417360623007349090150042001944696604737499160174391019030572483602867266711107136838523916077674888297896995042968746762200926853379", + "426343618817810911523", + "444747819283133684179", + "42", + }, } func TestExpNN(t *testing.T) { @@ -429,7 +504,7 @@ func TestExpNN(t *testing.T) { z := nat(nil).expNN(x, y, m) if z.cmp(out) != 0 { - t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString()) + t.Errorf("#%d got %s want %s", i, z.utoa(10), out.utoa(10)) } } } @@ -486,7 +561,7 @@ var fiboNums = []string{ func TestFibo(t *testing.T) { for i, want := range fiboNums { n := i * 10 - got := fibo(n).decimalString() + got := string(fibo(n).utoa(10)) if got != want { t.Errorf("fibo(%d) failed: got %s want %s", n, got, want) } diff --git a/libgo/go/math/big/natconv.go b/libgo/go/math/big/natconv.go index 022dcfe..d2ce667 100644 --- a/libgo/go/math/big/natconv.go +++ b/libgo/go/math/big/natconv.go @@ -14,6 +14,11 @@ import ( "sync" ) +const digits = "0123456789abcdefghijklmnopqrstuvwxyz" + +// Note: MaxBase = len(digits), but it must remain a rune constant +// for API compatibility. + // MaxBase is the largest number base accepted for string conversions. const MaxBase = 'z' - 'a' + 10 + 1 @@ -229,56 +234,45 @@ func (z nat) scan(r io.ByteScanner, base int, fracOk bool) (res nat, b, count in return } -// Character sets for string conversion. -const ( - lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz" - uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" -) - -// decimalString returns a decimal representation of x. -// It calls x.string with the charset "0123456789". -func (x nat) decimalString() string { - return x.string(lowercaseDigits[:10]) +// utoa converts x to an ASCII representation in the given base; +// base must be between 2 and MaxBase, inclusive. +func (x nat) utoa(base int) []byte { + return x.itoa(false, base) } -// hexString returns a hexadecimal representation of x. -// It calls x.string with the charset "0123456789abcdef". -func (x nat) hexString() string { - return x.string(lowercaseDigits[:16]) -} +// itoa is like utoa but it prepends a '-' if neg && x != 0. +func (x nat) itoa(neg bool, base int) []byte { + if base < 2 || base > MaxBase { + panic("invalid base") + } -// string converts x to a string using digits from a charset; a digit with -// value d is represented by charset[d]. The conversion base is determined -// by len(charset), which must be >= 2 and <= 256. -func (x nat) string(charset string) string { - b := Word(len(charset)) - - // special cases - switch { - case b < 2 || b > 256: - panic("invalid character set length") - case len(x) == 0: - return string(charset[0]) + // x == 0 + if len(x) == 0 { + return []byte("0") } + // len(x) > 0 // allocate buffer for conversion - i := int(float64(x.bitLen())/math.Log2(float64(b))) + 1 // off by one at most + i := int(float64(x.bitLen())/math.Log2(float64(base))) + 1 // off by 1 at most + if neg { + i++ + } s := make([]byte, i) // convert power of two and non power of two bases separately - if b == b&-b { - // shift is base-b digit size in bits + if b := Word(base); b == b&-b { + // shift is base b digit size in bits shift := trailingZeroBits(b) // shift > 0 because b >= 2 - mask := Word(1)<<shift - 1 - w := x[0] + mask := Word(1<<shift - 1) + w := x[0] // current word nbits := uint(_W) // number of unprocessed bits in w - // convert less-significant words + // convert less-significant words (include leading zeros) for k := 1; k < len(x); k++ { // convert full digits for nbits >= shift { i-- - s[i] = charset[w&mask] + s[i] = digits[w&mask] w >>= shift nbits -= shift } @@ -289,10 +283,10 @@ func (x nat) string(charset string) string { w = x[k] nbits = _W } else { - // partial digit in current (k-1) and next (k) word + // partial digit in current word w (== x[k-1]) and next word x[k] w |= x[k] << nbits i-- - s[i] = charset[w&mask] + s[i] = digits[w&mask] // advance w = x[k] >> (shift - nbits) @@ -300,12 +294,11 @@ func (x nat) string(charset string) string { } } - // convert digits of most-significant word (omit leading zeros) - for nbits >= 0 && w != 0 { + // convert digits of most-significant word w (omit leading zeros) + for w != 0 { i-- - s[i] = charset[w&mask] + s[i] = digits[w&mask] w >>= shift - nbits -= shift } } else { @@ -319,18 +312,23 @@ func (x nat) string(charset string) string { q := nat(nil).set(x) // convert q to string s in base b - q.convertWords(s, charset, b, ndigits, bb, table) + q.convertWords(s, b, ndigits, bb, table) // strip leading zeros // (x != 0; thus s must contain at least one non-zero digit // and the loop will terminate) i = 0 - for zero := charset[0]; s[i] == zero; { + for s[i] == '0' { i++ } } - return string(s[i:]) + if neg { + i-- + s[i] = '-' + } + + return s[i:] } // Convert words of q to base b digits in s. If q is large, it is recursively "split in half" @@ -349,7 +347,7 @@ func (x nat) string(charset string) string { // ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for // specific hardware. // -func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) { +func (q nat) convertWords(s []byte, b Word, ndigits int, bb Word, table []divisor) { // split larger blocks recursively if table != nil { // len(q) > leafSize > 0 @@ -374,8 +372,8 @@ func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word // convert subblocks and collect results in s[:h] and s[h:] h := len(s) - table[index].ndigits - r.convertWords(s[h:], charset, b, ndigits, bb, table[0:index]) - s = s[:h] // == q.convertWords(s, charset, b, ndigits, bb, table[0:index+1]) + r.convertWords(s[h:], b, ndigits, bb, table[0:index]) + s = s[:h] // == q.convertWords(s, b, ndigits, bb, table[0:index+1]) } } @@ -393,7 +391,7 @@ func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word // this appears to be faster for BenchmarkString10000Base10 // and smaller strings (but a bit slower for larger ones) t := r / 10 - s[i] = charset[r-t<<3-t-t] // TODO(gri) replace w/ t*10 once compiler produces better code + s[i] = '0' + byte(r-t<<3-t-t) // TODO(gri) replace w/ t*10 once compiler produces better code r = t } } @@ -403,17 +401,16 @@ func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word q, r = q.divW(q, bb) for j := 0; j < ndigits && i > 0; j++ { i-- - s[i] = charset[r%b] + s[i] = digits[r%b] r /= b } } } - // prepend high-order zeroes - zero := charset[0] - for i > 0 { // while need more leading zeroes + // prepend high-order zeros + for i > 0 { // while need more leading zeros i-- - s[i] = zero + s[i] = '0' } } @@ -425,7 +422,7 @@ var leafSize int = 8 // number of Word-size binary values treat as a monolithic type divisor struct { bbb nat // divisor - nbits int // bit length of divisor (discounting leading zeroes) ~= log2(bbb) + nbits int // bit length of divisor (discounting leading zeros) ~= log2(bbb) ndigits int // digit length of divisor in terms of output base digits } diff --git a/libgo/go/math/big/natconv_test.go b/libgo/go/math/big/natconv_test.go index f321fbc..028e5a8 100644 --- a/libgo/go/math/big/natconv_test.go +++ b/libgo/go/math/big/natconv_test.go @@ -5,20 +5,19 @@ package big import ( + "bytes" "io" "strings" "testing" ) -func toString(x nat, charset string) string { - base := len(charset) - +func itoa(x nat, base int) []byte { // special cases switch { case base < 2: panic("illegal base") case len(x) == 0: - return string(charset[0]) + return []byte("0") } // allocate buffer for conversion @@ -33,54 +32,53 @@ func toString(x nat, charset string) string { i-- var r Word q, r = q.divW(q, Word(base)) - s[i] = charset[r] + s[i] = digits[r] } - return string(s[i:]) + return s[i:] } var strTests = []struct { x nat // nat value to be converted - c string // conversion charset + b int // conversion base s string // expected result }{ - {nil, "01", "0"}, - {nat{1}, "01", "1"}, - {nat{0xc5}, "01", "11000101"}, - {nat{03271}, lowercaseDigits[:8], "3271"}, - {nat{10}, lowercaseDigits[:10], "10"}, - {nat{1234567890}, uppercaseDigits[:10], "1234567890"}, - {nat{0xdeadbeef}, lowercaseDigits[:16], "deadbeef"}, - {nat{0xdeadbeef}, uppercaseDigits[:16], "DEADBEEF"}, - {nat{0x229be7}, lowercaseDigits[:17], "1a2b3c"}, - {nat{0x309663e6}, uppercaseDigits[:32], "O9COV6"}, + {nil, 2, "0"}, + {nat{1}, 2, "1"}, + {nat{0xc5}, 2, "11000101"}, + {nat{03271}, 8, "3271"}, + {nat{10}, 10, "10"}, + {nat{1234567890}, 10, "1234567890"}, + {nat{0xdeadbeef}, 16, "deadbeef"}, + {nat{0x229be7}, 17, "1a2b3c"}, + {nat{0x309663e6}, 32, "o9cov6"}, } func TestString(t *testing.T) { - // test invalid character set explicitly + // test invalid base explicitly var panicStr string func() { defer func() { panicStr = recover().(string) }() - natOne.string("0") + natOne.utoa(1) }() - if panicStr != "invalid character set length" { - t.Errorf("expected panic for invalid character set") + if panicStr != "invalid base" { + t.Errorf("expected panic for invalid base") } for _, a := range strTests { - s := a.x.string(a.c) + s := string(a.x.utoa(a.b)) if s != a.s { t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s) } - x, b, _, err := nat(nil).scan(strings.NewReader(a.s), len(a.c), false) + x, b, _, err := nat(nil).scan(strings.NewReader(a.s), a.b, false) if x.cmp(a.x) != 0 { t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x) } - if b != len(a.c) { - t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, len(a.c)) + if b != a.b { + t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.b) } if err != nil { t.Errorf("scan%+v\n\tgot error = %s", a, err) @@ -236,7 +234,7 @@ func TestScanPi(t *testing.T) { if err != nil { t.Errorf("scanning pi: %s", err) } - if s := z.decimalString(); s != pi { + if s := string(z.utoa(10)); s != pi { t.Errorf("scanning pi: got %s", s) } } @@ -265,12 +263,12 @@ func BenchmarkScanPi(b *testing.B) { func BenchmarkStringPiParallel(b *testing.B) { var x nat x, _, _, _ = x.scan(strings.NewReader(pi), 0, false) - if x.decimalString() != pi { + if string(x.utoa(10)) != pi { panic("benchmark incorrect: conversion failed") } b.RunParallel(func(pb *testing.PB) { for pb.Next() { - x.decimalString() + x.utoa(10) } }) } @@ -304,15 +302,14 @@ func ScanHelper(b *testing.B, base int, x, y Word) { var z nat z = z.expWW(x, y) - var s string - s = z.string(lowercaseDigits[:base]) - if t := toString(z, lowercaseDigits[:base]); t != s { + s := z.utoa(base) + if t := itoa(z, base); !bytes.Equal(s, t) { b.Fatalf("scanning: got %s; want %s", s, t) } b.StartTimer() for i := 0; i < b.N; i++ { - z.scan(strings.NewReader(s), base, false) + z.scan(bytes.NewReader(s), base, false) } } @@ -344,11 +341,11 @@ func StringHelper(b *testing.B, base int, x, y Word) { b.StopTimer() var z nat z = z.expWW(x, y) - z.string(lowercaseDigits[:base]) // warm divisor cache + z.utoa(base) // warm divisor cache b.StartTimer() for i := 0; i < b.N; i++ { - _ = z.string(lowercaseDigits[:base]) + _ = z.utoa(base) } } @@ -372,7 +369,7 @@ func BenchmarkLeafSize16(b *testing.B) { LeafSizeHelper(b, 10, 16) } func BenchmarkLeafSize32(b *testing.B) { LeafSizeHelper(b, 10, 32) } // try some large lengths func BenchmarkLeafSize64(b *testing.B) { LeafSizeHelper(b, 10, 64) } -func LeafSizeHelper(b *testing.B, base Word, size int) { +func LeafSizeHelper(b *testing.B, base, size int) { b.StopTimer() originalLeafSize := leafSize resetTable(cacheBase10.table[:]) @@ -382,12 +379,12 @@ func LeafSizeHelper(b *testing.B, base Word, size int) { for d := 1; d <= 10000; d *= 10 { b.StopTimer() var z nat - z = z.expWW(base, Word(d)) // build target number - _ = z.string(lowercaseDigits[:base]) // warm divisor cache + z = z.expWW(Word(base), Word(d)) // build target number + _ = z.utoa(base) // warm divisor cache b.StartTimer() for i := 0; i < b.N; i++ { - _ = z.string(lowercaseDigits[:base]) + _ = z.utoa(base) } } @@ -408,13 +405,13 @@ func resetTable(table []divisor) { } func TestStringPowers(t *testing.T) { - var b, p Word - for b = 2; b <= 16; b++ { + var p Word + for b := 2; b <= 16; b++ { for p = 0; p <= 512; p++ { - x := nat(nil).expWW(b, p) - xs := x.string(lowercaseDigits[:b]) - xs2 := toString(x, lowercaseDigits[:b]) - if xs != xs2 { + x := nat(nil).expWW(Word(b), p) + xs := x.utoa(b) + xs2 := itoa(x, b) + if !bytes.Equal(xs, xs2) { t.Errorf("failed at %d ** %d in base %d: %s != %s", b, p, b, xs, xs2) } } diff --git a/libgo/go/math/big/rat.go b/libgo/go/math/big/rat.go index fb16f18..2cd9ed0 100644 --- a/libgo/go/math/big/rat.go +++ b/libgo/go/math/big/rat.go @@ -7,8 +7,6 @@ package big import ( - "encoding/binary" - "errors" "fmt" "math" ) @@ -510,61 +508,3 @@ func (z *Rat) Quo(x, y *Rat) *Rat { z.a.neg = a.neg != b.neg return z.norm() } - -// Gob codec version. Permits backward-compatible changes to the encoding. -const ratGobVersion byte = 1 - -// GobEncode implements the gob.GobEncoder interface. -func (x *Rat) GobEncode() ([]byte, error) { - if x == nil { - return nil, nil - } - buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b.abs))*_S) // extra bytes for version and sign bit (1), and numerator length (4) - i := x.b.abs.bytes(buf) - j := x.a.abs.bytes(buf[:i]) - n := i - j - if int(uint32(n)) != n { - // this should never happen - return nil, errors.New("Rat.GobEncode: numerator too large") - } - binary.BigEndian.PutUint32(buf[j-4:j], uint32(n)) - j -= 1 + 4 - b := ratGobVersion << 1 // make space for sign bit - if x.a.neg { - b |= 1 - } - buf[j] = b - return buf[j:], nil -} - -// GobDecode implements the gob.GobDecoder interface. -func (z *Rat) GobDecode(buf []byte) error { - if len(buf) == 0 { - // Other side sent a nil or default value. - *z = Rat{} - return nil - } - b := buf[0] - if b>>1 != ratGobVersion { - return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1) - } - const j = 1 + 4 - i := j + binary.BigEndian.Uint32(buf[j-4:j]) - z.a.neg = b&1 != 0 - z.a.abs = z.a.abs.setBytes(buf[j:i]) - z.b.abs = z.b.abs.setBytes(buf[i:]) - return nil -} - -// MarshalText implements the encoding.TextMarshaler interface. -func (r *Rat) MarshalText() (text []byte, err error) { - return []byte(r.RatString()), nil -} - -// UnmarshalText implements the encoding.TextUnmarshaler interface. -func (r *Rat) UnmarshalText(text []byte) error { - if _, ok := r.SetString(string(text)); !ok { - return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text) - } - return nil -} diff --git a/libgo/go/math/big/rat_test.go b/libgo/go/math/big/rat_test.go index 012d0c4..3a06fca 100644 --- a/libgo/go/math/big/rat_test.go +++ b/libgo/go/math/big/rat_test.go @@ -5,10 +5,6 @@ package big import ( - "bytes" - "encoding/gob" - "encoding/json" - "encoding/xml" "math" "testing" ) @@ -280,116 +276,6 @@ func TestRatSetFrac64Rat(t *testing.T) { } } -func TestRatGobEncoding(t *testing.T) { - var medium bytes.Buffer - enc := gob.NewEncoder(&medium) - dec := gob.NewDecoder(&medium) - for _, test := range encodingTests { - medium.Reset() // empty buffer for each test case (in case of failures) - var tx Rat - tx.SetString(test + ".14159265") - if err := enc.Encode(&tx); err != nil { - t.Errorf("encoding of %s failed: %s", &tx, err) - } - var rx Rat - if err := dec.Decode(&rx); err != nil { - t.Errorf("decoding of %s failed: %s", &tx, err) - } - if rx.Cmp(&tx) != 0 { - t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx) - } - } -} - -// Sending a nil Rat pointer (inside a slice) on a round trip through gob should yield a zero. -// TODO: top-level nils. -func TestGobEncodingNilRatInSlice(t *testing.T) { - buf := new(bytes.Buffer) - enc := gob.NewEncoder(buf) - dec := gob.NewDecoder(buf) - - var in = make([]*Rat, 1) - err := enc.Encode(&in) - if err != nil { - t.Errorf("gob encode failed: %q", err) - } - var out []*Rat - err = dec.Decode(&out) - if err != nil { - t.Fatalf("gob decode failed: %q", err) - } - if len(out) != 1 { - t.Fatalf("wrong len; want 1 got %d", len(out)) - } - var zero Rat - if out[0].Cmp(&zero) != 0 { - t.Errorf("transmission of (*Int)(nill) failed: got %s want 0", out) - } -} - -var ratNums = []string{ - "-141592653589793238462643383279502884197169399375105820974944592307816406286", - "-1415926535897932384626433832795028841971", - "-141592653589793", - "-1", - "0", - "1", - "141592653589793", - "1415926535897932384626433832795028841971", - "141592653589793238462643383279502884197169399375105820974944592307816406286", -} - -var ratDenoms = []string{ - "1", - "718281828459045", - "7182818284590452353602874713526624977572", - "718281828459045235360287471352662497757247093699959574966967627724076630353", -} - -func TestRatJSONEncoding(t *testing.T) { - for _, num := range ratNums { - for _, denom := range ratDenoms { - var tx Rat - tx.SetString(num + "/" + denom) - b, err := json.Marshal(&tx) - if err != nil { - t.Errorf("marshaling of %s failed: %s", &tx, err) - continue - } - var rx Rat - if err := json.Unmarshal(b, &rx); err != nil { - t.Errorf("unmarshaling of %s failed: %s", &tx, err) - continue - } - if rx.Cmp(&tx) != 0 { - t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx) - } - } - } -} - -func TestRatXMLEncoding(t *testing.T) { - for _, num := range ratNums { - for _, denom := range ratDenoms { - var tx Rat - tx.SetString(num + "/" + denom) - b, err := xml.Marshal(&tx) - if err != nil { - t.Errorf("marshaling of %s failed: %s", &tx, err) - continue - } - var rx Rat - if err := xml.Unmarshal(b, &rx); err != nil { - t.Errorf("unmarshaling of %s failed: %s", &tx, err) - continue - } - if rx.Cmp(&tx) != 0 { - t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx) - } - } - } -} - func TestIssue2379(t *testing.T) { // 1) no aliasing q := NewRat(3, 2) diff --git a/libgo/go/math/big/ratconv.go b/libgo/go/math/big/ratconv.go index 961ff64..4566ff4 100644 --- a/libgo/go/math/big/ratconv.go +++ b/libgo/go/math/big/ratconv.go @@ -188,11 +188,15 @@ func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err err // String returns a string representation of x in the form "a/b" (even if b == 1). func (x *Rat) String() string { - s := "/1" + var buf []byte + buf = x.a.Append(buf, 10) + buf = append(buf, '/') if len(x.b.abs) != 0 { - s = "/" + x.b.abs.decimalString() + buf = x.b.Append(buf, 10) + } else { + buf = append(buf, '1') } - return x.a.String() + s + return string(buf) } // RatString returns a string representation of x in the form "a/b" if b != 1, @@ -208,12 +212,17 @@ func (x *Rat) RatString() string { // digits of precision after the decimal point. The last digit is rounded to // nearest, with halves rounded away from zero. func (x *Rat) FloatString(prec int) string { + var buf []byte + if x.IsInt() { - s := x.a.String() + buf = x.a.Append(buf, 10) if prec > 0 { - s += "." + strings.Repeat("0", prec) + buf = append(buf, '.') + for i := prec; i > 0; i-- { + buf = append(buf, '0') + } } - return s + return string(buf) } // x.b.abs != 0 @@ -237,16 +246,19 @@ func (x *Rat) FloatString(prec int) string { } } - s := q.decimalString() if x.a.neg { - s = "-" + s + buf = append(buf, '-') } + buf = append(buf, q.utoa(10)...) // itoa ignores sign if q == 0 if prec > 0 { - rs := r.decimalString() - leadingZeros := prec - len(rs) - s += "." + strings.Repeat("0", leadingZeros) + rs + buf = append(buf, '.') + rs := r.utoa(10) + for i := prec - len(rs); i > 0; i-- { + buf = append(buf, '0') + } + buf = append(buf, rs...) } - return s + return string(buf) } diff --git a/libgo/go/math/big/ratmarsh.go b/libgo/go/math/big/ratmarsh.go new file mode 100644 index 0000000..b82e8d4 --- /dev/null +++ b/libgo/go/math/big/ratmarsh.go @@ -0,0 +1,73 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements encoding/decoding of Rats. + +package big + +import ( + "encoding/binary" + "errors" + "fmt" +) + +// Gob codec version. Permits backward-compatible changes to the encoding. +const ratGobVersion byte = 1 + +// GobEncode implements the gob.GobEncoder interface. +func (x *Rat) GobEncode() ([]byte, error) { + if x == nil { + return nil, nil + } + buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b.abs))*_S) // extra bytes for version and sign bit (1), and numerator length (4) + i := x.b.abs.bytes(buf) + j := x.a.abs.bytes(buf[:i]) + n := i - j + if int(uint32(n)) != n { + // this should never happen + return nil, errors.New("Rat.GobEncode: numerator too large") + } + binary.BigEndian.PutUint32(buf[j-4:j], uint32(n)) + j -= 1 + 4 + b := ratGobVersion << 1 // make space for sign bit + if x.a.neg { + b |= 1 + } + buf[j] = b + return buf[j:], nil +} + +// GobDecode implements the gob.GobDecoder interface. +func (z *Rat) GobDecode(buf []byte) error { + if len(buf) == 0 { + // Other side sent a nil or default value. + *z = Rat{} + return nil + } + b := buf[0] + if b>>1 != ratGobVersion { + return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1) + } + const j = 1 + 4 + i := j + binary.BigEndian.Uint32(buf[j-4:j]) + z.a.neg = b&1 != 0 + z.a.abs = z.a.abs.setBytes(buf[j:i]) + z.b.abs = z.b.abs.setBytes(buf[i:]) + return nil +} + +// MarshalText implements the encoding.TextMarshaler interface. +func (x *Rat) MarshalText() (text []byte, err error) { + // TODO(gri): get rid of the []byte/string conversion + return []byte(x.RatString()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +func (z *Rat) UnmarshalText(text []byte) error { + // TODO(gri): get rid of the []byte/string conversion + if _, ok := z.SetString(string(text)); !ok { + return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text) + } + return nil +} diff --git a/libgo/go/math/big/ratmarsh_test.go b/libgo/go/math/big/ratmarsh_test.go new file mode 100644 index 0000000..351d109 --- /dev/null +++ b/libgo/go/math/big/ratmarsh_test.go @@ -0,0 +1,125 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package big + +import ( + "bytes" + "encoding/gob" + "encoding/json" + "encoding/xml" + "testing" +) + +func TestRatGobEncoding(t *testing.T) { + var medium bytes.Buffer + enc := gob.NewEncoder(&medium) + dec := gob.NewDecoder(&medium) + for _, test := range encodingTests { + medium.Reset() // empty buffer for each test case (in case of failures) + var tx Rat + tx.SetString(test + ".14159265") + if err := enc.Encode(&tx); err != nil { + t.Errorf("encoding of %s failed: %s", &tx, err) + continue + } + var rx Rat + if err := dec.Decode(&rx); err != nil { + t.Errorf("decoding of %s failed: %s", &tx, err) + continue + } + if rx.Cmp(&tx) != 0 { + t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx) + } + } +} + +// Sending a nil Rat pointer (inside a slice) on a round trip through gob should yield a zero. +// TODO: top-level nils. +func TestGobEncodingNilRatInSlice(t *testing.T) { + buf := new(bytes.Buffer) + enc := gob.NewEncoder(buf) + dec := gob.NewDecoder(buf) + + var in = make([]*Rat, 1) + err := enc.Encode(&in) + if err != nil { + t.Errorf("gob encode failed: %q", err) + } + var out []*Rat + err = dec.Decode(&out) + if err != nil { + t.Fatalf("gob decode failed: %q", err) + } + if len(out) != 1 { + t.Fatalf("wrong len; want 1 got %d", len(out)) + } + var zero Rat + if out[0].Cmp(&zero) != 0 { + t.Fatalf("transmission of (*Int)(nil) failed: got %s want 0", out) + } +} + +var ratNums = []string{ + "-141592653589793238462643383279502884197169399375105820974944592307816406286", + "-1415926535897932384626433832795028841971", + "-141592653589793", + "-1", + "0", + "1", + "141592653589793", + "1415926535897932384626433832795028841971", + "141592653589793238462643383279502884197169399375105820974944592307816406286", +} + +var ratDenoms = []string{ + "1", + "718281828459045", + "7182818284590452353602874713526624977572", + "718281828459045235360287471352662497757247093699959574966967627724076630353", +} + +func TestRatJSONEncoding(t *testing.T) { + for _, num := range ratNums { + for _, denom := range ratDenoms { + var tx Rat + tx.SetString(num + "/" + denom) + b, err := json.Marshal(&tx) + if err != nil { + t.Errorf("marshaling of %s failed: %s", &tx, err) + continue + } + var rx Rat + if err := json.Unmarshal(b, &rx); err != nil { + t.Errorf("unmarshaling of %s failed: %s", &tx, err) + continue + } + if rx.Cmp(&tx) != 0 { + t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx) + } + } + } +} + +func TestRatXMLEncoding(t *testing.T) { + for _, num := range ratNums { + for _, denom := range ratDenoms { + var tx Rat + tx.SetString(num + "/" + denom) + b, err := xml.Marshal(&tx) + if err != nil { + t.Errorf("marshaling of %s failed: %s", &tx, err) + continue + } + var rx Rat + if err := xml.Unmarshal(b, &rx); err != nil { + t.Errorf("unmarshaling of %s failed: %s", &tx, err) + continue + } + if rx.Cmp(&tx) != 0 { + t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx) + } + } + } +} diff --git a/libgo/go/math/cmplx/cmath_test.go b/libgo/go/math/cmplx/cmath_test.go index f285646..18d9be8 100644 --- a/libgo/go/math/cmplx/cmath_test.go +++ b/libgo/go/math/cmplx/cmath_test.go @@ -438,8 +438,10 @@ func tolerance(a, b, e float64) bool { d = -d } - if a != 0 { - e = e * a + // note: b is correct (expected) value, a is actual value. + // make error tolerance a fraction of b, not a. + if b != 0 { + e = e * b if e < 0 { e = -e } @@ -460,8 +462,8 @@ func alike(a, b float64) bool { func cTolerance(a, b complex128, e float64) bool { d := Abs(a - b) - if a != 0 { - e = e * Abs(a) + if b != 0 { + e = e * Abs(b) if e < 0 { e = -e } diff --git a/libgo/go/math/cmplx/sqrt.go b/libgo/go/math/cmplx/sqrt.go index 4ef6807..276be07 100644 --- a/libgo/go/math/cmplx/sqrt.go +++ b/libgo/go/math/cmplx/sqrt.go @@ -40,7 +40,7 @@ import "math" // 1/2 // Im w = [ (r - x)/2 ] . // -// Cancellation error in r-x or r+x is avoided by using the +// Cancelation error in r-x or r+x is avoided by using the // identity 2 Re w Im w = y. // // Note that -w is also a square root of z. The root chosen diff --git a/libgo/go/math/expm1.go b/libgo/go/math/expm1.go index 8d7b3d3..b4dcdc5 100644 --- a/libgo/go/math/expm1.go +++ b/libgo/go/math/expm1.go @@ -233,7 +233,7 @@ func expm1(x float64) float64 { y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent return y } - t := Float64frombits(uint64((0x3ff - k) << 52)) // 2**-k + t := Float64frombits(uint64(0x3ff-k) << 52) // 2**-k y := x - (e + t) y += 1 y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent diff --git a/libgo/go/math/floor_asm.go b/libgo/go/math/floor_asm.go new file mode 100644 index 0000000..28e56a5 --- /dev/null +++ b/libgo/go/math/floor_asm.go @@ -0,0 +1,12 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build amd64 amd64p32 + +package math + +//defined in floor_amd64.s +func hasSSE4() bool + +var useSSE4 = hasSSE4() diff --git a/libgo/go/math/j0.go b/libgo/go/math/j0.go index c20a9b2..de77388 100644 --- a/libgo/go/math/j0.go +++ b/libgo/go/math/j0.go @@ -38,7 +38,7 @@ package math // = 1/sqrt(2) * (cos(x) + sin(x)) // sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) // = 1/sqrt(2) * (sin(x) - cos(x)) -// (To avoid cancellation, use +// (To avoid cancelation, use // sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) // to compute the worse one.) // @@ -188,7 +188,7 @@ func Y0(x float64) float64 { // = 1/sqrt(2) * (sin(x) + cos(x)) // sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) // = 1/sqrt(2) * (sin(x) - cos(x)) - // To avoid cancellation, use + // To avoid cancelation, use // sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) // to compute the worse one. diff --git a/libgo/go/math/j1.go b/libgo/go/math/j1.go index 7ac186b..c537a72 100644 --- a/libgo/go/math/j1.go +++ b/libgo/go/math/j1.go @@ -39,7 +39,7 @@ package math // = 1/sqrt(2) * (sin(x) - cos(x)) // sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) // = -1/sqrt(2) * (sin(x) + cos(x)) -// (To avoid cancellation, use +// (To avoid cancelation, use // sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) // to compute the worse one.) // @@ -197,7 +197,7 @@ func Y1(x float64) float64 { // = 1/sqrt(2) * (sin(x) - cos(x)) // sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) // = -1/sqrt(2) * (cos(x) + sin(x)) - // To avoid cancellation, use + // To avoid cancelation, use // sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) // to compute the worse one. diff --git a/libgo/go/math/jn.go b/libgo/go/math/jn.go index a7909eb..ffb8a00 100644 --- a/libgo/go/math/jn.go +++ b/libgo/go/math/jn.go @@ -200,13 +200,11 @@ func Jn(n int, x float64) float64 { for i := n - 1; i > 0; i-- { di := float64(i + i) a, b = b, b*di/x-a - di -= 2 } } else { for i := n - 1; i > 0; i-- { di := float64(i + i) a, b = b, b*di/x-a - di -= 2 // scale b to avoid spurious overflow if b > 1e100 { a /= b diff --git a/libgo/go/math/modf.go b/libgo/go/math/modf.go index ecec4b7..5d2f489 100644 --- a/libgo/go/math/modf.go +++ b/libgo/go/math/modf.go @@ -16,9 +16,12 @@ func Modf(f float64) (int float64, frac float64) { func modf(f float64) (int float64, frac float64) { if f < 1 { - if f < 0 { + switch { + case f < 0: int, frac = Modf(-f) return -int, -frac + case f == 0: + return f, f // Return -0, -0 when f == -0 } return 0, f } diff --git a/libgo/go/math/rand/rand.go b/libgo/go/math/rand/rand.go index 6360128..d693bfb 100644 --- a/libgo/go/math/rand/rand.go +++ b/libgo/go/math/rand/rand.go @@ -113,19 +113,18 @@ func (r *Rand) Float64() float64 { // // There is one bug in the value stream: r.Int63() may be so close // to 1<<63 that the division rounds up to 1.0, and we've guaranteed - // that the result is always less than 1.0. To fix that, we treat the - // range as cyclic and map 1 back to 0. This is justified by observing - // that while some of the values rounded down to 0, nothing was - // rounding up to 0, so 0 was underrepresented in the results. - // Mapping 1 back to zero restores some balance. - // (The balance is not perfect because the implementation - // returns denormalized numbers for very small r.Int63(), - // and those steal from what would normally be 0 results.) - // The remapping only happens 1/2⁵³ of the time, so most clients + // that the result is always less than 1.0. + // + // We tried to fix this by mapping 1.0 back to 0.0, but since float64 + // values near 0 are much denser than near 1, mapping 1 to 0 caused + // a theoretically significant overshoot in the probability of returning 0. + // Instead of that, if we round up to 1, just try again. + // Getting 1 only happens 1/2⁵³ of the time, so most clients // will not observe it anyway. +again: f := float64(r.Int63()) / (1 << 63) if f == 1 { - f = 0 + goto again // resample; this branch is taken O(never) } return f } @@ -134,13 +133,11 @@ func (r *Rand) Float64() float64 { func (r *Rand) Float32() float32 { // Same rationale as in Float64: we want to preserve the Go 1 value // stream except we want to fix it not to return 1.0 - // There is a double rounding going on here, but the argument for - // mapping 1 to 0 still applies: 0 was underrepresented before, - // so mapping 1 to 0 doesn't cause too many 0s. // This only happens 1/2²⁴ of the time (plus the 1/2⁵³ of the time in Float64). +again: f := float32(r.Float64()) if f == 1 { - f = 0 + goto again // resample; this branch is taken O(very rarely) } return f } @@ -148,6 +145,11 @@ func (r *Rand) Float32() float32 { // Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n). func (r *Rand) Perm(n int) []int { m := make([]int, n) + // In the following loop, the iteration when i=0 always swaps m[0] with m[0]. + // A change to remove this useless iteration is to assign 1 to i in the init + // statement. But Perm also effects r. Making this change will affect + // the final state of r. So this change can't be made for compatibility + // reasons for Go 1. for i := 0; i < n; i++ { j := r.Intn(i + 1) m[i] = m[j] @@ -156,6 +158,19 @@ func (r *Rand) Perm(n int) []int { return m } +// Read generates len(p) random bytes and writes them into p. It +// always returns len(p) and a nil error. +func (r *Rand) Read(p []byte) (n int, err error) { + for i := 0; i < len(p); i += 7 { + val := r.src.Int63() + for j := 0; i+j < len(p) && j < 7; j++ { + p[i+j] = byte(val) + val >>= 8 + } + } + return len(p), nil +} + /* * Top-level convenience functions */ @@ -209,6 +224,10 @@ func Float32() float32 { return globalRand.Float32() } // from the default Source. func Perm(n int) []int { return globalRand.Perm(n) } +// Read generates len(p) random bytes from the default Source and +// writes them into p. It always returns len(p) and a nil error. +func Read(p []byte) (n int, err error) { return globalRand.Read(p) } + // NormFloat64 returns a normally distributed float64 in the range // [-math.MaxFloat64, +math.MaxFloat64] with // standard normal distribution (mean = 0, stddev = 1) diff --git a/libgo/go/math/rand/rand_test.go b/libgo/go/math/rand/rand_test.go index c61494f..8d68335 100644 --- a/libgo/go/math/rand/rand_test.go +++ b/libgo/go/math/rand/rand_test.go @@ -7,6 +7,7 @@ package rand import ( "errors" "fmt" + "internal/testenv" "math" "os" "runtime" @@ -327,9 +328,10 @@ func TestExpTables(t *testing.T) { func TestFloat32(t *testing.T) { // For issue 6721, the problem came after 7533753 calls, so check 10e6. num := int(10e6) + // But do the full amount only on builders (not locally). // But ARM5 floating point emulation is slow (Issue 10749), so // do less for that builder: - if testing.Short() && runtime.GOARCH == "arm" && os.Getenv("GOARM") == "5" { + if testing.Short() && (testenv.Builder() == "" || runtime.GOARCH == "arm" && os.Getenv("GOARM") == "5") { num /= 100 // 1.72 seconds instead of 172 seconds } @@ -342,6 +344,59 @@ func TestFloat32(t *testing.T) { } } +func testReadUniformity(t *testing.T, n int, seed int64) { + r := New(NewSource(seed)) + buf := make([]byte, n) + nRead, err := r.Read(buf) + if err != nil { + t.Errorf("Read err %v", err) + } + if nRead != n { + t.Errorf("Read returned unexpected n; %d != %d", nRead, n) + } + + // Expect a uniform distribution of byte values, which lie in [0, 255]. + var ( + mean = 255.0 / 2 + stddev = math.Sqrt(255.0 * 255.0 / 12.0) + errorScale = stddev / math.Sqrt(float64(n)) + ) + + expected := &statsResults{mean, stddev, 0.10 * errorScale, 0.08 * errorScale} + + // Cast bytes as floats to use the common distribution-validity checks. + samples := make([]float64, n) + for i, val := range buf { + samples[i] = float64(val) + } + // Make sure that the entire set matches the expected distribution. + checkSampleDistribution(t, samples, expected) +} + +func TestRead(t *testing.T) { + testBufferSizes := []int{ + 2, 4, 7, 64, 1024, 1 << 16, 1 << 20, + } + for _, seed := range testSeeds { + for _, n := range testBufferSizes { + testReadUniformity(t, n, seed) + } + } +} + +func TestReadEmpty(t *testing.T) { + r := New(NewSource(1)) + buf := make([]byte, 0) + n, err := r.Read(buf) + if err != nil { + t.Errorf("Read err into empty buffer; %v", err) + } + if n != 0 { + t.Errorf("Read into empty buffer returned unexpected n of %d", n) + } + +} + // Benchmarks func BenchmarkInt63Threadsafe(b *testing.B) { @@ -405,3 +460,30 @@ func BenchmarkPerm30(b *testing.B) { r.Perm(30) } } + +func BenchmarkRead3(b *testing.B) { + r := New(NewSource(1)) + buf := make([]byte, 3) + b.ResetTimer() + for n := b.N; n > 0; n-- { + r.Read(buf) + } +} + +func BenchmarkRead64(b *testing.B) { + r := New(NewSource(1)) + buf := make([]byte, 64) + b.ResetTimer() + for n := b.N; n > 0; n-- { + r.Read(buf) + } +} + +func BenchmarkRead1000(b *testing.B) { + r := New(NewSource(1)) + buf := make([]byte, 1000) + b.ResetTimer() + for n := b.N; n > 0; n-- { + r.Read(buf) + } +} diff --git a/libgo/go/math/rand/regress_test.go b/libgo/go/math/rand/regress_test.go index 2b012af..9ae5357 100644 --- a/libgo/go/math/rand/regress_test.go +++ b/libgo/go/math/rand/regress_test.go @@ -25,6 +25,7 @@ func TestRegress(t *testing.T) { var int32s = []int32{1, 10, 32, 1 << 20, 1<<20 + 1, 1000000000, 1 << 30, 1<<31 - 2, 1<<31 - 1} var int64s = []int64{1, 10, 32, 1 << 20, 1<<20 + 1, 1000000000, 1 << 30, 1<<31 - 2, 1<<31 - 1, 1000000000000000000, 1 << 60, 1<<63 - 2, 1<<63 - 1} var permSizes = []int{0, 1, 5, 8, 9, 10, 16} + var readBufferSizes = []int{1, 7, 8, 9, 10} r := New(NewSource(0)) rv := reflect.ValueOf(r) @@ -40,9 +41,6 @@ func TestRegress(t *testing.T) { if mt.NumOut() == 0 { continue } - if mt.NumOut() != 1 { - t.Fatalf("unexpected result count for r.%s", m.Name) - } r.Seed(0) for repeat := 0; repeat < 20; repeat++ { var args []reflect.Value @@ -74,14 +72,25 @@ func TestRegress(t *testing.T) { case reflect.Int64: x = int64s[repeat%len(int64s)] + + case reflect.Slice: + if m.Name == "Read" { + n := readBufferSizes[repeat%len(readBufferSizes)] + x = make([]byte, n) + } } argstr = fmt.Sprint(x) args = append(args, reflect.ValueOf(x)) } - out := mv.Call(args)[0].Interface() + + var out interface{} + out = mv.Call(args)[0].Interface() if m.Name == "Int" || m.Name == "Intn" { out = int64(out.(int)) } + if m.Name == "Read" { + out = args[0].Interface().([]byte) + } if *printgolden { var val string big := int64(1 << 60) @@ -332,24 +341,44 @@ var regressGolden = []interface{}{ []int{2, 1, 7, 0, 6, 3, 4, 5}, // Perm(8) []int{8, 7, 5, 3, 4, 6, 0, 1, 2}, // Perm(9) []int{1, 0, 2, 5, 7, 6, 9, 8, 3, 4}, // Perm(10) - uint32(4059586549), // Uint32() - uint32(1052117029), // Uint32() - uint32(2817310706), // Uint32() - uint32(233405013), // Uint32() - uint32(1578775030), // Uint32() - uint32(1243308993), // Uint32() - uint32(826517535), // Uint32() - uint32(2814630155), // Uint32() - uint32(3853314576), // Uint32() - uint32(718781857), // Uint32() - uint32(1239465936), // Uint32() - uint32(3876658295), // Uint32() - uint32(3649778518), // Uint32() - uint32(1172727096), // Uint32() - uint32(2615979505), // Uint32() - uint32(1089444252), // Uint32() - uint32(3327114623), // Uint32() - uint32(75079301), // Uint32() - uint32(3380456901), // Uint32() - uint32(3433369789), // Uint32() + []byte{0x1}, // Read([0]) + []byte{0xc0, 0x41, 0xd3, 0xff, 0x12, 0x4, 0x5b}, // Read([0 0 0 0 0 0 0]) + []byte{0x73, 0xc8, 0x6e, 0x4f, 0xf9, 0x5f, 0xf6, 0x62}, // Read([0 0 0 0 0 0 0 0]) + []byte{0x4a, 0x2d, 0xb, 0x75, 0xfb, 0x18, 0xd, 0xaf, 0x48}, // Read([0 0 0 0 0 0 0 0 0]) + []byte{0x39, 0x46, 0x51, 0x85, 0xf, 0xd4, 0xa1, 0x78, 0x89, 0x2e}, // Read([0 0 0 0 0 0 0 0 0 0]) + []byte{0x51}, // Read([0]) + []byte{0x4e, 0xe2, 0xd3, 0xd0, 0xd0, 0xde, 0x6b}, // Read([0 0 0 0 0 0 0]) + []byte{0xf8, 0xf9, 0xb4, 0x4c, 0xe8, 0x5f, 0xf0, 0x44}, // Read([0 0 0 0 0 0 0 0]) + []byte{0x3b, 0xbf, 0x85, 0x7a, 0xab, 0x99, 0xc5, 0xb2, 0x52}, // Read([0 0 0 0 0 0 0 0 0]) + []byte{0xa8, 0xae, 0xb7, 0x9e, 0xf8, 0x56, 0xf6, 0x59, 0xc1, 0x8f}, // Read([0 0 0 0 0 0 0 0 0 0]) + []byte{0xc7}, // Read([0]) + []byte{0x5f, 0x67, 0xcf, 0xe2, 0x42, 0xcf, 0x3c}, // Read([0 0 0 0 0 0 0]) + []byte{0xc3, 0x54, 0xf3, 0xed, 0xe2, 0xd6, 0xbe, 0xcc}, // Read([0 0 0 0 0 0 0 0]) + []byte{0x6a, 0x9f, 0x4a, 0x57, 0x8b, 0xcb, 0x9e, 0xf2, 0xd4}, // Read([0 0 0 0 0 0 0 0 0]) + []byte{0x6d, 0x29, 0x97, 0x61, 0xea, 0x9e, 0x4f, 0x5a, 0xa6, 0xae}, // Read([0 0 0 0 0 0 0 0 0 0]) + []byte{0xaa}, // Read([0]) + []byte{0x20, 0xef, 0xcd, 0x6c, 0xea, 0x84, 0xb6}, // Read([0 0 0 0 0 0 0]) + []byte{0x92, 0x5e, 0x60, 0x7b, 0xe0, 0x63, 0x71, 0x6f}, // Read([0 0 0 0 0 0 0 0]) + []byte{0x4, 0x5c, 0x3f, 0x0, 0xf, 0x8a, 0x79, 0x6b, 0xce}, // Read([0 0 0 0 0 0 0 0 0]) + []byte{0xaa, 0xca, 0xee, 0xdf, 0xad, 0x5b, 0x50, 0x66, 0x64, 0xe8}, // Read([0 0 0 0 0 0 0 0 0 0]) + uint32(4059586549), // Uint32() + uint32(1052117029), // Uint32() + uint32(2817310706), // Uint32() + uint32(233405013), // Uint32() + uint32(1578775030), // Uint32() + uint32(1243308993), // Uint32() + uint32(826517535), // Uint32() + uint32(2814630155), // Uint32() + uint32(3853314576), // Uint32() + uint32(718781857), // Uint32() + uint32(1239465936), // Uint32() + uint32(3876658295), // Uint32() + uint32(3649778518), // Uint32() + uint32(1172727096), // Uint32() + uint32(2615979505), // Uint32() + uint32(1089444252), // Uint32() + uint32(3327114623), // Uint32() + uint32(75079301), // Uint32() + uint32(3380456901), // Uint32() + uint32(3433369789), // Uint32() } diff --git a/libgo/go/math/sqrt.go b/libgo/go/math/sqrt.go index 215d648..86c0452 100644 --- a/libgo/go/math/sqrt.go +++ b/libgo/go/math/sqrt.go @@ -114,7 +114,7 @@ func sqrt(x float64) float64 { // normalize x exp := int((ix >> shift) & mask) if exp == 0 { // subnormal x - for ix&1<<shift == 0 { + for ix&(1<<shift) == 0 { ix <<= 1 exp-- } |