math: special cases for Atan, Asin and Acos
Added tests for NaN and out-of-range values.
Combined asin.go and atan.go into atan.go.
R=rsc
CC=golang-dev
https://golang.org/cl/180065
diff --git a/src/pkg/math/sqrt.go b/src/pkg/math/sqrt.go
index 1e2209f..a3a3119 100644
--- a/src/pkg/math/sqrt.go
+++ b/src/pkg/math/sqrt.go
@@ -4,13 +4,83 @@
package math
-
-/*
- * sqrt returns the square root of its floating
- * point argument. Newton's method.
- *
- * calls frexp
- */
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_sqrt.c and
+// came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_sqrt(x)
+// Return correctly rounded sqrt.
+// -----------------------------------------
+// | Use the hardware sqrt if you have one |
+// -----------------------------------------
+// Method:
+// Bit by bit method using integer arithmetic. (Slow, but portable)
+// 1. Normalization
+// Scale x to y in [1,4) with even powers of 2:
+// find an integer k such that 1 <= (y=x*2^(2k)) < 4, then
+// sqrt(x) = 2^k * sqrt(y)
+// 2. Bit by bit computation
+// Let q = sqrt(y) truncated to i bit after binary point (q = 1),
+// i 0
+// i+1 2
+// s = 2*q , and y = 2 * ( y - q ). (1)
+// i i i i
+//
+// To compute q from q , one checks whether
+// i+1 i
+//
+// -(i+1) 2
+// (q + 2 ) <= y. (2)
+// i
+// -(i+1)
+// If (2) is false, then q = q ; otherwise q = q + 2 .
+// i+1 i i+1 i
+//
+// With some algebric manipulation, it is not difficult to see
+// that (2) is equivalent to
+// -(i+1)
+// s + 2 <= y (3)
+// i i
+//
+// The advantage of (3) is that s and y can be computed by
+// i i
+// the following recurrence formula:
+// if (3) is false
+//
+// s = s , y = y ; (4)
+// i+1 i i+1 i
+//
+// otherwise,
+// -i -(i+1)
+// s = s + 2 , y = y - s - 2 (5)
+// i+1 i i+1 i i
+//
+// One may easily use induction to prove (4) and (5).
+// Note. Since the left hand side of (3) contain only i+2 bits,
+// it does not necessary to do a full (53-bit) comparison
+// in (3).
+// 3. Final rounding
+// After generating the 53 bits result, we compute one more bit.
+// Together with the remainder, we can decide whether the
+// result is exact, bigger than 1/2ulp, or less than 1/2ulp
+// (it will never equal to 1/2ulp).
+// The rounding mode can be detected by checking whether
+// huge + tiny is equal to huge, and whether huge - tiny is
+// equal to huge for some floating point number "huge" and "tiny".
+//
+//
+// Notes: Rounding mode detection omitted. The constants "mask", "shift",
+// and "bias" are found in src/pkg/math/bits.go
// Sqrt returns the square root of x.
//
@@ -18,48 +88,55 @@
// Sqrt(+Inf) = +Inf
// Sqrt(0) = 0
// Sqrt(x < 0) = NaN
+// Sqrt(NaN) = NaN
func Sqrt(x float64) float64 {
- if IsInf(x, 1) {
+ // special cases
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ switch {
+ case x != x || x > MaxFloat64: // IsNaN(x) || IsInf(x, 1):
return x
- }
-
- if x <= 0 {
- if x < 0 {
- return NaN()
- }
+ case x == 0:
return 0
+ case x < 0:
+ return NaN()
}
-
- y, exp := Frexp(x)
- for y < 0.5 {
- y = y * 2
- exp = exp - 1
+ ix := Float64bits(x)
+ // normalize x
+ exp := int((ix >> shift) & mask)
+ if exp == 0 { // subnormal x
+ for ix&1<<shift == 0 {
+ ix <<= 1
+ exp--
+ }
+ exp++
}
-
- if exp&1 != 0 {
- y = y * 2
- exp = exp - 1
+ exp -= bias + 1 // unbias exponent
+ ix &^= mask << shift
+ ix |= 1 << shift
+ if exp&1 == 1 { // odd exp, double x to make it even
+ ix <<= 1
}
- temp := 0.5 * (1 + y)
-
- for exp > 60 {
- temp = temp * float64(1<<30)
- exp = exp - 60
+ exp >>= 1 // exp = exp/2, exponent of square root
+ // generate sqrt(x) bit by bit
+ ix <<= 1
+ var q, s uint64 // q = sqrt(x)
+ r := uint64(1 << (shift + 1)) // r = moving bit from MSB to LSB
+ for r != 0 {
+ t := s + r
+ if t <= ix {
+ s = t + r
+ ix -= t
+ q += r
+ }
+ ix <<= 1
+ r >>= 1
}
- for exp < -60 {
- temp = temp / float64(1<<30)
- exp = exp + 60
+ // final rounding
+ if ix != 0 { // remainder, result not exact
+ q += q & 1 // round according to extra bit
}
- if exp >= 0 {
- exp = 1 << uint(exp/2)
- temp = temp * float64(exp)
- } else {
- exp = 1 << uint(-exp/2)
- temp = temp / float64(exp)
- }
-
- for i := 0; i <= 4; i++ {
- temp = 0.5 * (temp + x/temp)
- }
- return temp
+ ix = q>>1 + 0x3fe0000000000000 // q/2 + 0.5
+ ix += uint64(exp) << shift
+ return Float64frombits(ix)
}