// Int64 returns x as an int64, truncating the fractional portion, if any. func (x *Big) Int64() int64 { var b int64 if x.isCompact() { b = x.compact } else { b = x.mantissa.Int64() } if x.scale == 0 { return b } if x.scale < 0 { // Undefined. checked.MulPow10 returns 0 when ok is false. // IMO, 0 is a better choice than 1 << 64 - 1 because it could cause a // division by zero panic which would be a clear indication something is // incorrect. b, _ = checked.MulPow10(b, -x.scale) return b } p, ok := pow.Ten64(int64(x.scale)) // See above comment. if !ok { return 0 } return b / p }
// cmpNorm compares x and y in the range [0.1, 0.999...] and // returns true if x > y. func cmpNorm(x int64, xs int32, y int64, ys int32) (ok bool) { if debug && (x == 0 || y == 0) { panic("x and/or y cannot be zero") } if diff := xs - ys; diff != 0 { if diff < 0 { x, ok = checked.MulPow10(x, -diff) } else { y, ok = checked.MulPow10(y, diff) } } if x != c.Inflated { if y != c.Inflated { return arith.AbsCmp(x, y) > 0 } return false } return true }
// addCompact sets z to x + y and returns z. func (z *Big) addCompact(x, y *Big) *Big { // Fast path: if the scales are the same we can just add // without adjusting either number. if x.scale == y.scale { z.scale = x.scale sum, ok := checked.Add(x.compact, y.compact) if ok { z.compact = sum if sum == 0 { z.form = zero } } else { z.mantissa.Add(big.NewInt(x.compact), big.NewInt(y.compact)) z.compact = c.Inflated if z.mantissa.Sign() == 0 { z.form = zero } } return z } // Guess the scales. We need to inflate lo. hi, lo := x, y if hi.scale < lo.scale { hi, lo = lo, hi } // Power of 10 we need to multiply our lo value by in order // to equalize the scales. inc := hi.scale - lo.scale z.scale = hi.scale scaledLo, ok := checked.MulPow10(lo.compact, inc) if ok { sum, ok := checked.Add(hi.compact, scaledLo) if ok { z.compact = sum return z } } scaled := checked.MulBigPow10(big.NewInt(lo.compact), inc) z.mantissa.Add(scaled, big.NewInt(hi.compact)) z.compact = c.Inflated if z.mantissa.Sign() == 0 { z.form = zero } return z }
func (z *Big) quoCompact(x, y *Big) *Big { if x.compact == 0 { if y.compact == 0 { panic(ErrNaN{"division of zero by zero"}) } z.form = 0 return z } scale, ok := checked.Sub32(x.scale, y.scale) if !ok { z.form = inf return z } zp := z.ctx.prec() xp := int32(x.Prec()) yp := int32(y.Prec()) // Multiply y by 10 if x' > y' if cmpNorm(x.compact, xp, y.compact, yp) { yp-- } scale, ok = checked.Int32(int64(scale) + int64(yp) - int64(xp) + int64(zp)) if !ok { z.form = inf return z } z.scale = scale shift, ok := checked.SumSub(zp, yp, xp) if !ok { z.form = inf return z } xs, ys := x.compact, y.compact if shift > 0 { xs, ok = checked.MulPow10(x.compact, shift) if !ok { x0 := checked.MulBigPow10(big.NewInt(x.compact), shift) return z.quoBigAndRound(x0, big.NewInt(y.compact)) } return z.quoAndRound(xs, ys) } // shift < 0 ns, ok := checked.Sub32(xp, zp) if !ok { z.form = inf return z } // new scale == yp, so no inflation needed. if ns == yp { return z.quoAndRound(xs, ys) } shift, ok = checked.Sub32(ns, yp) if !ok { z.form = inf return z } ys, ok = checked.MulPow10(ys, shift) if !ok { y0 := checked.MulBigPow10(big.NewInt(y.compact), shift) return z.quoBigAndRound(big.NewInt(x.compact), y0) } return z.quoAndRound(xs, ys) }
// Cmp compares d and x and returns: // // -1 if z < x // 0 if z == x // +1 if z > x // // It does not modify d or x. func (z *Big) Cmp(x *Big) int { // Check for same pointers. if z == x { return 0 } // Same scales means we can compare straight across. if z.scale == x.scale { if z.isCompact() && x.isCompact() { if z.compact > x.compact { return +1 } if z.compact < x.compact { return -1 } return 0 } if z.isInflated() && x.isInflated() { if z.mantissa.Sign() != x.mantissa.Sign() { return z.mantissa.Sign() } if z.scale < 0 { return z.mantissa.Cmp(&x.mantissa) } zb := z.mantissa.Bits() xb := x.mantissa.Bits() min := len(zb) if len(xb) < len(zb) { min = len(xb) } i := 0 for i < min-1 && zb[i] == xb[i] { i++ } if zb[i] > xb[i] { return +1 } if zb[i] < xb[i] { return -1 } return 0 } } // Different scales -- check signs and/or if they're // both zero. ds := z.Sign() xs := x.Sign() switch { case ds > xs: return +1 case ds < xs: return -1 case ds == 0 && xs == 0: return 0 } // Scales aren't equal, the signs are the same, and both // are non-zero. dl := int32(z.Prec()) - z.scale xl := int32(x.Prec()) - x.scale if dl > xl { return +1 } if dl < xl { return -1 } // We need to inflate one of the numbers. dc := z.compact // hi xc := x.compact // lo var swap bool hi, lo := z, x if hi.scale < lo.scale { hi, lo = lo, hi dc, xc = xc, dc swap = true // d is lo } diff := hi.scale - lo.scale if diff <= c.BadScale { var ok bool xc, ok = checked.MulPow10(xc, diff) if !ok && dc == c.Inflated { // d is lo if swap { zm := new(big.Int).Set(&z.mantissa) return checked.MulBigPow10(zm, diff).Cmp(&x.mantissa) } // x is lo xm := new(big.Int).Set(&x.mantissa) return z.mantissa.Cmp(checked.MulBigPow10(xm, diff)) } } if swap { dc, xc = xc, dc } if dc != c.Inflated { if xc != c.Inflated { return arith.AbsCmp(dc, xc) } return big.NewInt(dc).Cmp(&x.mantissa) } if xc != c.Inflated { return z.mantissa.Cmp(big.NewInt(xc)) } return z.mantissa.Cmp(&x.mantissa) }