Update prebuilts to go 1.12.1 From https://ci.android.com/builds/submitted/5389456/linux/latest/go.zip Also includes a cherry-pick of https://github.com/golang/go/commit/ff048033e4304898245d843e79ed1a0897006c6d Fixes: 126298064 Test: m blueprint_tools Change-Id: I581e084f909acc0b1e3f95be6452c86c86da1bac
diff --git a/src/math/acos_s390x.s b/src/math/acos_s390x.s index 306f45a..d2288b8 100644 --- a/src/math/acos_s390x.s +++ b/src/math/acos_s390x.s
@@ -42,7 +42,7 @@ TEXT ·acosAsm(SB), NOSPLIT, $0-16 FMOVD x+0(FP), F0 MOVD $·acosrodataL13<>+0(SB), R9 - WORD $0xB3CD00C0 //lgdr %r12, %f0 + LGDR F0, R12 FMOVD F0, F10 SRAD $32, R12 WORD $0xC0293FE6 //iilf %r2,1072079005
diff --git a/src/math/acosh_s390x.s b/src/math/acosh_s390x.s index 3575ed6..87a5d00 100644 --- a/src/math/acosh_s390x.s +++ b/src/math/acosh_s390x.s
@@ -53,7 +53,7 @@ TEXT ·acoshAsm(SB), NOSPLIT, $0-16 FMOVD x+0(FP), F0 MOVD $·acoshrodataL11<>+0(SB), R9 - WORD $0xB3CD0010 //lgdr %r1, %f0 + LGDR F0, R1 WORD $0xC0295FEF //iilf %r2,1609564159 BYTE $0xFF BYTE $0xFF @@ -85,7 +85,7 @@ WORD $0xC0398006 //iilf %r3,2147909631 BYTE $0x7F BYTE $0xFF - WORD $0xB3CD0050 //lgdr %r5, %f0 + LGDR F0, R5 SRAD $32, R5 MOVH $0x0, R1 SUBW R5, R3 @@ -105,7 +105,7 @@ SRAW $8, R2, R2 ORW $0x45000000, R2 L5: - WORD $0xB3C10001 //ldgr %f0,%r1 + LDGR R1, F0 FMOVD 104(R9), F2 FMADD F8, F0, F2 FMOVD 96(R9), F4 @@ -153,7 +153,7 @@ WORD $0xC0398006 //iilf %r3,2147909631 BYTE $0x7F BYTE $0xFF - WORD $0xB3CD0050 //lgdr %r5, %f0 + LGDR F0, R5 SRAD $32, R5 MOVH $0x0, R1 SUBW R5, R3
diff --git a/src/math/all_test.go b/src/math/all_test.go index bcc20a3..ed42941 100644 --- a/src/math/all_test.go +++ b/src/math/all_test.go
@@ -128,7 +128,7 @@ var ceil = []float64{ 5.0000000000000000e+00, 8.0000000000000000e+00, - 0.0000000000000000e+00, + Copysign(0, -1), -5.0000000000000000e+00, 1.0000000000000000e+01, 3.0000000000000000e+00, @@ -175,6 +175,7 @@ -2.51772931436786954751e-01, -7.3924135157173099849e-01, } + var cosh = []float64{ 7.2668796942212842775517446e+01, 1.1479413465659254502011135e+03, @@ -644,7 +645,7 @@ var trunc = []float64{ 4.0000000000000000e+00, 7.0000000000000000e+00, - -0.0000000000000000e+00, + Copysign(0, -1), -5.0000000000000000e+00, 9.0000000000000000e+00, 2.0000000000000000e+00, @@ -1527,6 +1528,7 @@ 0, Inf(1), NaN(), + 4503599627370496.5, // Issue #29488 } var log1pSC = []float64{ NaN(), @@ -1536,6 +1538,7 @@ 0, Inf(1), NaN(), + 36.04365338911715, // Issue #29488 } var vfmodfSC = []float64{ @@ -2158,7 +2161,7 @@ func TestCeil(t *testing.T) { for i := 0; i < len(vf); i++ { - if f := Ceil(vf[i]); ceil[i] != f { + if f := Ceil(vf[i]); !alike(ceil[i], f) { t.Errorf("Ceil(%g) = %g, want %g", vf[i], f, ceil[i]) } } @@ -2385,7 +2388,7 @@ func TestFloor(t *testing.T) { for i := 0; i < len(vf); i++ { - if f := Floor(vf[i]); floor[i] != f { + if f := Floor(vf[i]); !alike(floor[i], f) { t.Errorf("Floor(%g) = %g, want %g", vf[i], f, floor[i]) } } @@ -2916,7 +2919,7 @@ func TestTrunc(t *testing.T) { for i := 0; i < len(vf); i++ { - if f := Trunc(vf[i]); trunc[i] != f { + if f := Trunc(vf[i]); !alike(trunc[i], f) { t.Errorf("Trunc(%g) = %g, want %g", vf[i], f, trunc[i]) } } @@ -3026,6 +3029,41 @@ } } +// Check that trigReduce matches the standard reduction results for input values +// below reduceThreshold. +func TestTrigReduce(t *testing.T) { + inputs := make([]float64, len(vf)) + // all of the standard inputs + copy(inputs, vf) + // all of the large inputs + large := float64(100000 * Pi) + for _, v := range vf { + inputs = append(inputs, v+large) + } + // Also test some special inputs, Pi and right below the reduceThreshold + inputs = append(inputs, Pi, Nextafter(ReduceThreshold, 0)) + for _, x := range inputs { + // reduce the value to compare + j, z := TrigReduce(x) + xred := float64(j)*(Pi/4) + z + + if f, fred := Sin(x), Sin(xred); !close(f, fred) { + t.Errorf("Sin(trigReduce(%g)) != Sin(%g), got %g, want %g", x, x, fred, f) + } + if f, fred := Cos(x), Cos(xred); !close(f, fred) { + t.Errorf("Cos(trigReduce(%g)) != Cos(%g), got %g, want %g", x, x, fred, f) + } + if f, fred := Tan(x), Tan(xred); !close(f, fred) { + t.Errorf(" Tan(trigReduce(%g)) != Tan(%g), got %g, want %g", x, x, fred, f) + } + f, g := Sincos(x) + fred, gred := Sincos(xred) + if !close(f, fred) || !close(g, gred) { + t.Errorf(" Sincos(trigReduce(%g)) != Sincos(%g), got %g, %g, want %g, %g", x, x, fred, gred, f, g) + } + } +} + // Check that math constants are accepted by compiler // and have right value (assumes strconv.ParseFloat works). // https://golang.org/issue/201 @@ -3635,3 +3673,41 @@ } GlobalF = x } + +func BenchmarkFloat64bits(b *testing.B) { + y := uint64(0) + for i := 0; i < b.N; i++ { + y = Float64bits(roundNeg) + } + GlobalI = int(y) +} + +var roundUint64 = uint64(5) + +func BenchmarkFloat64frombits(b *testing.B) { + x := 0.0 + for i := 0; i < b.N; i++ { + x = Float64frombits(roundUint64) + } + GlobalF = x +} + +var roundFloat32 = float32(-2.5) + +func BenchmarkFloat32bits(b *testing.B) { + y := uint32(0) + for i := 0; i < b.N; i++ { + y = Float32bits(roundFloat32) + } + GlobalI = int(y) +} + +var roundUint32 = uint32(5) + +func BenchmarkFloat32frombits(b *testing.B) { + x := float32(0.0) + for i := 0; i < b.N; i++ { + x = Float32frombits(roundUint32) + } + GlobalF = float64(x) +}
diff --git a/src/math/asin_s390x.s b/src/math/asin_s390x.s index fd5ab04..dc54d05 100644 --- a/src/math/asin_s390x.s +++ b/src/math/asin_s390x.s
@@ -46,7 +46,7 @@ TEXT ·asinAsm(SB), NOSPLIT, $0-16 FMOVD x+0(FP), F0 MOVD $·asinrodataL15<>+0(SB), R9 - WORD $0xB3CD0070 //lgdr %r7, %f0 + LGDR F0, R7 FMOVD F0, F8 SRAD $32, R7 WORD $0xC0193FE6 //iilf %r1,1072079005
diff --git a/src/math/asinh_s390x.s b/src/math/asinh_s390x.s index a9cee34..a3680c6 100644 --- a/src/math/asinh_s390x.s +++ b/src/math/asinh_s390x.s
@@ -64,7 +64,7 @@ TEXT ·asinhAsm(SB), NOSPLIT, $0-16 FMOVD x+0(FP), F0 MOVD $·asinhrodataL18<>+0(SB), R9 - WORD $0xB3CD00C0 //lgdr %r12, %f0 + LGDR F0, R12 WORD $0xC0293FDF //iilf %r2,1071644671 BYTE $0xFF BYTE $0xFF @@ -93,7 +93,7 @@ WORD $0xC0398006 //iilf %r3,2147909631 BYTE $0x7F BYTE $0xFF - WORD $0xB3CD0050 //lgdr %r5, %f0 + LGDR F0, R5 SRAD $32, R5 MOVH $0x0, R2 SUBW R5, R3 @@ -133,7 +133,7 @@ WORD $0xC0398006 //iilf %r3,2147909631 BYTE $0x7F BYTE $0xFF - WORD $0xB3CD0050 //lgdr %r5, %f0 + LGDR F0, R5 SRAD $32, R5 MOVH $0x0, R2 SUBW R5, R3 @@ -146,7 +146,7 @@ BYTE $0x59 ORW $0x45000000, R1 L6: - WORD $0xB3C10022 //ldgr %f2,%r2 + LDGR R2, F2 FMOVD 184(R9), F0 WFMADB V8, V2, V0, V8 FMOVD 176(R9), F4
diff --git a/src/math/atan2_s390x.s b/src/math/atan2_s390x.s index f37555b..c7a8a09 100644 --- a/src/math/atan2_s390x.s +++ b/src/math/atan2_s390x.s
@@ -142,8 +142,8 @@ FMOVD x+0(FP), F0 FMOVD y+8(FP), F2 MOVD $·atan2rodataL25<>+0(SB), R9 - WORD $0xB3CD0020 //lgdr %r2,%f0 - WORD $0xB3CD0012 //lgdr %r1,%f2 + LGDR F0, R2 + LGDR F2, R1 WORD $0xEC2220BF //risbgn %r2,%r2,64-32,128+63,64+0+32 BYTE $0x60 BYTE $0x59 @@ -229,7 +229,7 @@ BYTE $0x55 MOVD $·atan2xpi2h<>+0(SB), R1 MOVD ·atan2xpim<>+0(SB), R3 - WORD $0xB3C10003 //ldgr %f0,%r3 + LDGR R3, F0 WORD $0xED021000 //madb %f4,%f0,0(%r2,%r1) BYTE $0x40 BYTE $0x1E
diff --git a/src/math/atan_s390x.s b/src/math/atan_s390x.s index 9f4eaa2..713727d 100644 --- a/src/math/atan_s390x.s +++ b/src/math/atan_s390x.s
@@ -54,7 +54,7 @@ MOVD $·atanrodataL8<>+0(SB), R5 MOVH $0x3FE0, R3 - WORD $0xB3CD0010 //lgdr %r1,%f0 + LGDR F0, R1 WORD $0xEC1120BF //risbgn %r1,%r1,64-32,128+63,64+0+32 BYTE $0x60 BYTE $0x59
diff --git a/src/math/atanh_s390x.s b/src/math/atanh_s390x.s index 57b61a3..e7c6359 100644 --- a/src/math/atanh_s390x.s +++ b/src/math/atanh_s390x.s
@@ -64,7 +64,7 @@ TEXT ·atanhAsm(SB), NOSPLIT, $0-16 FMOVD x+0(FP), F0 MOVD $·atanhrodataL10<>+0(SB), R5 - WORD $0xB3CD0010 //lgdr %r1, %f0 + LGDR F0, R1 WORD $0xC0393FEF //iilf %r3,1072693247 BYTE $0xFF BYTE $0xFF @@ -128,7 +128,7 @@ WORD $0xED405088 //adb %f4,.L12-.L10(%r5) BYTE $0x00 BYTE $0x1A - WORD $0xB3CD0044 //lgdr %r4, %f4 + LGDR F4, R4 SRAD $32, R4 FMOVD F4, F3 WORD $0xED305088 //sdb %f3,.L12-.L10(%r5) @@ -140,7 +140,7 @@ BYTE $0x00 BYTE $0x55 SLD $32, R1, R1 - WORD $0xB3C10021 //ldgr %f2,%r1 + LDGR R1, F2 WFMADB V4, V2, V16, V4 SRAW $8, R2, R1 WFMADB V4, V5, V6, V5
diff --git a/src/math/big/arith.go b/src/math/big/arith.go index ad35240..f9db911 100644 --- a/src/math/big/arith.go +++ b/src/math/big/arith.go
@@ -82,7 +82,7 @@ return uint(bits.LeadingZeros(uint(x))) } -// q = (u1<<_W + u0 - r)/y +// q = (u1<<_W + u0 - r)/v // Adapted from Warren, Hacker's Delight, p. 152. func divWW_g(u1, u0, v Word) (q, r Word) { if u1 >= v {
diff --git a/src/math/big/arith_386.s b/src/math/big/arith_386.s index 6c080f0..864fbc5 100644 --- a/src/math/big/arith_386.s +++ b/src/math/big/arith_386.s
@@ -183,7 +183,7 @@ SHRL CX, DX:AX // w>>s | w1<<ŝ MOVL DX, (DI)(BX*4) // z[i] = w>>s | w1<<ŝ ADDL $1, BX // i++ - + E9: CMPL BX, BP JL L9 // i < n-1
diff --git a/src/math/big/arith_amd64.s b/src/math/big/arith_amd64.s index 1b950a4..e9c8887 100644 --- a/src/math/big/arith_amd64.s +++ b/src/math/big/arith_amd64.s
@@ -324,10 +324,10 @@ MOVQ r+56(FP), CX // c = r MOVQ z_len+8(FP), R11 MOVQ $0, BX // i = 0 - + CMPQ R11, $4 JL E5 - + U5: // i+4 <= n // regular loop body unrolled 4x MOVQ (0*8)(R8)(BX*8), AX @@ -355,7 +355,7 @@ MOVQ AX, (3*8)(R10)(BX*8) MOVQ DX, CX ADDQ $4, BX // i += 4 - + LEAQ 4(BX), DX CMPQ DX, R11 JLE U5
diff --git a/src/math/big/arith_arm.s b/src/math/big/arith_arm.s index ba65fd2..33aa36f 100644 --- a/src/math/big/arith_arm.s +++ b/src/math/big/arith_arm.s
@@ -123,7 +123,7 @@ MOVW z_len+4(FP), R5 TEQ $0, R5 BEQ X7 - + MOVW z+0(FP), R1 MOVW x+12(FP), R2 ADD R5<<2, R2, R2 @@ -135,7 +135,7 @@ MOVW $32, R4 SUB R3, R4 MOVW $0, R7 - + MOVW.W -4(R2), R6 MOVW R6<<R3, R7 MOVW R6>>R4, R6
diff --git a/src/math/big/arith_s390x.s b/src/math/big/arith_s390x.s index 4520d16..9156d9d 100644 --- a/src/math/big/arith_s390x.s +++ b/src/math/big/arith_s390x.s
@@ -54,7 +54,7 @@ TEXT ·addVV(SB),NOSPLIT,$0 MOVD addvectorfacility+0x00(SB),R1 BR (R1) - + TEXT ·addVV_check(SB),NOSPLIT, $0 MOVB ·hasVX(SB), R1 CMPBEQ R1, $1, vectorimpl // vectorfacility = 1, vector supported @@ -89,7 +89,7 @@ BLT v1 SUB $12, R3 // n -= 16 BLT A1 // if n < 0 goto A1 - + MOVD R8, R5 MOVD R9, R6 MOVD R2, R7 @@ -291,7 +291,7 @@ TEXT ·subVV(SB),NOSPLIT,$0 MOVD subvectorfacility+0x00(SB),R1 BR (R1) - + TEXT ·subVV_check(SB),NOSPLIT,$0 MOVB ·hasVX(SB), R1 CMPBEQ R1, $1, vectorimpl // vectorfacility = 1, vector supported @@ -321,7 +321,7 @@ MOVD $0, R4 // c = 0 MOVD $0, R0 // make sure it's zero MOVD $0, R10 // i = 0 - + // s/JL/JMP/ below to disable the unrolled loop SUB $4, R3 // n -= 4 BLT v1 // if n < 0 goto v1 @@ -413,7 +413,7 @@ A1: ADD $12, R3 // n += 16 BLT v1 // if n < 0 goto v1 - + U1: // n >= 0 // regular loop body unrolled 4x MOVD 0(R8)(R10*1), R5 @@ -532,7 +532,7 @@ TEXT ·addVW(SB),NOSPLIT,$0 MOVD addwvectorfacility+0x00(SB),R1 BR (R1) - + TEXT ·addVW_check(SB),NOSPLIT,$0 MOVB ·hasVX(SB), R1 CMPBEQ R1, $1, vectorimpl // vectorfacility = 1, vector supported @@ -742,7 +742,7 @@ TEXT ·subVW(SB),NOSPLIT,$0 MOVD subwvectorfacility+0x00(SB),R1 BR (R1) - + TEXT ·subVW_check(SB),NOSPLIT,$0 MOVB ·hasVX(SB), R1 CMPBEQ R1, $1, vectorimpl // vectorfacility = 1, vector supported
diff --git a/src/math/big/float.go b/src/math/big/float.go index 55b93c8..b3c3295 100644 --- a/src/math/big/float.go +++ b/src/math/big/float.go
@@ -43,7 +43,7 @@ // precision of the argument with the largest precision value before any // rounding takes place, and the rounding mode remains unchanged. Thus, // uninitialized Floats provided as result arguments will have their -// precision set to a reasonable value determined by the operands and +// precision set to a reasonable value determined by the operands, and // their mode is the zero value for RoundingMode (ToNearestEven). // // By setting the desired precision to 24 or 53 and using matching rounding @@ -56,6 +56,12 @@ // The zero (uninitialized) value for a Float is ready to use and represents // the number +0.0 exactly, with precision 0 and rounding mode ToNearestEven. // +// Operations always take pointer arguments (*Float) rather +// than Float values, and each unique Float value requires +// its own unique *Float pointer. To "copy" a Float value, +// an existing (or newly allocated) Float must be set to +// a new value using the Float.Set method; shallow copies +// of Floats are not supported and may lead to errors. type Float struct { prec uint32 mode RoundingMode @@ -293,7 +299,7 @@ z.round(sbit) } -// SetMantExp sets z to mant × 2**exp and and returns z. +// SetMantExp sets z to mant × 2**exp and returns z. // The result z has the same precision and rounding mode // as mant. SetMantExp is an inverse of MantExp but does // not require 0.5 <= |mant| < 1.0. Specifically: @@ -321,7 +327,7 @@ return z } -// Signbit returns true if x is negative or negative zero. +// Signbit reports whether x is negative or negative zero. func (x *Float) Signbit() bool { return x.neg }
diff --git a/src/math/big/int.go b/src/math/big/int.go index 47a288a..dab9a5c 100644 --- a/src/math/big/int.go +++ b/src/math/big/int.go
@@ -15,6 +15,13 @@ // An Int represents a signed multi-precision integer. // The zero value for an Int represents the value 0. +// +// Operations always take pointer arguments (*Int) rather +// than Int values, and each unique Int value requires +// its own unique *Int pointer. To "copy" an Int value, +// an existing (or newly allocated) Int must be set to +// a new value using the Int.Set method; shallow copies +// of Ints are not supported and may lead to errors. type Int struct { neg bool // sign abs nat // absolute value of the integer
diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go index 9930ed0..7ef2b39 100644 --- a/src/math/big/int_test.go +++ b/src/math/big/int_test.go
@@ -1727,3 +1727,29 @@ }) } } + +func benchmarkDiv(b *testing.B, aSize, bSize int) { + var r = rand.New(rand.NewSource(1234)) + aa := randInt(r, uint(aSize)) + bb := randInt(r, uint(bSize)) + if aa.Cmp(bb) < 0 { + aa, bb = bb, aa + } + x := new(Int) + y := new(Int) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + x.DivMod(aa, bb, y) + } +} + +func BenchmarkDiv(b *testing.B) { + min, max, step := 10, 100000, 10 + for i := min; i <= max; i *= step { + j := 2 * i + b.Run(fmt.Sprintf("%d/%d", j, i), func(b *testing.B) { + benchmarkDiv(b, j, i) + }) + } +}
diff --git a/src/math/big/nat.go b/src/math/big/nat.go index a6f79ed..1e4a3b0 100644 --- a/src/math/big/nat.go +++ b/src/math/big/nat.go
@@ -58,6 +58,10 @@ if n <= cap(z) { return z[:n] // reuse z } + if n == 1 { + // Most nats start small and stay that way; don't over-allocate. + return make(nat, 1) + } // Choosing a good value for e has significant performance impact // because it increases the chance that a value can be reused. const e = 4 // extra capacity @@ -680,43 +684,36 @@ var natPool sync.Pool -// q = (uIn-r)/v, with 0 <= r < y +// q = (uIn-r)/vIn, with 0 <= r < y // Uses z as storage for q, and u as storage for r if possible. // See Knuth, Volume 2, section 4.3.1, Algorithm D. // Preconditions: -// len(v) >= 2 -// len(uIn) >= len(v) -func (z nat) divLarge(u, uIn, v nat) (q, r nat) { - n := len(v) +// len(vIn) >= 2 +// len(uIn) >= len(vIn) +// u must not alias z +func (z nat) divLarge(u, uIn, vIn nat) (q, r nat) { + n := len(vIn) m := len(uIn) - n - // determine if z can be reused - // TODO(gri) should find a better solution - this if statement - // is very costly (see e.g. time pidigits -s -n 10000) - if alias(z, u) || alias(z, uIn) || alias(z, v) { - z = nil // z is an alias for u or uIn or v - cannot reuse + // D1. + shift := nlz(vIn[n-1]) + // do not modify vIn, it may be used by another goroutine simultaneously + vp := getNat(n) + v := *vp + shlVU(v, vIn, shift) + + // u may safely alias uIn or vIn, the value of uIn is used to set u and vIn was already used + u = u.make(len(uIn) + 1) + u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift) + + // z may safely alias uIn or vIn, both values were used already + if alias(z, u) { + z = nil // z is an alias for u - cannot reuse } q = z.make(m + 1) qhatvp := getNat(n + 1) qhatv := *qhatvp - if alias(u, uIn) || alias(u, v) { - u = nil // u is an alias for uIn or v - cannot reuse - } - u = u.make(len(uIn) + 1) - u.clear() // TODO(gri) no need to clear if we allocated a new u - - // D1. - var v1p *nat - shift := nlz(v[n-1]) - if shift > 0 { - // do not modify v, it may be used by another goroutine simultaneously - v1p = getNat(n) - v1 := *v1p - shlVU(v1, v, shift) - v = v1 - } - u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift) // D2. vn1 := v[n-1] @@ -756,9 +753,8 @@ q[j] = qhat } - if v1p != nil { - putNat(v1p) - } + + putNat(vp) putNat(qhatvp) q = q.norm()
diff --git a/src/math/big/prime.go b/src/math/big/prime.go index 4c2c152..d9a5f1e 100644 --- a/src/math/big/prime.go +++ b/src/math/big/prime.go
@@ -51,7 +51,7 @@ } if w&1 == 0 { - return false // n is even + return false // x is even } const primesA = 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 37
diff --git a/src/math/big/rat.go b/src/math/big/rat.go index 46d58fc..5d0800c 100644 --- a/src/math/big/rat.go +++ b/src/math/big/rat.go
@@ -13,6 +13,13 @@ // A Rat represents a quotient a/b of arbitrary precision. // The zero value for a Rat represents the value 0. +// +// Operations always take pointer arguments (*Rat) rather +// than Rat values, and each unique Rat value requires +// its own unique *Rat pointer. To "copy" a Rat value, +// an existing (or newly allocated) Rat must be set to +// a new value using the Rat.Set method; shallow copies +// of Rats are not supported and may lead to errors. type Rat struct { // To make zero values for Rat work w/o initialization, // a zero value of b (len(b) == 0) acts like b == 1.
diff --git a/src/math/big/ratconv.go b/src/math/big/ratconv.go index 157d8d0..5656280 100644 --- a/src/math/big/ratconv.go +++ b/src/math/big/ratconv.go
@@ -38,8 +38,8 @@ } // SetString sets z to the value of s and returns z and a boolean indicating -// success. s can be given as a fraction "a/b" or as a floating-point number -// optionally followed by an exponent. The entire string (not just a prefix) +// success. s can be given as a fraction "a/b" or as a decimal floating-point +// number optionally followed by an exponent. The entire string (not just a prefix) // must be valid for success. If the operation failed, the value of z is // undefined but the returned value is nil. func (z *Rat) SetString(s string) (*Rat, bool) { @@ -78,6 +78,7 @@ } // mantissa + // TODO(gri) allow other bases besides 10 for mantissa and exponent? (issue #29799) var ecorr int z.a.abs, _, ecorr, err = z.a.abs.scan(r, 10, true) if err != nil {
diff --git a/src/math/big/sqrt.go b/src/math/big/sqrt.go index b989649..53403aa 100644 --- a/src/math/big/sqrt.go +++ b/src/math/big/sqrt.go
@@ -7,8 +7,6 @@ import "math" var ( - half = NewFloat(0.5) - two = NewFloat(2.0) three = NewFloat(3.0) ) @@ -57,9 +55,9 @@ case 0: // nothing to do case 1: - z.Mul(two, z) + z.exp++ case -1: - z.Mul(half, z) + z.exp-- } // 0.25 <= z < 2.0 @@ -96,7 +94,7 @@ u.prec = t.prec u.Mul(t, t) // u = t² u.Add(u, x) // = t² + x - u.Mul(half, u) // = ½(t² + x) + u.exp-- // = ½(t² + x) return t.Quo(u, t) // = ½(t² + x)/t } @@ -133,11 +131,13 @@ ng := func(t *Float) *Float { u.prec = t.prec v.prec = t.prec - u.Mul(t, t) // u = t² - u.Mul(x, u) // = xt² - v.Sub(three, u) // v = 3 - xt² - u.Mul(t, v) // u = t(3 - xt²) - return t.Mul(half, u) // = ½t(3 - xt²) + u.Mul(t, t) // u = t² + u.Mul(x, u) // = xt² + v.Sub(three, u) // v = 3 - xt² + u.Mul(t, v) // u = t(3 - xt²) + u.exp-- // = ½t(3 - xt²) + return t.Set(u) + } xf, _ := x.Float64()
diff --git a/src/math/bits/bits.go b/src/math/bits/bits.go index 989baac..b06c363 100644 --- a/src/math/bits/bits.go +++ b/src/math/bits/bits.go
@@ -8,6 +8,8 @@ // functions for the predeclared unsigned integer types. package bits +import _ "unsafe" // for go:linkname + const uintSize = 32 << (^uint(0) >> 32 & 1) // 32 or 64 // UintSize is the size of a uint in bits. @@ -63,7 +65,7 @@ } // TrailingZeros16 returns the number of trailing zero bits in x; the result is 16 for x == 0. -func TrailingZeros16(x uint16) (n int) { +func TrailingZeros16(x uint16) int { if x == 0 { return 16 } @@ -328,3 +330,206 @@ } return n + int(len8tab[x]) } + +// --- Add with carry --- + +// Add returns the sum with carry of x, y and carry: sum = x + y + carry. +// The carry input must be 0 or 1; otherwise the behavior is undefined. +// The carryOut output is guaranteed to be 0 or 1. +func Add(x, y, carry uint) (sum, carryOut uint) { + yc := y + carry + sum = x + yc + if sum < x || yc < y { + carryOut = 1 + } + return +} + +// Add32 returns the sum with carry of x, y and carry: sum = x + y + carry. +// The carry input must be 0 or 1; otherwise the behavior is undefined. +// The carryOut output is guaranteed to be 0 or 1. +func Add32(x, y, carry uint32) (sum, carryOut uint32) { + yc := y + carry + sum = x + yc + if sum < x || yc < y { + carryOut = 1 + } + return +} + +// Add64 returns the sum with carry of x, y and carry: sum = x + y + carry. +// The carry input must be 0 or 1; otherwise the behavior is undefined. +// The carryOut output is guaranteed to be 0 or 1. +func Add64(x, y, carry uint64) (sum, carryOut uint64) { + yc := y + carry + sum = x + yc + if sum < x || yc < y { + carryOut = 1 + } + return +} + +// --- Subtract with borrow --- + +// Sub returns the difference of x, y and borrow: diff = x - y - borrow. +// The borrow input must be 0 or 1; otherwise the behavior is undefined. +// The borrowOut output is guaranteed to be 0 or 1. +func Sub(x, y, borrow uint) (diff, borrowOut uint) { + yb := y + borrow + diff = x - yb + if diff > x || yb < y { + borrowOut = 1 + } + return +} + +// Sub32 returns the difference of x, y and borrow, diff = x - y - borrow. +// The borrow input must be 0 or 1; otherwise the behavior is undefined. +// The borrowOut output is guaranteed to be 0 or 1. +func Sub32(x, y, borrow uint32) (diff, borrowOut uint32) { + yb := y + borrow + diff = x - yb + if diff > x || yb < y { + borrowOut = 1 + } + return +} + +// Sub64 returns the difference of x, y and borrow: diff = x - y - borrow. +// The borrow input must be 0 or 1; otherwise the behavior is undefined. +// The borrowOut output is guaranteed to be 0 or 1. +func Sub64(x, y, borrow uint64) (diff, borrowOut uint64) { + yb := y + borrow + diff = x - yb + if diff > x || yb < y { + borrowOut = 1 + } + return +} + +// --- Full-width multiply --- + +// Mul returns the full-width product of x and y: (hi, lo) = x * y +// with the product bits' upper half returned in hi and the lower +// half returned in lo. +func Mul(x, y uint) (hi, lo uint) { + if UintSize == 32 { + h, l := Mul32(uint32(x), uint32(y)) + return uint(h), uint(l) + } + h, l := Mul64(uint64(x), uint64(y)) + return uint(h), uint(l) +} + +// Mul32 returns the 64-bit product of x and y: (hi, lo) = x * y +// with the product bits' upper half returned in hi and the lower +// half returned in lo. +func Mul32(x, y uint32) (hi, lo uint32) { + tmp := uint64(x) * uint64(y) + hi, lo = uint32(tmp>>32), uint32(tmp) + return +} + +// Mul64 returns the 128-bit product of x and y: (hi, lo) = x * y +// with the product bits' upper half returned in hi and the lower +// half returned in lo. +func Mul64(x, y uint64) (hi, lo uint64) { + const mask32 = 1<<32 - 1 + x0 := x & mask32 + x1 := x >> 32 + y0 := y & mask32 + y1 := y >> 32 + w0 := x0 * y0 + t := x1*y0 + w0>>32 + w1 := t & mask32 + w2 := t >> 32 + w1 += x0 * y1 + hi = x1*y1 + w2 + w1>>32 + lo = x * y + return +} + +// --- Full-width divide --- + +// Div returns the quotient and remainder of (hi, lo) divided by y: +// quo = (hi, lo)/y, rem = (hi, lo)%y with the dividend bits' upper +// half in parameter hi and the lower half in parameter lo. +// Div panics for y == 0 (division by zero) or y <= hi (quotient overflow). +func Div(hi, lo, y uint) (quo, rem uint) { + if UintSize == 32 { + q, r := Div32(uint32(hi), uint32(lo), uint32(y)) + return uint(q), uint(r) + } + q, r := Div64(uint64(hi), uint64(lo), uint64(y)) + return uint(q), uint(r) +} + +// Div32 returns the quotient and remainder of (hi, lo) divided by y: +// quo = (hi, lo)/y, rem = (hi, lo)%y with the dividend bits' upper +// half in parameter hi and the lower half in parameter lo. +// Div32 panics for y == 0 (division by zero) or y <= hi (quotient overflow). +func Div32(hi, lo, y uint32) (quo, rem uint32) { + if y != 0 && y <= hi { + panic(overflowError) + } + z := uint64(hi)<<32 | uint64(lo) + quo, rem = uint32(z/uint64(y)), uint32(z%uint64(y)) + return +} + +// Div64 returns the quotient and remainder of (hi, lo) divided by y: +// quo = (hi, lo)/y, rem = (hi, lo)%y with the dividend bits' upper +// half in parameter hi and the lower half in parameter lo. +// Div64 panics for y == 0 (division by zero) or y <= hi (quotient overflow). +func Div64(hi, lo, y uint64) (quo, rem uint64) { + const ( + two32 = 1 << 32 + mask32 = two32 - 1 + ) + if y == 0 { + panic(divideError) + } + if y <= hi { + panic(overflowError) + } + + s := uint(LeadingZeros64(y)) + y <<= s + + yn1 := y >> 32 + yn0 := y & mask32 + un32 := hi<<s | lo>>(64-s) + un10 := lo << s + un1 := un10 >> 32 + un0 := un10 & mask32 + q1 := un32 / yn1 + rhat := un32 - q1*yn1 + + for q1 >= two32 || q1*yn0 > two32*rhat+un1 { + q1-- + rhat += yn1 + if rhat >= two32 { + break + } + } + + un21 := un32*two32 + un1 - q1*y + q0 := un21 / yn1 + rhat = un21 - q0*yn1 + + for q0 >= two32 || q0*yn0 > two32*rhat+un0 { + q0-- + rhat += yn1 + if rhat >= two32 { + break + } + } + + return q1*two32 + q0, (un21*two32 + un0 - q0*y) >> s +} + +//go:linkname overflowError runtime.overflowError +var overflowError error + +//go:linkname divideError runtime.divideError +var divideError error
diff --git a/src/math/bits/bits_test.go b/src/math/bits/bits_test.go index 5c34f6d..1ec5107 100644 --- a/src/math/bits/bits_test.go +++ b/src/math/bits/bits_test.go
@@ -6,6 +6,7 @@ import ( . "math/bits" + "runtime" "testing" "unsafe" ) @@ -705,6 +706,385 @@ } } +const ( + _M = 1<<UintSize - 1 + _M32 = 1<<32 - 1 + _M64 = 1<<64 - 1 +) + +func TestAddSubUint(t *testing.T) { + test := func(msg string, f func(x, y, c uint) (z, cout uint), x, y, c, z, cout uint) { + z1, cout1 := f(x, y, c) + if z1 != z || cout1 != cout { + t.Errorf("%s: got z:cout = %#x:%#x; want %#x:%#x", msg, z1, cout1, z, cout) + } + } + for _, a := range []struct{ x, y, c, z, cout uint }{ + {0, 0, 0, 0, 0}, + {0, 1, 0, 1, 0}, + {0, 0, 1, 1, 0}, + {0, 1, 1, 2, 0}, + {12345, 67890, 0, 80235, 0}, + {12345, 67890, 1, 80236, 0}, + {_M, 1, 0, 0, 1}, + {_M, 0, 1, 0, 1}, + {_M, 1, 1, 1, 1}, + {_M, _M, 0, _M - 1, 1}, + {_M, _M, 1, _M, 1}, + } { + test("Add", Add, a.x, a.y, a.c, a.z, a.cout) + test("Add symmetric", Add, a.y, a.x, a.c, a.z, a.cout) + test("Sub", Sub, a.z, a.x, a.c, a.y, a.cout) + test("Sub symmetric", Sub, a.z, a.y, a.c, a.x, a.cout) + } +} + +func TestAddSubUint32(t *testing.T) { + test := func(msg string, f func(x, y, c uint32) (z, cout uint32), x, y, c, z, cout uint32) { + z1, cout1 := f(x, y, c) + if z1 != z || cout1 != cout { + t.Errorf("%s: got z:cout = %#x:%#x; want %#x:%#x", msg, z1, cout1, z, cout) + } + } + for _, a := range []struct{ x, y, c, z, cout uint32 }{ + {0, 0, 0, 0, 0}, + {0, 1, 0, 1, 0}, + {0, 0, 1, 1, 0}, + {0, 1, 1, 2, 0}, + {12345, 67890, 0, 80235, 0}, + {12345, 67890, 1, 80236, 0}, + {_M32, 1, 0, 0, 1}, + {_M32, 0, 1, 0, 1}, + {_M32, 1, 1, 1, 1}, + {_M32, _M32, 0, _M32 - 1, 1}, + {_M32, _M32, 1, _M32, 1}, + } { + test("Add32", Add32, a.x, a.y, a.c, a.z, a.cout) + test("Add32 symmetric", Add32, a.y, a.x, a.c, a.z, a.cout) + test("Sub32", Sub32, a.z, a.x, a.c, a.y, a.cout) + test("Sub32 symmetric", Sub32, a.z, a.y, a.c, a.x, a.cout) + } +} + +func TestAddSubUint64(t *testing.T) { + test := func(msg string, f func(x, y, c uint64) (z, cout uint64), x, y, c, z, cout uint64) { + z1, cout1 := f(x, y, c) + if z1 != z || cout1 != cout { + t.Errorf("%s: got z:cout = %#x:%#x; want %#x:%#x", msg, z1, cout1, z, cout) + } + } + for _, a := range []struct{ x, y, c, z, cout uint64 }{ + {0, 0, 0, 0, 0}, + {0, 1, 0, 1, 0}, + {0, 0, 1, 1, 0}, + {0, 1, 1, 2, 0}, + {12345, 67890, 0, 80235, 0}, + {12345, 67890, 1, 80236, 0}, + {_M64, 1, 0, 0, 1}, + {_M64, 0, 1, 0, 1}, + {_M64, 1, 1, 1, 1}, + {_M64, _M64, 0, _M64 - 1, 1}, + {_M64, _M64, 1, _M64, 1}, + } { + test("Add64", Add64, a.x, a.y, a.c, a.z, a.cout) + test("Add64 symmetric", Add64, a.y, a.x, a.c, a.z, a.cout) + test("Sub64", Sub64, a.z, a.x, a.c, a.y, a.cout) + test("Sub64 symmetric", Sub64, a.z, a.y, a.c, a.x, a.cout) + } +} + +func TestMulDiv(t *testing.T) { + testMul := func(msg string, f func(x, y uint) (hi, lo uint), x, y, hi, lo uint) { + hi1, lo1 := f(x, y) + if hi1 != hi || lo1 != lo { + t.Errorf("%s: got hi:lo = %#x:%#x; want %#x:%#x", msg, hi1, lo1, hi, lo) + } + } + testDiv := func(msg string, f func(hi, lo, y uint) (q, r uint), hi, lo, y, q, r uint) { + q1, r1 := f(hi, lo, y) + if q1 != q || r1 != r { + t.Errorf("%s: got q:r = %#x:%#x; want %#x:%#x", msg, q1, r1, q, r) + } + } + for _, a := range []struct { + x, y uint + hi, lo, r uint + }{ + {1 << (UintSize - 1), 2, 1, 0, 1}, + {_M, _M, _M - 1, 1, 42}, + } { + testMul("Mul", Mul, a.x, a.y, a.hi, a.lo) + testMul("Mul symmetric", Mul, a.y, a.x, a.hi, a.lo) + testDiv("Div", Div, a.hi, a.lo+a.r, a.y, a.x, a.r) + testDiv("Div symmetric", Div, a.hi, a.lo+a.r, a.x, a.y, a.r) + } +} + +func TestMulDiv32(t *testing.T) { + testMul := func(msg string, f func(x, y uint32) (hi, lo uint32), x, y, hi, lo uint32) { + hi1, lo1 := f(x, y) + if hi1 != hi || lo1 != lo { + t.Errorf("%s: got hi:lo = %#x:%#x; want %#x:%#x", msg, hi1, lo1, hi, lo) + } + } + testDiv := func(msg string, f func(hi, lo, y uint32) (q, r uint32), hi, lo, y, q, r uint32) { + q1, r1 := f(hi, lo, y) + if q1 != q || r1 != r { + t.Errorf("%s: got q:r = %#x:%#x; want %#x:%#x", msg, q1, r1, q, r) + } + } + for _, a := range []struct { + x, y uint32 + hi, lo, r uint32 + }{ + {1 << 31, 2, 1, 0, 1}, + {0xc47dfa8c, 50911, 0x98a4, 0x998587f4, 13}, + {_M32, _M32, _M32 - 1, 1, 42}, + } { + testMul("Mul32", Mul32, a.x, a.y, a.hi, a.lo) + testMul("Mul32 symmetric", Mul32, a.y, a.x, a.hi, a.lo) + testDiv("Div32", Div32, a.hi, a.lo+a.r, a.y, a.x, a.r) + testDiv("Div32 symmetric", Div32, a.hi, a.lo+a.r, a.x, a.y, a.r) + } +} + +func TestMulDiv64(t *testing.T) { + testMul := func(msg string, f func(x, y uint64) (hi, lo uint64), x, y, hi, lo uint64) { + hi1, lo1 := f(x, y) + if hi1 != hi || lo1 != lo { + t.Errorf("%s: got hi:lo = %#x:%#x; want %#x:%#x", msg, hi1, lo1, hi, lo) + } + } + testDiv := func(msg string, f func(hi, lo, y uint64) (q, r uint64), hi, lo, y, q, r uint64) { + q1, r1 := f(hi, lo, y) + if q1 != q || r1 != r { + t.Errorf("%s: got q:r = %#x:%#x; want %#x:%#x", msg, q1, r1, q, r) + } + } + for _, a := range []struct { + x, y uint64 + hi, lo, r uint64 + }{ + {1 << 63, 2, 1, 0, 1}, + {0x3626229738a3b9, 0xd8988a9f1cc4a61, 0x2dd0712657fe8, 0x9dd6a3364c358319, 13}, + {_M64, _M64, _M64 - 1, 1, 42}, + } { + testMul("Mul64", Mul64, a.x, a.y, a.hi, a.lo) + testMul("Mul64 symmetric", Mul64, a.y, a.x, a.hi, a.lo) + testDiv("Div64", Div64, a.hi, a.lo+a.r, a.y, a.x, a.r) + testDiv("Div64 symmetric", Div64, a.hi, a.lo+a.r, a.x, a.y, a.r) + } +} + +const ( + divZeroError = "runtime error: integer divide by zero" + overflowError = "runtime error: integer overflow" +) + +func TestDivPanicOverflow(t *testing.T) { + // Expect a panic + defer func() { + if err := recover(); err == nil { + t.Error("Div should have panicked when y<=hi") + } else if e, ok := err.(runtime.Error); !ok || e.Error() != overflowError { + t.Errorf("Div expected panic: %q, got: %q ", overflowError, e.Error()) + } + }() + q, r := Div(1, 0, 1) + t.Errorf("undefined q, r = %v, %v calculated when Div should have panicked", q, r) +} + +func TestDiv32PanicOverflow(t *testing.T) { + // Expect a panic + defer func() { + if err := recover(); err == nil { + t.Error("Div32 should have panicked when y<=hi") + } else if e, ok := err.(runtime.Error); !ok || e.Error() != overflowError { + t.Errorf("Div32 expected panic: %q, got: %q ", overflowError, e.Error()) + } + }() + q, r := Div32(1, 0, 1) + t.Errorf("undefined q, r = %v, %v calculated when Div32 should have panicked", q, r) +} + +func TestDiv64PanicOverflow(t *testing.T) { + // Expect a panic + defer func() { + if err := recover(); err == nil { + t.Error("Div64 should have panicked when y<=hi") + } else if e, ok := err.(runtime.Error); !ok || e.Error() != overflowError { + t.Errorf("Div64 expected panic: %q, got: %q ", overflowError, e.Error()) + } + }() + q, r := Div64(1, 0, 1) + t.Errorf("undefined q, r = %v, %v calculated when Div64 should have panicked", q, r) +} + +func TestDivPanicZero(t *testing.T) { + // Expect a panic + defer func() { + if err := recover(); err == nil { + t.Error("Div should have panicked when y==0") + } else if e, ok := err.(runtime.Error); !ok || e.Error() != divZeroError { + t.Errorf("Div expected panic: %q, got: %q ", divZeroError, e.Error()) + } + }() + q, r := Div(1, 1, 0) + t.Errorf("undefined q, r = %v, %v calculated when Div should have panicked", q, r) +} + +func TestDiv32PanicZero(t *testing.T) { + // Expect a panic + defer func() { + if err := recover(); err == nil { + t.Error("Div32 should have panicked when y==0") + } else if e, ok := err.(runtime.Error); !ok || e.Error() != divZeroError { + t.Errorf("Div32 expected panic: %q, got: %q ", divZeroError, e.Error()) + } + }() + q, r := Div32(1, 1, 0) + t.Errorf("undefined q, r = %v, %v calculated when Div32 should have panicked", q, r) +} + +func TestDiv64PanicZero(t *testing.T) { + // Expect a panic + defer func() { + if err := recover(); err == nil { + t.Error("Div64 should have panicked when y==0") + } else if e, ok := err.(runtime.Error); !ok || e.Error() != divZeroError { + t.Errorf("Div64 expected panic: %q, got: %q ", divZeroError, e.Error()) + } + }() + q, r := Div64(1, 1, 0) + t.Errorf("undefined q, r = %v, %v calculated when Div64 should have panicked", q, r) +} + +func BenchmarkAdd(b *testing.B) { + var z, c uint + for i := 0; i < b.N; i++ { + z, c = Add(uint(Input), uint(i), c) + } + Output = int(z + c) +} + +func BenchmarkAdd32(b *testing.B) { + var z, c uint32 + for i := 0; i < b.N; i++ { + z, c = Add32(uint32(Input), uint32(i), c) + } + Output = int(z + c) +} + +func BenchmarkAdd64(b *testing.B) { + var z, c uint64 + for i := 0; i < b.N; i++ { + z, c = Add64(uint64(Input), uint64(i), c) + } + Output = int(z + c) +} + +func BenchmarkAdd64multiple(b *testing.B) { + var z0 = uint64(Input) + var z1 = uint64(Input) + var z2 = uint64(Input) + var z3 = uint64(Input) + for i := 0; i < b.N; i++ { + var c uint64 + z0, c = Add64(z0, uint64(i), c) + z1, c = Add64(z1, uint64(i), c) + z2, c = Add64(z2, uint64(i), c) + z3, _ = Add64(z3, uint64(i), c) + } + Output = int(z0 + z1 + z2 + z3) +} + +func BenchmarkSub(b *testing.B) { + var z, c uint + for i := 0; i < b.N; i++ { + z, c = Sub(uint(Input), uint(i), c) + } + Output = int(z + c) +} + +func BenchmarkSub32(b *testing.B) { + var z, c uint32 + for i := 0; i < b.N; i++ { + z, c = Sub32(uint32(Input), uint32(i), c) + } + Output = int(z + c) +} + +func BenchmarkSub64(b *testing.B) { + var z, c uint64 + for i := 0; i < b.N; i++ { + z, c = Sub64(uint64(Input), uint64(i), c) + } + Output = int(z + c) +} + +func BenchmarkSub64multiple(b *testing.B) { + var z0 = uint64(Input) + var z1 = uint64(Input) + var z2 = uint64(Input) + var z3 = uint64(Input) + for i := 0; i < b.N; i++ { + var c uint64 + z0, c = Sub64(z0, uint64(i), c) + z1, c = Sub64(z1, uint64(i), c) + z2, c = Sub64(z2, uint64(i), c) + z3, _ = Sub64(z3, uint64(i), c) + } + Output = int(z0 + z1 + z2 + z3) +} + +func BenchmarkMul(b *testing.B) { + var hi, lo uint + for i := 0; i < b.N; i++ { + hi, lo = Mul(uint(Input), uint(i)) + } + Output = int(hi + lo) +} + +func BenchmarkMul32(b *testing.B) { + var hi, lo uint32 + for i := 0; i < b.N; i++ { + hi, lo = Mul32(uint32(Input), uint32(i)) + } + Output = int(hi + lo) +} + +func BenchmarkMul64(b *testing.B) { + var hi, lo uint64 + for i := 0; i < b.N; i++ { + hi, lo = Mul64(uint64(Input), uint64(i)) + } + Output = int(hi + lo) +} + +func BenchmarkDiv(b *testing.B) { + var q, r uint + for i := 0; i < b.N; i++ { + q, r = Div(1, uint(i), uint(Input)) + } + Output = int(q + r) +} + +func BenchmarkDiv32(b *testing.B) { + var q, r uint32 + for i := 0; i < b.N; i++ { + q, r = Div32(1, uint32(i), uint32(Input)) + } + Output = int(q + r) +} + +func BenchmarkDiv64(b *testing.B) { + var q, r uint64 + for i := 0; i < b.N; i++ { + q, r = Div64(1, uint64(i), uint64(Input)) + } + Output = int(q + r) +} + // ---------------------------------------------------------------------------- // Testing support
diff --git a/src/math/cbrt_s390x.s b/src/math/cbrt_s390x.s index 85a2fcb..d79b48f 100644 --- a/src/math/cbrt_s390x.s +++ b/src/math/cbrt_s390x.s
@@ -77,7 +77,7 @@ TEXT ·cbrtAsm(SB), NOSPLIT, $0-16 FMOVD x+0(FP), F0 MOVD $·cbrtrodataL9<>+0(SB), R9 - WORD $0xB3CD0020 //lgdr %r2, %f0 + LGDR F0, R2 WORD $0xC039000F //iilf %r3,1048575 BYTE $0xFF BYTE $0xFF @@ -103,7 +103,7 @@ BYTE $0x00 BYTE $0x1C MOVH $0x200, R4 - WORD $0xB3CD0022 //lgdr %r2, %f2 + LGDR F2, R2 SRAD $32, R2 L4: WORD $0xEC3239BE //risbg %r3,%r2,57,128+62,64-25 @@ -134,7 +134,7 @@ ADDW R4, R1 SLW $16, R1, R1 SLD $32, R1, R1 - WORD $0xB3C10021 //ldgr %f2,%r1 + LDGR R1, F2 WFMDB V2, V2, V4 WFMDB V4, V0, V6 WFMSDB V4, V6, V2, V4
diff --git a/src/math/cmplx/isinf.go b/src/math/cmplx/isinf.go index d5a65b4..6273cd3 100644 --- a/src/math/cmplx/isinf.go +++ b/src/math/cmplx/isinf.go
@@ -6,7 +6,7 @@ import "math" -// IsInf returns true if either real(x) or imag(x) is an infinity. +// IsInf reports whether either real(x) or imag(x) is an infinity. func IsInf(x complex128) bool { if math.IsInf(real(x), 0) || math.IsInf(imag(x), 0) { return true
diff --git a/src/math/cmplx/isnan.go b/src/math/cmplx/isnan.go index 05d0cce..d3382c0 100644 --- a/src/math/cmplx/isnan.go +++ b/src/math/cmplx/isnan.go
@@ -6,7 +6,7 @@ import "math" -// IsNaN returns true if either real(x) or imag(x) is NaN +// IsNaN reports whether either real(x) or imag(x) is NaN // and neither is an infinity. func IsNaN(x complex128) bool { switch {
diff --git a/src/math/erf_s390x.s b/src/math/erf_s390x.s index 5b62bda..5be5d4d 100644 --- a/src/math/erf_s390x.s +++ b/src/math/erf_s390x.s
@@ -100,7 +100,7 @@ TEXT ·erfAsm(SB), NOSPLIT, $0-16 FMOVD x+0(FP), F0 MOVD $·erfrodataL13<>+0(SB), R5 - WORD $0xB3CD0010 //lgdr %r1, %f0 + LGDR F0, R1 FMOVD F0, F6 SRAD $48, R1 MOVH $16383, R3 @@ -205,7 +205,7 @@ FMOVD 256(R5), F4 WFMADB V1, V4, V3, V4 FDIV F6, F2 - WORD $0xB3CD0014 //lgdr %r1, %f4 + LGDR F4, R1 FSUB F3, F4 FMOVD 248(R5), F6 WFMSDB V4, V6, V1, V4 @@ -230,7 +230,7 @@ BYTE $0x59 MOVD $·erftab2066<>+0(SB), R1 FMOVD 192(R5), F1 - WORD $0xB3C10033 //ldgr %f3,%r3 + LDGR R3, F3 WORD $0xED221000 //madb %f2,%f2,0(%r2,%r1) BYTE $0x20 BYTE $0x1E
diff --git a/src/math/erfc_s390x.s b/src/math/erfc_s390x.s index 57710b2..0cb606d 100644 --- a/src/math/erfc_s390x.s +++ b/src/math/erfc_s390x.s
@@ -219,7 +219,7 @@ WFMADB V0, V5, V3, V5 WFMADB V6, V7, V2, V7 L11: - WORD $0xB3CD0065 //lgdr %r6, %f5 + LGDR F5, R6 WFSDB V0, V0, V2 WORD $0xED509298 //sdb %f5,.L55-.L38(%r9) BYTE $0x00 @@ -253,7 +253,7 @@ BYTE $0x30 BYTE $0x59 WFMADB V4, V0, V2, V4 - WORD $0xB3C10024 //ldgr %f2,%r4 + LDGR R4, F2 FMADD F4, F2, F2 MOVW R2, R6 CMPBLE R6, $0, L20 @@ -504,7 +504,7 @@ CMPBGT R6, R7, L24 WORD $0xA5400010 //iihh %r4,16 - WORD $0xB3C10024 //ldgr %f2,%r4 + LDGR R4, F2 FMUL F2, F2 BR L1 L23: @@ -521,7 +521,7 @@ CMPBGT R6, R7, L25 WORD $0xA5408010 //iihh %r4,32784 FMOVD 568(R9), F2 - WORD $0xB3C10004 //ldgr %f0,%r4 + LDGR R4, F0 FMADD F2, F0, F2 BR L1 L25:
diff --git a/src/math/example_test.go b/src/math/example_test.go index a1f764b..25d6975 100644 --- a/src/math/example_test.go +++ b/src/math/example_test.go
@@ -113,3 +113,25 @@ fmt.Printf("%.1f", c) // Output: 100.0 } + +func ExampleRound() { + p := math.Round(10.5) + fmt.Printf("%.1f\n", p) + + n := math.Round(-10.5) + fmt.Printf("%.1f\n", n) + // Output: + // 11.0 + // -11.0 +} + +func ExampleRoundToEven() { + u := math.RoundToEven(11.5) + fmt.Printf("%.1f\n", u) + + d := math.RoundToEven(12.5) + fmt.Printf("%.1f\n", d) + // Output: + // 12.0 + // 12.0 +}
diff --git a/src/math/exp_s390x.s b/src/math/exp_s390x.s index 613ec24..cef1ce7 100644 --- a/src/math/exp_s390x.s +++ b/src/math/exp_s390x.s
@@ -84,7 +84,7 @@ FMOVD 32(R5), F4 FMUL F0, F0 WFMADB V2, V4, V1, V4 - WORD $0xB3CD0016 //lgdr %r1,%f6 + LGDR F6, R1 FMOVD 24(R5), F1 WFMADB V2, V3, V1, V3 FMOVD 16(R5), F1 @@ -100,7 +100,7 @@ FMADD F4, F2, F2 SLD $48, R1, R2 WFMADB V2, V0, V4, V2 - WORD $0xB3C10002 //ldgr %f0,%r2 + LDGR R2, F0 FMADD F0, F2, F0 FMOVD F0, ret+8(FP) RET @@ -135,7 +135,7 @@ FMUL F6, F6 WFMADB V4, V1, V5, V1 FMOVD 48(R5), F7 - WORD $0xB3CD0013 //lgdr %r1,%f3 + LGDR F3, R1 FMOVD 24(R5), F5 WFMADB V4, V7, V5, V7 FMOVD 16(R5), F5 @@ -157,7 +157,7 @@ WORD $0xEC21000F //risbgn %r2,%r1,64-64+0,64-64+0+16-1,64-0-16 BYTE $0x30 BYTE $0x59 - WORD $0xB3C10002 //ldgr %f0,%r2 + LDGR R2, F0 FMADD F0, F4, F0 MOVD $·expx4ff<>+0(SB), R3 FMOVD 0(R3), F2 @@ -173,7 +173,7 @@ WORD $0xEC21000F //risbgn %r2,%r1,64-64+0,64-64+0+16-1,64-0-16 BYTE $0x30 BYTE $0x59 - WORD $0xB3C10002 //ldgr %f0,%r2 + LDGR R2, F0 FMADD F0, F4, F0 MOVD $·expx2ff<>+0(SB), R3 FMOVD 0(R3), F2
diff --git a/src/math/expm1_386.s b/src/math/expm1_386.s index c1392cd..d020296 100644 --- a/src/math/expm1_386.s +++ b/src/math/expm1_386.s
@@ -8,7 +8,7 @@ TEXT ·Expm1(SB),NOSPLIT,$0 FLDLN2 // F0=log(2) = 1/log2(e) ~ 0.693147 FMOVD x+0(FP), F0 // F0=x, F1=1/log2(e) - FABS // F0=|x|, F1=1/log2(e) + FABS // F0=|x|, F1=1/log2(e) FUCOMPP F0, F1 // compare F0 to F1 FSTSW AX SAHF @@ -36,7 +36,7 @@ FSCALE // F0=e**x, F1=int(x*log2(e)) FMOVDP F0, F1 // F0=e**x FLD1 // F0=1, F1=e**x - FSUBDP F0, F1 // F0=e**x-1 + FSUBDP F0, F1 // F0=e**x-1 FMOVDP F0, ret+8(FP) RET not_finite:
diff --git a/src/math/expm1_s390x.s b/src/math/expm1_s390x.s index 22e5eb1..c7c793b 100644 --- a/src/math/expm1_s390x.s +++ b/src/math/expm1_s390x.s
@@ -89,7 +89,7 @@ FMADD F2, F0, F6 WFMADB V0, V5, V3, V5 WFMDB V0, V0, V2 - WORD $0xB3CD0011 //lgdr %r1,%f1 + LGDR F1, R1 WFMADB V6, V2, V5, V6 FMOVD 40(R5), F3 FMOVD 32(R5), F5 @@ -108,7 +108,7 @@ FMADD F4, F0, F0 SLD $48, R1, R2 WFMSDB V2, V0, V4, V0 - WORD $0xB3C10042 //ldgr %f4,%r2 + LDGR R2, F4 WORD $0xB3130000 //lcdbr %f0,%f0 FSUB F4, F6 WFMSDB V0, V4, V6, V0 @@ -155,7 +155,7 @@ WFMADB V1, V16, V3, V1 FMOVD 16(R5), F6 FMADD F4, F1, F6 - WORD $0xB3CD0015 //lgdr %r1,%f5 + LGDR F5, R1 WORD $0xB3130066 //lcdbr %f6,%f6 WORD $0xEC3139BC //risbg %r3,%r1,57,128+60,3 BYTE $0x03 @@ -171,7 +171,7 @@ WORD $0xEC21000F //risbgn %r2,%r1,64-64+0,64-64+0+16-1,64-0-16 BYTE $0x30 BYTE $0x59 - WORD $0xB3C10002 //ldgr %f0,%r2 + LDGR R2, F0 FMADD F0, F4, F0 MOVD $·expm1x4ff<>+0(SB), R3 FMOVD 0(R5), F4 @@ -189,7 +189,7 @@ WORD $0xEC21000F //risbgn %r2,%r1,64-64+0,64-64+0+16-1,64-0-16 BYTE $0x30 BYTE $0x59 - WORD $0xB3C10002 //ldgr %f0,%r2 + LDGR R2, F0 FMADD F0, F4, F0 MOVD $·expm1x2ff<>+0(SB), R3 FMOVD 0(R5), F4
diff --git a/src/math/export_test.go b/src/math/export_test.go index 368308e..53d9205 100644 --- a/src/math/export_test.go +++ b/src/math/export_test.go
@@ -9,3 +9,6 @@ var Exp2Go = exp2 var HypotGo = hypot var SqrtGo = sqrt +var TrigReduce = trigReduce + +const ReduceThreshold = reduceThreshold
diff --git a/src/math/huge_test.go b/src/math/huge_test.go new file mode 100644 index 0000000..0b45dbf --- /dev/null +++ b/src/math/huge_test.go
@@ -0,0 +1,99 @@ +// Copyright 2018 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. + +// Disabled for s390x because it uses assembly routines that are not +// accurate for huge arguments. + +// +build !s390x + +package math_test + +import ( + . "math" + "testing" +) + +// Inputs to test trig_reduce +var trigHuge = []float64{ + 1 << 120, + 1 << 240, + 1 << 480, + 1234567891234567 << 180, + 1234567891234567 << 300, + MaxFloat64, +} + +// Results for trigHuge[i] calculated with https://github.com/robpike/ivy +// using 4096 bits of working precision. Values requiring less than +// 102 decimal digits (1 << 120, 1 << 240, 1 << 480, 1234567891234567 << 180) +// were confirmed via https://keisan.casio.com/ +var cosHuge = []float64{ + -0.92587902285483787, + 0.93601042593353793, + -0.28282777640193788, + -0.14616431394103619, + -0.79456058210671406, + -0.99998768942655994, +} + +var sinHuge = []float64{ + 0.37782010936075202, + -0.35197227524865778, + 0.95917070894368716, + 0.98926032637023618, + -0.60718488235646949, + 0.00496195478918406, +} + +var tanHuge = []float64{ + -0.40806638884180424, + -0.37603456702698076, + -3.39135965054779932, + -6.76813854009065030, + 0.76417695016604922, + -0.00496201587444489, +} + +// Check that trig values of huge angles return accurate results. +// This confirms that argument reduction works for very large values +// up to MaxFloat64. +func TestHugeCos(t *testing.T) { + for i := 0; i < len(trigHuge); i++ { + f1 := cosHuge[i] + f2 := Cos(trigHuge[i]) + if !close(f1, f2) { + t.Errorf("Cos(%g) = %g, want %g", trigHuge[i], f2, f1) + } + } +} + +func TestHugeSin(t *testing.T) { + for i := 0; i < len(trigHuge); i++ { + f1 := sinHuge[i] + f2 := Sin(trigHuge[i]) + if !close(f1, f2) { + t.Errorf("Sin(%g) = %g, want %g", trigHuge[i], f2, f1) + } + } +} + +func TestHugeSinCos(t *testing.T) { + for i := 0; i < len(trigHuge); i++ { + f1, g1 := sinHuge[i], cosHuge[i] + f2, g2 := Sincos(trigHuge[i]) + if !close(f1, f2) || !close(g1, g2) { + t.Errorf("Sincos(%g) = %g, %g, want %g, %g", trigHuge[i], f2, g2, f1, g1) + } + } +} + +func TestHugeTan(t *testing.T) { + for i := 0; i < len(trigHuge); i++ { + f1 := tanHuge[i] + f2 := Tan(trigHuge[i]) + if !close(f1, f2) { + t.Errorf("Tan(%g) = %g, want %g", trigHuge[i], f2, f1) + } + } +}
diff --git a/src/math/log1p.go b/src/math/log1p.go index b128a16..c4ec61b 100644 --- a/src/math/log1p.go +++ b/src/math/log1p.go
@@ -151,12 +151,13 @@ u = 1.0 + x iu = Float64bits(u) k = int((iu >> 52) - 1023) + // correction term if k > 0 { c = 1.0 - (u - x) } else { - c = x - (u - 1.0) // correction term - c /= u + c = x - (u - 1.0) } + c /= u } else { u = x iu = Float64bits(u)
diff --git a/src/math/log1p_s390x.s b/src/math/log1p_s390x.s index c7e9860..ba4933d 100644 --- a/src/math/log1p_s390x.s +++ b/src/math/log1p_s390x.s
@@ -96,7 +96,7 @@ MOVD $·log1pc5<>+0(SB), R1 VLEG $0, 0(R1), V16 MOVD R2, R5 - WORD $0xB3CD0034 //lgdr %r3,%f4 + LGDR F4, R3 WORD $0xC0190006 //iilf %r1,425983 BYTE $0x7F BYTE $0xFF @@ -118,7 +118,7 @@ MOVD $·log1pxzero<>+0(SB), R1 FMOVD 0(R1), F2 BVS LEXITTAGlog1p - WORD $0xB3130044 + WORD $0xB3130044 // lcdbr %f4,%f4 WFCEDBS V2, V4, V6 BEQ L9 WFCHDBS V4, V2, V2 @@ -129,11 +129,11 @@ RET L8: - WORD $0xB3C10022 //ldgr %f2,%r2 + LDGR R2, F2 FSUB F4, F3 FMADD F2, F4, F1 MOVD $·log1pc4<>+0(SB), R2 - WORD $0xB3130041 + WORD $0xB3130041 // lcdbr %f4,%f1 FMOVD 0(R2), F7 FSUB F3, F0 MOVD $·log1pc3<>+0(SB), R2 @@ -164,7 +164,7 @@ FMOVD 0(R3), F2 WFMADB V0, V6, V1, V0 MOVD $·log1pyout<>+0(SB), R1 - WORD $0xB3C10065 //ldgr %f6,%r5 + LDGR R5, F6 FMOVD 0(R1), F4 WFMSDB V2, V6, V4, V2 MOVD $·log1pxl2<>+0(SB), R1
diff --git a/src/math/log_s390x.s b/src/math/log_s390x.s index 3e24ca7..7bcfdfc 100644 --- a/src/math/log_s390x.s +++ b/src/math/log_s390x.s
@@ -63,7 +63,7 @@ FMOVD x+0(FP), F0 MOVD $·logrodataL21<>+0(SB), R9 MOVH $0x8006, R4 - WORD $0xB3CD0010 //lgdr %r1,%f0 + LGDR F0, R1 MOVD $0x3FF0000000000000, R6 SRAD $48, R1, R1 MOVD $0x40F03E8000000000, R8 @@ -91,7 +91,7 @@ BLEU L3 L15: FMUL F2, F0 - WORD $0xB3CD0010 //lgdr %r1,%f0 + LGDR F0, R1 SRAD $48, R1, R1 SUBW R1, R0, R2 SUBW R1, R12, R3 @@ -114,7 +114,7 @@ MOVH $0x7FEF, R1 CMPW R5, R1 BGT L1 - WORD $0xB3C10026 //ldgr %f2,%r6 + LDGR R6, F2 FMUL F2, F0 WORD $0xEC4439BB //risbg %r4,%r4,57,128+59,3 BYTE $0x03 @@ -148,14 +148,14 @@ WFMADB V6, V4, V1, V4 FMOVD 8(R4), F1 WFMADB V0, V2, V4, V2 - WORD $0xB3C10048 //ldgr %f4,%r8 + LDGR R8, F4 WFMADB V6, V2, V0, V2 WORD $0xED401000 //msdb %f1,%f4,0(%r1) BYTE $0x10 BYTE $0x1F MOVD ·logxl2<>+0(SB), R1 WORD $0xB3130001 //lcdbr %f0,%f1 - WORD $0xB3C10041 //ldgr %f4,%r1 + LDGR R1, F4 WFMADB V0, V4, V2, V0 L1: FMOVD F0, ret+8(FP)
diff --git a/src/math/mod.go b/src/math/mod.go index e1a414e..7efc018 100644 --- a/src/math/mod.go +++ b/src/math/mod.go
@@ -24,16 +24,12 @@ if y == 0 || IsInf(x, 0) || IsNaN(x) || IsNaN(y) { return NaN() } - if y < 0 { - y = -y - } + y = Abs(y) yfr, yexp := Frexp(y) - sign := false r := x if x < 0 { r = -x - sign = true } for r >= y { @@ -43,7 +39,7 @@ } r = r - Ldexp(y, rexp-yexp) } - if sign { + if x < 0 { r = -r } return r
diff --git a/src/math/pow.go b/src/math/pow.go index 336193b..2219a90 100644 --- a/src/math/pow.go +++ b/src/math/pow.go
@@ -83,13 +83,7 @@ return 1 / Sqrt(x) } - absy := y - flip := false - if absy < 0 { - absy = -absy - flip = true - } - yi, yf := Modf(absy) + yi, yf := Modf(Abs(y)) if yf != 0 && x < 0 { return NaN() } @@ -147,9 +141,9 @@ } // ans = a1*2**ae - // if flip { ans = 1 / ans } + // if y < 0 { ans = 1 / ans } // but in the opposite order - if flip { + if y < 0 { a1 = 1 / a1 ae = -ae }
diff --git a/src/math/pow_s390x.s b/src/math/pow_s390x.s index fd19617..754b119 100644 --- a/src/math/pow_s390x.s +++ b/src/math/pow_s390x.s
@@ -297,7 +297,7 @@ FMOVD x+0(FP), F0 FMOVD y+8(FP), F2 MOVD $·powrodataL51<>+0(SB), R9 - WORD $0xB3CD0030 //lgdr %r3,%f0 + LGDR F0, R3 WORD $0xC0298009 //iilf %r2,2148095317 BYTE $0x55 BYTE $0x55 @@ -340,7 +340,7 @@ BYTE $0x24 FMOVD 0(R2), F6 FSUBS F1, F3 - WORD $0xB3C10018 //ldgr %f1,%r8 + LDGR R8, F1 WFMSDB V4, V1, V6, V4 FMOVD 152(R9), F6 WFMDB V4, V4, V7 @@ -387,7 +387,7 @@ WFMSDB V2, V3, V5, V3 VLEG $0, 48(R9), V18 WFADB V3, V5, V6 - WORD $0xB3CD0023 //lgdr %r2,%f3 + LGDR F3, R2 WFMSDB V2, V16, V6, V16 FMOVD 40(R9), F1 WFMADB V2, V4, V16, V4 @@ -410,8 +410,8 @@ BYTE $0x30 BYTE $0x59 WFMADB V4, V1, V3, V4 - WORD $0xB3CD0026 //lgdr %r2,%f6 - WORD $0xB3C10015 //ldgr %f1,%r5 + LGDR F6, R2 + LDGR R5, F1 SRAD $48, R2, R2 FMADD F1, F4, F1 RLL $16, R2, R2 @@ -452,7 +452,7 @@ WORD $0xEC1520BF //risbgn %r1,%r5,64-32,128+63,64+0+32 BYTE $0x60 BYTE $0x59 - WORD $0xB3CD0026 //lgdr %r2,%f6 + LGDR F6, R2 MOVD $powiadd<>+0(SB), R3 WORD $0xEC223CBC //risbg %r2,%r2,60,128+60,64-60 BYTE $0x04 @@ -461,7 +461,7 @@ WORD $0xEC51001F //risbgn %r5,%r1,64-64+0,64-64+0+32-1,64-0-32 BYTE $0x20 BYTE $0x59 - WORD $0xB3C10015 //ldgr %f1,%r5 + LDGR R5, F1 FMADD F1, F4, F1 MOVD $powxscale<>+0(SB), R1 WORD $0xED121000 //mdb %f1,0(%r2,%r1) @@ -486,7 +486,7 @@ WORD $0xC0298009 //iilf %r2,2148095317 BYTE $0x55 BYTE $0x55 - WORD $0xB3CD0034 //lgdr %r3,%f4 + LGDR F4, R3 WORD $0xEC3320BF //risbgn %r3,%r3,64-32,128+63,64+0+32 BYTE $0x60 BYTE $0x59 @@ -566,11 +566,11 @@ BVS L49 L16: MOVD ·pow_xnan<>+0(SB), R1 - WORD $0xB3C10001 //ldgr %f0,%r1 + LDGR R1, F0 WFMDB V4, V0, V1 BR L1 L48: - WORD $0xB3CD0030 //lgdr %r3,%f0 + LGDR F0, R3 WORD $0xEC1320BF //risbgn %r1,%r3,64-32,128+63,64+0+32 BYTE $0x60 BYTE $0x59
diff --git a/src/math/signbit.go b/src/math/signbit.go index 670cc1a..f6e61d6 100644 --- a/src/math/signbit.go +++ b/src/math/signbit.go
@@ -4,7 +4,7 @@ package math -// Signbit returns true if x is negative or negative zero. +// Signbit reports whether x is negative or negative zero. func Signbit(x float64) bool { return Float64bits(x)&(1<<63) != 0 }
diff --git a/src/math/sin.go b/src/math/sin.go index 929cac3..cc8b136 100644 --- a/src/math/sin.go +++ b/src/math/sin.go
@@ -118,10 +118,9 @@ func cos(x float64) float64 { const ( - PI4A = 7.85398125648498535156E-1 // 0x3fe921fb40000000, Pi/4 split into three parts - PI4B = 3.77489470793079817668E-8 // 0x3e64442d00000000, - PI4C = 2.69515142907905952645E-15 // 0x3ce8469898cc5170, - M4PI = 1.273239544735162542821171882678754627704620361328125 // 4/pi + PI4A = 7.85398125648498535156E-1 // 0x3fe921fb40000000, Pi/4 split into three parts + PI4B = 3.77489470793079817668E-8 // 0x3e64442d00000000, + PI4C = 2.69515142907905952645E-15 // 0x3ce8469898cc5170, ) // special cases switch { @@ -133,15 +132,23 @@ sign := false x = Abs(x) - j := int64(x * M4PI) // integer part of x/(Pi/4), as integer for tests on the phase angle - y := float64(j) // integer part of x/(Pi/4), as float + var j uint64 + var y, z float64 + if x >= reduceThreshold { + j, z = trigReduce(x) + } else { + j = uint64(x * (4 / Pi)) // integer part of x/(Pi/4), as integer for tests on the phase angle + y = float64(j) // integer part of x/(Pi/4), as float - // map zeros to origin - if j&1 == 1 { - j++ - y++ + // map zeros to origin + if j&1 == 1 { + j++ + y++ + } + j &= 7 // octant modulo 2Pi radians (360 degrees) + z = ((x - y*PI4A) - y*PI4B) - y*PI4C // Extended precision modular arithmetic } - j &= 7 // octant modulo 2Pi radians (360 degrees) + if j > 3 { j -= 4 sign = !sign @@ -150,7 +157,6 @@ sign = !sign } - z := ((x - y*PI4A) - y*PI4B) - y*PI4C // Extended precision modular arithmetic zz := z * z if j == 1 || j == 2 { y = z + z*zz*((((((_sin[0]*zz)+_sin[1])*zz+_sin[2])*zz+_sin[3])*zz+_sin[4])*zz+_sin[5]) @@ -173,10 +179,9 @@ func sin(x float64) float64 { const ( - PI4A = 7.85398125648498535156E-1 // 0x3fe921fb40000000, Pi/4 split into three parts - PI4B = 3.77489470793079817668E-8 // 0x3e64442d00000000, - PI4C = 2.69515142907905952645E-15 // 0x3ce8469898cc5170, - M4PI = 1.273239544735162542821171882678754627704620361328125 // 4/pi + PI4A = 7.85398125648498535156E-1 // 0x3fe921fb40000000, Pi/4 split into three parts + PI4B = 3.77489470793079817668E-8 // 0x3e64442d00000000, + PI4C = 2.69515142907905952645E-15 // 0x3ce8469898cc5170, ) // special cases switch { @@ -193,22 +198,27 @@ sign = true } - j := int64(x * M4PI) // integer part of x/(Pi/4), as integer for tests on the phase angle - y := float64(j) // integer part of x/(Pi/4), as float + var j uint64 + var y, z float64 + if x >= reduceThreshold { + j, z = trigReduce(x) + } else { + j = uint64(x * (4 / Pi)) // integer part of x/(Pi/4), as integer for tests on the phase angle + y = float64(j) // integer part of x/(Pi/4), as float - // map zeros to origin - if j&1 == 1 { - j++ - y++ + // map zeros to origin + if j&1 == 1 { + j++ + y++ + } + j &= 7 // octant modulo 2Pi radians (360 degrees) + z = ((x - y*PI4A) - y*PI4B) - y*PI4C // Extended precision modular arithmetic } - j &= 7 // octant modulo 2Pi radians (360 degrees) // reflect in x axis if j > 3 { sign = !sign j -= 4 } - - z := ((x - y*PI4A) - y*PI4B) - y*PI4C // Extended precision modular arithmetic zz := z * z if j == 1 || j == 2 { y = 1.0 - 0.5*zz + zz*zz*((((((_cos[0]*zz)+_cos[1])*zz+_cos[2])*zz+_cos[3])*zz+_cos[4])*zz+_cos[5])
diff --git a/src/math/sin_386.s b/src/math/sin_386.s index 9d605a1..cf7679d 100644 --- a/src/math/sin_386.s +++ b/src/math/sin_386.s
@@ -6,42 +6,8 @@ // func Cos(x float64) float64 TEXT ·Cos(SB),NOSPLIT,$0 - FMOVD x+0(FP), F0 // F0=x - FCOS // F0=cos(x) if -2**63 < x < 2**63 - FSTSW AX // AX=status word - ANDW $0x0400, AX - JNE 3(PC) // jump if x outside range - FMOVDP F0, ret+8(FP) - RET - FLDPI // F0=Pi, F1=x - FADDD F0, F0 // F0=2*Pi, F1=x - FXCHD F0, F1 // F0=x, F1=2*Pi - FPREM1 // F0=reduced_x, F1=2*Pi - FSTSW AX // AX=status word - ANDW $0x0400, AX - JNE -3(PC) // jump if reduction incomplete - FMOVDP F0, F1 // F0=reduced_x - FCOS // F0=cos(reduced_x) - FMOVDP F0, ret+8(FP) - RET - + JMP ·cos(SB) + // func Sin(x float64) float64 TEXT ·Sin(SB),NOSPLIT,$0 - FMOVD x+0(FP), F0 // F0=x - FSIN // F0=sin(x) if -2**63 < x < 2**63 - FSTSW AX // AX=status word - ANDW $0x0400, AX - JNE 3(PC) // jump if x outside range - FMOVDP F0, ret+8(FP) - RET - FLDPI // F0=Pi, F1=x - FADDD F0, F0 // F0=2*Pi, F1=x - FXCHD F0, F1 // F0=x, F1=2*Pi - FPREM1 // F0=reduced_x, F1=2*Pi - FSTSW AX // AX=status word - ANDW $0x0400, AX - JNE -3(PC) // jump if reduction incomplete - FMOVDP F0, F1 // F0=reduced_x - FSIN // F0=sin(reduced_x) - FMOVDP F0, ret+8(FP) - RET + JMP ·sin(SB)
diff --git a/src/math/sincos.go b/src/math/sincos.go index 3ae193a..c002db6 100644 --- a/src/math/sincos.go +++ b/src/math/sincos.go
@@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !386 - package math // Coefficients _sin[] and _cos[] are found in pkg/math/sin.go. @@ -16,10 +14,9 @@ // Sincos(NaN) = NaN, NaN func Sincos(x float64) (sin, cos float64) { const ( - PI4A = 7.85398125648498535156E-1 // 0x3fe921fb40000000, Pi/4 split into three parts - PI4B = 3.77489470793079817668E-8 // 0x3e64442d00000000, - PI4C = 2.69515142907905952645E-15 // 0x3ce8469898cc5170, - M4PI = 1.273239544735162542821171882678754627704620361328125 // 4/pi + PI4A = 7.85398125648498535156E-1 // 0x3fe921fb40000000, Pi/4 split into three parts + PI4B = 3.77489470793079817668E-8 // 0x3e64442d00000000, + PI4C = 2.69515142907905952645E-15 // 0x3ce8469898cc5170, ) // special cases switch { @@ -36,14 +33,21 @@ sinSign = true } - j := int64(x * M4PI) // integer part of x/(Pi/4), as integer for tests on the phase angle - y := float64(j) // integer part of x/(Pi/4), as float + var j uint64 + var y, z float64 + if x >= reduceThreshold { + j, z = trigReduce(x) + } else { + j = uint64(x * (4 / Pi)) // integer part of x/(Pi/4), as integer for tests on the phase angle + y = float64(j) // integer part of x/(Pi/4), as float - if j&1 == 1 { // map zeros to origin - j++ - y++ + if j&1 == 1 { // map zeros to origin + j++ + y++ + } + j &= 7 // octant modulo 2Pi radians (360 degrees) + z = ((x - y*PI4A) - y*PI4B) - y*PI4C // Extended precision modular arithmetic } - j &= 7 // octant modulo 2Pi radians (360 degrees) if j > 3 { // reflect in x axis j -= 4 sinSign, cosSign = !sinSign, !cosSign @@ -52,7 +56,6 @@ cosSign = !cosSign } - z := ((x - y*PI4A) - y*PI4B) - y*PI4C // Extended precision modular arithmetic zz := z * z cos = 1.0 - 0.5*zz + zz*zz*((((((_cos[0]*zz)+_cos[1])*zz+_cos[2])*zz+_cos[3])*zz+_cos[4])*zz+_cos[5]) sin = z + z*zz*((((((_sin[0]*zz)+_sin[1])*zz+_sin[2])*zz+_sin[3])*zz+_sin[4])*zz+_sin[5])
diff --git a/src/math/sincos_386.go b/src/math/sincos_386.go deleted file mode 100644 index 38bb050..0000000 --- a/src/math/sincos_386.go +++ /dev/null
@@ -1,13 +0,0 @@ -// Copyright 2017 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 math - -// Sincos returns Sin(x), Cos(x). -// -// Special cases are: -// Sincos(±0) = ±0, 1 -// Sincos(±Inf) = NaN, NaN -// Sincos(NaN) = NaN, NaN -func Sincos(x float64) (sin, cos float64)
diff --git a/src/math/sincos_386.s b/src/math/sincos_386.s deleted file mode 100644 index f700a4f..0000000 --- a/src/math/sincos_386.s +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2010 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. - -#include "textflag.h" - -// func Sincos(x float64) (sin, cos float64) -TEXT ·Sincos(SB),NOSPLIT,$0 - FMOVD x+0(FP), F0 // F0=x - FSINCOS // F0=cos(x), F1=sin(x) if -2**63 < x < 2**63 - FSTSW AX // AX=status word - ANDW $0x0400, AX - JNE 4(PC) // jump if x outside range - FMOVDP F0, cos+16(FP) // F0=sin(x) - FMOVDP F0, sin+8(FP) - RET - FLDPI // F0=Pi, F1=x - FADDD F0, F0 // F0=2*Pi, F1=x - FXCHD F0, F1 // F0=x, F1=2*Pi - FPREM1 // F0=reduced_x, F1=2*Pi - FSTSW AX // AX=status word - ANDW $0x0400, AX - JNE -3(PC) // jump if reduction incomplete - FMOVDP F0, F1 // F0=reduced_x - FSINCOS // F0=cos(reduced_x), F1=sin(reduced_x) - FMOVDP F0, cos+16(FP) // F0=sin(reduced_x) - FMOVDP F0, sin+8(FP) - RET
diff --git a/src/math/sinh.go b/src/math/sinh.go index 39e7c20..573a37e 100644 --- a/src/math/sinh.go +++ b/src/math/sinh.go
@@ -43,7 +43,7 @@ } var temp float64 - switch true { + switch { case x > 21: temp = Exp(x) * 0.5
diff --git a/src/math/sqrt_386.s b/src/math/sqrt_386.s index 402d152..5a5c33a 100644 --- a/src/math/sqrt_386.s +++ b/src/math/sqrt_386.s
@@ -4,7 +4,7 @@ #include "textflag.h" -// func Sqrt(x float64) float64 +// func Sqrt(x float64) float64 TEXT ·Sqrt(SB),NOSPLIT,$0 FMOVD x+0(FP),F0 FSQRT
diff --git a/src/math/sqrt_arm.s b/src/math/sqrt_arm.s index deb6712..ffc7d10 100644 --- a/src/math/sqrt_arm.s +++ b/src/math/sqrt_arm.s
@@ -4,7 +4,7 @@ #include "textflag.h" -// func Sqrt(x float64) float64 +// func Sqrt(x float64) float64 TEXT ·Sqrt(SB),NOSPLIT,$0 MOVB runtime·goarm(SB), R11 CMP $5, R11
diff --git a/src/math/tan.go b/src/math/tan.go index aa2fb37..0d5394c 100644 --- a/src/math/tan.go +++ b/src/math/tan.go
@@ -83,10 +83,9 @@ func tan(x float64) float64 { const ( - PI4A = 7.85398125648498535156E-1 // 0x3fe921fb40000000, Pi/4 split into three parts - PI4B = 3.77489470793079817668E-8 // 0x3e64442d00000000, - PI4C = 2.69515142907905952645E-15 // 0x3ce8469898cc5170, - M4PI = 1.273239544735162542821171882678754627704620361328125 // 4/pi + PI4A = 7.85398125648498535156E-1 // 0x3fe921fb40000000, Pi/4 split into three parts + PI4B = 3.77489470793079817668E-8 // 0x3e64442d00000000, + PI4C = 2.69515142907905952645E-15 // 0x3ce8469898cc5170, ) // special cases switch { @@ -102,17 +101,22 @@ x = -x sign = true } + var j uint64 + var y, z float64 + if x >= reduceThreshold { + j, z = trigReduce(x) + } else { + j = uint64(x * (4 / Pi)) // integer part of x/(Pi/4), as integer for tests on the phase angle + y = float64(j) // integer part of x/(Pi/4), as float - j := int64(x * M4PI) // integer part of x/(Pi/4), as integer for tests on the phase angle - y := float64(j) // integer part of x/(Pi/4), as float + /* map zeros and singularities to origin */ + if j&1 == 1 { + j++ + y++ + } - /* map zeros and singularities to origin */ - if j&1 == 1 { - j++ - y++ + z = ((x - y*PI4A) - y*PI4B) - y*PI4C } - - z := ((x - y*PI4A) - y*PI4B) - y*PI4C zz := z * z if zz > 1e-14 {
diff --git a/src/math/tan_386.s b/src/math/tan_386.s index cb65a3f..4e44c26 100644 --- a/src/math/tan_386.s +++ b/src/math/tan_386.s
@@ -6,23 +6,4 @@ // func Tan(x float64) float64 TEXT ·Tan(SB),NOSPLIT,$0 - FMOVD x+0(FP), F0 // F0=x - FPTAN // F0=1, F1=tan(x) if -2**63 < x < 2**63 - FSTSW AX // AX=status word - ANDW $0x0400, AX - JNE 4(PC) // jump if x outside range - FMOVDP F0, F0 // F0=tan(x) - FMOVDP F0, ret+8(FP) - RET - FLDPI // F0=Pi, F1=x - FADDD F0, F0 // F0=2*Pi, F1=x - FXCHD F0, F1 // F0=x, F1=2*Pi - FPREM1 // F0=reduced_x, F1=2*Pi - FSTSW AX // AX=status word - ANDW $0x0400, AX - JNE -3(PC) // jump if reduction incomplete - FMOVDP F0, F1 // F0=reduced_x - FPTAN // F0=1, F1=tan(reduced_x) - FMOVDP F0, F0 // F0=tan(reduced_x) - FMOVDP F0, ret+8(FP) - RET + JMP ·tan(SB)
diff --git a/src/math/tan_s390x.s b/src/math/tan_s390x.s index 7b05ba0..b6e2295 100644 --- a/src/math/tan_s390x.s +++ b/src/math/tan_s390x.s
@@ -68,7 +68,7 @@ WFMADB V4, V3, V2, V4 FMUL F2, F2 VLEG $0, 48(R5), V18 - WORD $0xB3CD0016 //lgdr %r1,%f6 + LGDR F6, R1 FMOVD 40(R5), F5 FMOVD 32(R5), F3 FMADD F1, F2, F3 @@ -82,7 +82,7 @@ WFLCDB V4, V16 WFMADB V2, V5, V18, V5 WFMADB V1, V0, V7, V0 - WORD $0xA7110001 //tmll %r1,1 + TMLL R1, $1 WFMADB V1, V5, V3, V1 BNE L12 WFDDB V0, V1, V0
diff --git a/src/math/trig_reduce.go b/src/math/trig_reduce.go new file mode 100644 index 0000000..6f8eaba --- /dev/null +++ b/src/math/trig_reduce.go
@@ -0,0 +1,94 @@ +// Copyright 2018 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 math + +import ( + "math/bits" +) + +// reduceThreshold is the maximum value where the reduction using Pi/4 +// in 3 float64 parts still gives accurate results. Above this +// threshold Payne-Hanek range reduction must be used. +const reduceThreshold = (1 << 52) / (4 / Pi) + +// trigReduce implements Payne-Hanek range reduction by Pi/4 +// for x > 0. It returns the integer part mod 8 (j) and +// the fractional part (z) of x / (Pi/4). +// The implementation is based on: +// "ARGUMENT REDUCTION FOR HUGE ARGUMENTS: Good to the Last Bit" +// K. C. Ng et al, March 24, 1992 +// The simulated multi-precision calculation of x*B uses 64-bit integer arithmetic. +func trigReduce(x float64) (j uint64, z float64) { + const PI4 = Pi / 4 + if x < PI4 { + return 0, x + } + // Extract out the integer and exponent such that, + // x = ix * 2 ** exp. + ix := Float64bits(x) + exp := int(ix>>shift&mask) - bias - shift + ix &^= mask << shift + ix |= 1 << shift + // Use the exponent to extract the 3 appropriate uint64 digits from mPi4, + // B ~ (z0, z1, z2), such that the product leading digit has the exponent -61. + // Note, exp >= -53 since x >= PI4 and exp < 971 for maximum float64. + digit, bitshift := uint(exp+61)/64, uint(exp+61)%64 + z0 := (mPi4[digit] << bitshift) | (mPi4[digit+1] >> (64 - bitshift)) + z1 := (mPi4[digit+1] << bitshift) | (mPi4[digit+2] >> (64 - bitshift)) + z2 := (mPi4[digit+2] << bitshift) | (mPi4[digit+3] >> (64 - bitshift)) + // Multiply mantissa by the digits and extract the upper two digits (hi, lo). + z2hi, _ := bits.Mul64(z2, ix) + z1hi, z1lo := bits.Mul64(z1, ix) + z0lo := z0 * ix + lo, c := bits.Add64(z1lo, z2hi, 0) + hi, _ := bits.Add64(z0lo, z1hi, c) + // The top 3 bits are j. + j = hi >> 61 + // Extract the fraction and find its magnitude. + hi = hi<<3 | lo>>61 + lz := uint(bits.LeadingZeros64(hi)) + e := uint64(bias - (lz + 1)) + // Clear implicit mantissa bit and shift into place. + hi = (hi << (lz + 1)) | (lo >> (64 - (lz + 1))) + hi >>= 64 - shift + // Include the exponent and convert to a float. + hi |= e << shift + z = Float64frombits(hi) + // Map zeros to origin. + if j&1 == 1 { + j++ + j &= 7 + z-- + } + // Multiply the fractional part by pi/4. + return j, z * PI4 +} + +// mPi4 is the binary digits of 4/pi as a uint64 array, +// that is, 4/pi = Sum mPi4[i]*2^(-64*i) +// 19 64-bit digits and the leading one bit give 1217 bits +// of precision to handle the largest possible float64 exponent. +var mPi4 = [...]uint64{ + 0x0000000000000001, + 0x45f306dc9c882a53, + 0xf84eafa3ea69bb81, + 0xb6c52b3278872083, + 0xfca2c757bd778ac3, + 0x6e48dc74849ba5c0, + 0x0c925dd413a32439, + 0xfc3bd63962534e7d, + 0xd1046bea5d768909, + 0xd338e04d68befc82, + 0x7323ac7306a673e9, + 0x3908bf177bf25076, + 0x3ff12fffbc0b301f, + 0xde5e2316b414da3e, + 0xda6cfd9e4f96136e, + 0x9e8c7ecd3cbfd45a, + 0xea4f758fd7cbe2f6, + 0x7a0e73ef14a525d4, + 0xd7f6bf623f1aba10, + 0xac06608df8f6d757, +}
diff --git a/src/math/unsafe.go b/src/math/unsafe.go index 5ae6742..e59f50c 100644 --- a/src/math/unsafe.go +++ b/src/math/unsafe.go
@@ -6,16 +6,24 @@ import "unsafe" -// Float32bits returns the IEEE 754 binary representation of f. +// Float32bits returns the IEEE 754 binary representation of f, +// with the sign bit of f and the result in the same bit position. +// Float32bits(Float32frombits(x)) == x. func Float32bits(f float32) uint32 { return *(*uint32)(unsafe.Pointer(&f)) } -// Float32frombits returns the floating point number corresponding -// to the IEEE 754 binary representation b. +// Float32frombits returns the floating-point number corresponding +// to the IEEE 754 binary representation b, with the sign bit of b +// and the result in the same bit position. +// Float32frombits(Float32bits(x)) == x. func Float32frombits(b uint32) float32 { return *(*float32)(unsafe.Pointer(&b)) } -// Float64bits returns the IEEE 754 binary representation of f. +// Float64bits returns the IEEE 754 binary representation of f, +// with the sign bit of f and the result in the same bit position, +// and Float64bits(Float64frombits(x)) == x. func Float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) } -// Float64frombits returns the floating point number corresponding -// the IEEE 754 binary representation b. +// Float64frombits returns the floating-point number corresponding +// to the IEEE 754 binary representation b, with the sign bit of b +// and the result in the same bit position. +// Float64frombits(Float64bits(x)) == x. func Float64frombits(b uint64) float64 { return *(*float64)(unsafe.Pointer(&b)) }