// floatSqrt computes the square root of x using Newton's method. // TODO: Use a better algorithm such as the one from math/sqrt.go. func floatSqrt(c Context, x *big.Float) *big.Float { switch x.Sign() { case -1: Errorf("square root of negative number") case 0: return newFloat(c) } // Each iteration computes // z = z - (z²-x)/2z // z holds the result so far. A good starting point is to halve the exponent. // Experiments show we converge in only a handful of iterations. z := newFloat(c) exp := x.MantExp(z) z.SetMantExp(z, exp/2) // Intermediates, allocated once. zSquared := newFloat(c) num := newFloat(c) den := newFloat(c) for loop := newLoop(c.Config(), "sqrt", x, 1); ; { zSquared.Mul(z, z) num.Sub(zSquared, x) den.Mul(floatTwo, z) num.Quo(num, den) z.Sub(z, num) if loop.done(z) { break } } return z }
// smallRat reports whether x would lead to "reasonably"-sized fraction // if converted to a *big.Rat. func smallRat(x *big.Float) bool { if !x.IsInf() { e := x.MantExp(nil) return -maxExp < e && e < maxExp } return false }
// toRat returns the fraction corresponding to x, or nil // if x cannot be represented as a fraction a/b because // its components a or b are too large. func toRat(x *big.Float) *big.Rat { m := newFloat() e := x.MantExp(m) // fail to convert if fraction components are too large if e <= maxExp || e >= maxExp { return nil } // convert mantissa to big.Int value by shifting by ecorr ecorr := int(m.MinPrec()) a, _ := m.SetMantExp(m, ecorr).Int(nil) e -= ecorr // correct exponent // compute actual fraction b := big.NewInt(1) switch { case e < 0: b.Lsh(b, uint(-e)) case e > 0: a.Lsh(a, uint(e)) } return new(big.Rat).SetFrac(a, b) }
// floatLog computes natural log(x) using the Maclaurin series for log(1-x). func floatLog(x *big.Float) *big.Float { if x.Sign() <= 0 { Errorf("log of non-positive value") } // The series wants x < 1, and log 1/x == -log x, so exploit that. invert := false if x.Cmp(floatOne) > 0 { invert = true xx := newF() xx.Quo(floatOne, x) x = xx } // x = mantissa * 2**exp, and 0.5 <= mantissa < 1. // So log(x) is log(mantissa)+exp*log(2), and 1-x will be // between 0 and 0.5, so the series for 1-x will converge well. // (The series converges slowly in general.) mantissa := newF() exp2 := x.MantExp(mantissa) exp := newF().SetInt64(int64(exp2)) exp.Mul(exp, floatLog2) if invert { exp.Neg(exp) } // y = 1-x (whereupon x = 1-y and we use that in the series). y := newF().SetInt64(1) y.Sub(y, mantissa) // The Maclaurin series for log(1-y) == log(x) is: -y - y²/2 - y³/3 ... yN := newF().Set(y) term := newF() n := newF().Set(floatOne) z := newF() // This is the slowest-converging series, so we add a factor of ten to the cutoff. // Only necessary when FloatPrec is at or beyond constPrecisionInBits. loop := newLoop("log", y, 40) for { term.Set(yN) term.Quo(term, n) z.Sub(z, term) if loop.terminate(z) { break } // Advance y**index (multiply by y). yN.Mul(yN, y) n.Add(n, floatOne) } if invert { z.Neg(z) } z.Add(z, exp) return z }
func (bed BinaryEncoderDecoder) Encode(w io.Writer, n *big.Float) error { exponent := n.MantExp(bed.tmp) f, _ := bed.tmp.Float64() if err := binary.Write(w, binary.BigEndian, f); err != nil { return err } return binary.Write(w, binary.BigEndian, int32(exponent)) }
// Sqrt returns a big.Float representation of the square root of // z. Precision is the same as the one of the argument. The function // panics if z is negative, returns ±0 when z = ±0, and +Inf when z = // +Inf. func Sqrt(z *big.Float) *big.Float { // panic on negative z if z.Sign() == -1 { panic("Sqrt: argument is negative") } // √±0 = ±0 if z.Sign() == 0 { return big.NewFloat(float64(z.Sign())) } // √+Inf = +Inf if z.IsInf() { return big.NewFloat(math.Inf(+1)) } // Compute √(a·2**b) as // √(a)·2**b/2 if b is even // √(2a)·2**b/2 if b > 0 is odd // √(0.5a)·2**b/2 if b < 0 is odd // // The difference in the odd exponent case is due to the fact that // exp/2 is rounded in different directions when exp is negative. mant := new(big.Float) exp := z.MantExp(mant) switch exp % 2 { case 1: mant.Mul(big.NewFloat(2), mant) case -1: mant.Mul(big.NewFloat(0.5), mant) } // Solving x² - z = 0 directly requires a Quo call, but it's // faster for small precisions. // // Solving 1/x² - z = 0 avoids the Quo call and is much faster for // high precisions. // // Use sqrtDirect for prec <= 128 and sqrtInverse for prec > 128. var x *big.Float if z.Prec() <= 128 { x = sqrtDirect(mant) } else { x = sqrtInverse(mant) } // re-attach the exponent and return return x.SetMantExp(x, exp/2) }
func (p *exporter) float(x constant.Value) { if x.Kind() != constant.Float { log.Fatalf("gcimporter: unexpected constant %v, want float", x) } // extract sign (there is no -0) sign := constant.Sign(x) if sign == 0 { // x == 0 p.int(0) return } // x != 0 var f big.Float if v, exact := constant.Float64Val(x); exact { // float64 f.SetFloat64(v) } else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int { // TODO(gri): add big.Rat accessor to constant.Value. r := valueToRat(num) f.SetRat(r.Quo(r, valueToRat(denom))) } else { // Value too large to represent as a fraction => inaccessible. // TODO(gri): add big.Float accessor to constant.Value. f.SetFloat64(math.MaxFloat64) // FIXME } // extract exponent such that 0.5 <= m < 1.0 var m big.Float exp := f.MantExp(&m) // extract mantissa as *big.Int // - set exponent large enough so mant satisfies mant.IsInt() // - get *big.Int from mant m.SetMantExp(&m, int(m.MinPrec())) mant, acc := m.Int(nil) if acc != big.Exact { log.Fatalf("gcimporter: internal error") } p.int(sign) p.int(exp) p.string(string(mant.Bytes())) }
func (bed BinaryIntEncoderDecoder) Encode(w io.Writer, n *big.Float) error { if n.IsInt() { x, _ := n.Int64() // TODO - if accuracy is not Exact, then use the other path if err := binary.Write(w, binary.BigEndian, int8(0)); err != nil { return err } return binary.Write(w, binary.BigEndian, x) } else { if err := binary.Write(w, binary.BigEndian, int8(1)); err != nil { return err } exponent := n.MantExp(bed.tmp) f, _ := bed.tmp.Float64() if err := binary.Write(w, binary.BigEndian, f); err != nil { return err } return binary.Write(w, binary.BigEndian, int32(exponent)) } }
// floatSqrt computes the square root of x using Newton's method. // TODO: Use a better algorithm such as the one from math/sqrt.go. func floatSqrt(x *big.Float) *big.Float { switch x.Sign() { case -1: Errorf("square root of negative number") case 0: return newF() } // Each iteration computes // z = z - (z²-x)/2z // delta holds the difference between the result // this iteration and the previous. The loop stops // when it hits zero. // z holds the result so far. A good starting point is to halve the exponent. // Experiments show we converge in only a handful of iterations. z := newF() exp := x.MantExp(z) z.SetMantExp(z, exp/2) // Intermediates, allocated once. zSquared := newF() num := newF() den := newF() loop := newLoop("sqrt", x, 1) for { zSquared.Mul(z, z) num.Sub(zSquared, x) den.Mul(floatTwo, z) num.Quo(num, den) z.Sub(z, num) if loop.terminate(z) { break } } return z }
// fast path for z**w when w is an integer func powInt(z *big.Float, w int) *big.Float { // get mantissa and exponent of z mant := new(big.Float) exp := z.MantExp(mant) // result's exponent exp = exp * w // result's mantissa x := big.NewFloat(1).SetPrec(z.Prec()) // Classic right-to-left binary exponentiation for w > 0 { if w%2 == 1 { x.Mul(x, mant) } w >>= 1 mant.Mul(mant, mant) } return new(big.Float).SetMantExp(x, exp) }
func (bed BinaryVarintEncoderDecoder) Encode(w io.Writer, n *big.Float) error { if n.IsInt() { x, _ := n.Int64() // TODO - if accuracy is not Exact, then use the other path buf := make([]byte, binary.MaxVarintLen64) nBytes := binary.PutVarint(buf, x) if _, err := w.Write([]byte{byte(0)}); err != nil { return err } _, err := w.Write(buf[0:nBytes]) return err } else { if err := binary.Write(w, binary.BigEndian, int8(1)); err != nil { return err } exponent := n.MantExp(bed.tmp) f, _ := bed.tmp.Float64() if err := binary.Write(w, binary.BigEndian, f); err != nil { return err } return binary.Write(w, binary.BigEndian, int32(exponent)) } }