diff --git a/src/cmd/compile/internal/big/example_test.go b/src/cmd/compile/internal/big/example_test.go index cb91bc23bd..8a71a08627 100644 --- a/src/cmd/compile/internal/big/example_test.go +++ b/src/cmd/compile/internal/big/example_test.go @@ -8,6 +8,7 @@ import ( "cmd/compile/internal/big" "fmt" "log" + "math" ) func ExampleRat_SetString() { @@ -49,3 +50,79 @@ func ExampleInt_Scan() { } // Output: 18446744073709551617 } + +// This example demonstrates how to use big.Int to compute the smallest +// Fibonacci number with 100 decimal digits and to test whether it is prime. +func Example_fibonacci() { + // Initialize two big ints with the first two numbers in the sequence. + a := big.NewInt(0) + b := big.NewInt(1) + + // Initialize limit as 10^99, the smallest integer with 100 digits. + var limit big.Int + limit.Exp(big.NewInt(10), big.NewInt(99), nil) + + // Loop while a is smaller than 1e100. + for a.Cmp(&limit) < 0 { + // Compute the next Fibonacci number, storing it in a. + a.Add(a, b) + // Swap a and b so that b is the next number in the sequence. + a, b = b, a + } + fmt.Println(a) // 100-digit Fibonacci number + + // Test a for primality. + // (ProbablyPrimes' argument sets the number of Miller-Rabin + // rounds to be performed. 20 is a good value.) + fmt.Println(a.ProbablyPrime(20)) + + // Output: + // 1344719667586153181419716641724567886890850696275767987106294472017884974410332069524504824747437757 + // false +} + +// This example shows how to use big.Float to compute the square root of 2 with +// a precision of 200 bits, and how to print the result as a decimal number. +func Example_sqrt2() { + // We'll do computations with 200 bits of precision in the mantissa. + const prec = 200 + + // Compute the square root of 2 using Newton's Method. We start with + // an initial estimate for sqrt(2), and then iterate: + // x_{n+1} = 1/2 * ( x_n + (2.0 / x_n) ) + + // Since Newton's Method doubles the number of correct digits at each + // iteration, we need at least log_2(prec) steps. + steps := int(math.Log2(prec)) + + // Initialize values we need for the computation. + two := new(big.Float).SetPrec(prec).SetInt64(2) + half := new(big.Float).SetPrec(prec).SetFloat64(0.5) + + // Use 1 as the initial estimate. + x := new(big.Float).SetPrec(prec).SetInt64(1) + + // We use t as a temporary variable. There's no need to set its precision + // since big.Float values with unset (== 0) precision automatically assume + // the largest precision of the arguments when used as the result (receiver) + // of a big.Float operation. + t := new(big.Float) + + // Iterate. + for i := 0; i <= steps; i++ { + t.Quo(two, x) // t = 2.0 / x_n + t.Add(x, t) // t = x_n + (2.0 / x_n) + x.Mul(half, t) // x_{n+1} = 0.5 * t + } + + // We can use the usual fmt.Printf verbs since big.Float implements fmt.Formatter + fmt.Printf("sqrt(2) = %.50f\n", x) + + // Print the error between 2 and x*x. + t.Mul(x, x) // t = x*x + fmt.Printf("error = %e\n", t.Sub(two, t)) + + // Output: + // sqrt(2) = 1.41421356237309504880168872420969807856967187537695 + // error = 0.000000e+00 +} diff --git a/src/cmd/compile/internal/big/floatconv.go b/src/cmd/compile/internal/big/floatconv.go index 4a070ca64d..0e8b7b649e 100644 --- a/src/cmd/compile/internal/big/floatconv.go +++ b/src/cmd/compile/internal/big/floatconv.go @@ -125,9 +125,9 @@ func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) { // apply 10**exp10 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)) + z.Quo(z, p.pow10(-exp10)) } else { - z.umul(z, p.pow10(exp10)) + z.Mul(z, p.pow10(exp10)) } return diff --git a/src/cmd/compile/internal/big/floatconv_test.go b/src/cmd/compile/internal/big/floatconv_test.go index 4f239534a1..156e1af300 100644 --- a/src/cmd/compile/internal/big/floatconv_test.go +++ b/src/cmd/compile/internal/big/floatconv_test.go @@ -367,9 +367,9 @@ 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"}, + {"1e1000000000", 64, 'p', 0, "+Inf"}, {"1e-1000000", 64, 'p', 0, "0x.efb4542cc8ca418ap-3321928"}, - {"1e-1000000000", 64, 'p', 0, "0x.8a64dd983a4c7dabp-1538481528"}, + {"1e-1000000000", 64, 'p', 0, "0"}, // TODO(gri) need tests for actual large Floats diff --git a/src/cmd/compile/internal/big/int.go b/src/cmd/compile/internal/big/int.go index 5e3125375b..65334e0ef5 100644 --- a/src/cmd/compile/internal/big/int.go +++ b/src/cmd/compile/internal/big/int.go @@ -500,15 +500,17 @@ func (z *Int) binaryGCD(a, b *Int) *Int { // use one Euclidean iteration to ensure that u and v are approx. the same size switch { case len(a.abs) > len(b.abs): - u.Set(b) + // must set v before u since u may be alias for a or b (was issue #11284) v.Rem(a, b) + u.Set(b) case len(a.abs) < len(b.abs): - u.Set(a) v.Rem(b, a) - default: u.Set(a) + default: v.Set(b) + u.Set(a) } + // a, b must not be used anymore (may be aliases with u) // v might be 0 now if len(v.abs) == 0 { diff --git a/src/cmd/compile/internal/big/int_test.go b/src/cmd/compile/internal/big/int_test.go index 16eed9a770..97874626f3 100644 --- a/src/cmd/compile/internal/big/int_test.go +++ b/src/cmd/compile/internal/big/int_test.go @@ -387,6 +387,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) } @@ -662,6 +667,21 @@ func testGcd(t *testing.T, d, x, y, a, b *Int) { if D.Cmp(d) != 0 { t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, D, d) } + + // check results in presence of aliasing (issue #11284) + a2 := new(Int).Set(a) + b2 := new(Int).Set(b) + a2.binaryGCD(a2, b2) // result is same as 1st argument + if a2.Cmp(d) != 0 { + t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, a2, d) + } + + a2 = new(Int).Set(a) + b2 = new(Int).Set(b) + b2.binaryGCD(a2, b2) // result is same as 2nd argument + if b2.Cmp(d) != 0 { + t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, b2, d) + } } func TestGcd(t *testing.T) { diff --git a/src/cmd/compile/internal/big/intconv.go b/src/cmd/compile/internal/big/intconv.go index 9c68a22bed..737d176cb8 100644 --- a/src/cmd/compile/internal/big/intconv.go +++ b/src/cmd/compile/internal/big/intconv.go @@ -101,31 +101,31 @@ func (x *Int) Format(s fmt.State, ch rune) { digits := x.abs.string(cs) // 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 + zeros = precision - len(digits) // count of zero padding case digits == "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,7 +136,7 @@ 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, "0", zeros) writeMultiple(s, digits, 1) writeMultiple(s, " ", right) } diff --git a/src/cmd/compile/internal/big/natconv.go b/src/cmd/compile/internal/big/natconv.go index 022dcfe38c..80da307147 100644 --- a/src/cmd/compile/internal/big/natconv.go +++ b/src/cmd/compile/internal/big/natconv.go @@ -252,14 +252,15 @@ func (x nat) hexString() string { // 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: + if b < 2 || b > 256 { panic("invalid character set length") - case len(x) == 0: + } + + // x == 0 + if len(x) == 0 { return string(charset[0]) } + // len(x) > 0 // allocate buffer for conversion i := int(float64(x.bitLen())/math.Log2(float64(b))) + 1 // off by one at most @@ -267,13 +268,13 @@ func (x nat) string(charset string) string { // convert power of two and non power of two bases separately if b == b&-b { - // shift is base-b digit size in bits + // shift is base b digit size in bits shift := trailingZeroBits(b) // shift > 0 because b >= 2 - mask := Word(1)<= shift { @@ -289,7 +290,7 @@ 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] @@ -300,12 +301,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] w >>= shift - nbits -= shift } } else { @@ -409,9 +409,9 @@ func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word } } - // prepend high-order zeroes + // prepend high-order zeros zero := charset[0] - for i > 0 { // while need more leading zeroes + for i > 0 { // while need more leading zeros i-- s[i] = zero } @@ -425,7 +425,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/src/cmd/compile/internal/big/ratconv.go b/src/cmd/compile/internal/big/ratconv.go index 778077b96e..961ff649a5 100644 --- a/src/cmd/compile/internal/big/ratconv.go +++ b/src/cmd/compile/internal/big/ratconv.go @@ -205,7 +205,8 @@ func (x *Rat) RatString() string { } // FloatString returns a string representation of x in decimal form with prec -// digits of precision after the decimal point and the last digit rounded. +// 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 { if x.IsInt() { s := x.a.String() diff --git a/src/cmd/compile/internal/big/ratconv_test.go b/src/cmd/compile/internal/big/ratconv_test.go index 16b3a19418..da2fdab4ca 100644 --- a/src/cmd/compile/internal/big/ratconv_test.go +++ b/src/cmd/compile/internal/big/ratconv_test.go @@ -113,6 +113,8 @@ var floatStringTests = []struct { {"1", 0, "1"}, {"1", 2, "1.00"}, {"-1", 0, "-1"}, + {"0.05", 1, "0.1"}, + {"-0.05", 1, "-0.1"}, {".25", 2, "0.25"}, {".25", 1, "0.3"}, {".25", 3, "0.250"},