func (p *exporter) float(x *Mpflt) { // extract sign (there is no -0) f := &x.Val sign := f.Sign() if sign == 0 { // x == 0 p.int(0) return } // x != 0 // 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 { Fatalf("exporter: internal error") } p.int(sign) p.int(exp) p.string(string(mant.Bytes())) }
func (bed BinaryVarintEncoderDecoder) Decode(r io.Reader, n *big.Float) error { var isInteger int8 var f float64 var exponent int32 n.SetUint64(0) if err := binary.Read(r, binary.BigEndian, &isInteger); err != nil { return err } if isInteger <= 0 { var x int64 var err error if x, err = binary.ReadVarint(miniByteReader{r}); err != nil { return err } n.SetInt64(x) n.SetPrec(ENCODER_DECODER_PREC) return nil } else { if err := binary.Read(r, binary.BigEndian, &f); err != nil { return err } if err := binary.Read(r, binary.BigEndian, &exponent); err != nil { return err } bed.tmp.SetFloat64(f) bed.tmp.SetPrec(ENCODER_DECODER_PREC) n.SetMantExp(bed.tmp, int(exponent)) return nil } }
// 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 (bed BinaryEncoderDecoder) Decode(r io.Reader, n *big.Float) error { var f float64 var exponent int32 n.SetUint64(0) if err := binary.Read(r, binary.BigEndian, &f); err != nil { return err } if err := binary.Read(r, binary.BigEndian, &exponent); err != nil { return err } bed.tmp.SetFloat64(f) bed.tmp.SetPrec(ENCODER_DECODER_PREC) n.SetMantExp(bed.tmp, int(exponent)) return nil }
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())) }
// Log returns a big.Float representation of the natural logarithm of // z. Precision is the same as the one of the argument. The function // panics if z is negative, returns -Inf when z = 0, and +Inf when z = // +Inf func Log(z *big.Float) *big.Float { // panic on negative z if z.Sign() == -1 { panic("Log: argument is negative") } // Log(0) = -Inf if z.Sign() == 0 { return big.NewFloat(math.Inf(-1)).SetPrec(z.Prec()) } prec := z.Prec() + 64 // guard digits one := big.NewFloat(1).SetPrec(prec) two := big.NewFloat(2).SetPrec(prec) four := big.NewFloat(4).SetPrec(prec) // Log(1) = 0 if z.Cmp(one) == 0 { return big.NewFloat(0).SetPrec(z.Prec()) } // Log(+Inf) = +Inf if z.IsInf() { return big.NewFloat(math.Inf(+1)).SetPrec(z.Prec()) } x := new(big.Float).SetPrec(prec) // if 0 < z < 1 we compute log(z) as -log(1/z) var neg bool if z.Cmp(one) < 0 { x.Quo(one, z) neg = true } else { x.Set(z) } // We scale up x until x >= 2**(prec/2), and then we'll be allowed // to use the AGM formula for Log(x). // // Double x until the condition is met, and keep track of the // number of doubling we did (needed to scale back later). lim := new(big.Float) lim.SetMantExp(two, int(prec/2)) k := 0 for x.Cmp(lim) < 0 { x.Mul(x, x) k++ } // Compute the natural log of x using the fact that // log(x) = π / (2 * AGM(1, 4/x)) // if // x >= 2**(prec/2), // where prec is the desired precision (in bits) pi := pi(prec) agm := agm(one, x.Quo(four, x)) // agm = AGM(1, 4/x) x.Quo(pi, x.Mul(two, agm)) // reuse x, we don't need it if neg { x.Neg(x) } // scale the result back multiplying by 2**-k // reuse lim to reduce allocations. x.Mul(x, lim.SetMantExp(one, -k)) return x.SetPrec(z.Prec()) }