Example #1
0
// cmpNormBig compares x and y in the range [0.1, 0.999...] and
// returns true if x > y.
func cmpNormBig(x *big.Int, xs int32, y *big.Int, ys int32) (ok bool) {
	diff := xs - ys
	if diff < 0 {
		x1 := new(big.Int).Set(x)
		return checked.MulBigPow10(x1, -diff).Cmp(y) > 0
	}
	y1 := new(big.Int).Set(y)
	return x.Cmp(checked.MulBigPow10(y1, diff)) > 0
}
Example #2
0
func (z *Big) quoBig(x, y *Big) *Big {
	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 cmpNormBig(&x.mantissa, xp, &y.mantissa, 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
	}
	if shift > 0 {
		xs := checked.MulBigPow10(new(big.Int).Set(&x.mantissa), shift)
		return z.quoBigAndRound(xs, &y.mantissa)
	}

	// shift < 0
	ns, ok := checked.Sub32(xp, zp)
	if !ok {
		z.form = inf
		return z
	}
	shift, ok = checked.Sub32(ns, yp)
	if !ok {
		z.form = inf
		return z
	}
	ys := checked.MulBigPow10(new(big.Int).Set(&y.mantissa), shift)
	return z.quoBigAndRound(&x.mantissa, ys)
}
Example #3
0
// 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
}
Example #4
0
// Int returns x as a big.Int, truncating the fractional portion, if any.
func (x *Big) Int() *big.Int {
	var b big.Int
	if x.isCompact() {
		b.SetInt64(x.compact)
	} else {
		b.Set(&x.mantissa)
	}
	if x.scale == 0 {
		return &b
	}
	if x.scale < 0 {
		return checked.MulBigPow10(&b, -x.scale)
	}
	p := pow.BigTen(int64(x.scale))
	return b.Div(&b, &p)
}
Example #5
0
func (z *Big) addBig(x, y *Big) *Big {
	hi, lo := x, y
	if hi.scale < lo.scale {
		hi, lo = lo, hi
	}

	inc := hi.scale - lo.scale
	scaled := checked.MulBigPow10(&lo.mantissa, inc)
	z.mantissa.Add(&hi.mantissa, scaled)
	z.compact = c.Inflated
	z.scale = hi.scale
	if z.mantissa.Sign() == 0 {
		z.form = zero
	}
	return z
}
Example #6
0
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)
}
Example #7
0
// 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)
}