mirror of
https://github.com/golang/go
synced 2024-11-20 03:34:40 -07:00
102436e800
When emulating ARM FSQRT instruction, the sqrt function itself should not use any floating point arithmetics, otherwise it will clobber the user software FP registers. Fortunately, the sqrt function only uses floating point instructions to test for corner cases, so it's easy to make that function does all it job using pure integer arithmetic only. I've verified that after this change, runtime.stepflt and runtime.sqrt doesn't contain any call to _sfloat. (Perhaps we should add //go:nosfloat to make the compiler enforce this?) Fixes #10641. Change-Id: Ida4742c49000fae4fea4649f28afde630ce4c576 Signed-off-by: Shenghou Ma <minux@golang.org> Reviewed-on: https://go-review.googlesource.com/9570 Reviewed-by: Dave Cheney <dave@cheney.net> Reviewed-by: Keith Randall <khr@golang.org>
154 lines
5.2 KiB
Go
154 lines
5.2 KiB
Go
// 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.
|
|
|
|
// Copy of math/sqrt.go, here for use by ARM softfloat.
|
|
// Modified to not use any floating point arithmetic so
|
|
// that we don't clobber any floating-point registers
|
|
// while emulating the sqrt instruction.
|
|
|
|
package runtime
|
|
|
|
// 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 algebraic 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.
|
|
|
|
const (
|
|
float64Mask = 0x7FF
|
|
float64Shift = 64 - 11 - 1
|
|
float64Bias = 1023
|
|
float64NaN = 0x7FF8000000000001
|
|
float64Inf = 0x7FF0000000000000
|
|
maxFloat64 = 1.797693134862315708145274237317043567981e+308 // 2**1023 * (2**53 - 1) / 2**52
|
|
)
|
|
|
|
// isnanu returns whether ix represents a NaN floating point number.
|
|
func isnanu(ix uint64) bool {
|
|
exp := (ix >> float64Shift) & float64Mask
|
|
sig := ix << (64 - float64Shift) >> (64 - float64Shift)
|
|
return exp == float64Mask && sig != 0
|
|
}
|
|
|
|
func sqrt(ix uint64) uint64 {
|
|
// special cases
|
|
switch {
|
|
case ix == 0 || ix == 1<<63: // x == 0
|
|
return ix
|
|
case isnanu(ix): // x != x
|
|
return ix
|
|
case ix&(1<<63) != 0: // x < 0
|
|
return float64NaN
|
|
case ix == float64Inf: // x > MaxFloat
|
|
return ix
|
|
}
|
|
// normalize x
|
|
exp := int((ix >> float64Shift) & float64Mask)
|
|
if exp == 0 { // subnormal x
|
|
for ix&1<<float64Shift == 0 {
|
|
ix <<= 1
|
|
exp--
|
|
}
|
|
exp++
|
|
}
|
|
exp -= float64Bias // unbias exponent
|
|
ix &^= float64Mask << float64Shift
|
|
ix |= 1 << float64Shift
|
|
if exp&1 == 1 { // odd exp, double x to make it even
|
|
ix <<= 1
|
|
}
|
|
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 << (float64Shift + 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
|
|
}
|
|
// final rounding
|
|
if ix != 0 { // remainder, result not exact
|
|
q += q & 1 // round according to extra bit
|
|
}
|
|
ix = q>>1 + uint64(exp-1+float64Bias)<<float64Shift // significand + biased exponent
|
|
return ix
|
|
}
|