Example #1
0
func decodeNonsortingDecimalValueWithoutExp(dec *inf.Dec, buf, tmp []byte) {
	bi := dec.UnscaledBig()
	bi.SetBytes(buf)

	// Set the decimal's scale.
	nDigits, _ := decimal.NumDigits(bi, tmp)
	dec.SetScale(inf.Scale(nDigits))
}
Example #2
0
func decodeNonsortingDecimalValue(dec *inf.Dec, negExp bool, buf, tmp []byte) error {
	// Decode the exponent.
	buf, e, err := DecodeUvarintAscending(buf)
	if err != nil {
		return err
	}
	if negExp {
		e = -e
	}

	bi := dec.UnscaledBig()
	bi.SetBytes(buf)

	// Set the decimal's scale.
	nDigits, _ := decimal.NumDigits(bi, tmp)
	exp := int(e) - nDigits
	dec.SetScale(inf.Scale(-exp))
	return nil
}
Example #3
0
// EncodeNonsortingDecimal returns the resulting byte slice with the
// encoded decimal appended to b. The encoding is limited compared to
// standard encodings in this package in that
// - It will not sort lexicographically
// - It does not encode its length or terminate itself, so decoding
//   functions must be provided the exact encoded bytes
//
// The encoding assumes that any number can be written as ±0.xyz... * 10^exp,
// where xyz is a digit string, x != 0, and the last decimal in xyz is also
// not 0.
//
// The encoding uses its first byte to split decimals into 7 distinct
// ordered groups (no NaN or Infinity support yet). The groups can
// be seen in encoding.go's const definition. Following this, the
// absolute value of the exponent of the decimal (as defined above)
// is encoded as an unsigned varint. Second, the absolute value of
// the digit string is added as a big-endian byte slice.
//
// All together, the encoding looks like:
//   <marker><uvarint exponent><big-endian encoded big.Int>.
//
// The markers are shared with the sorting decimal encoding as follows:
//  decimalNaN              -> decimalNaN
//  decimalNegativeInfinity -> decimalNegativeInfinity
//  decimalNegLarge         -> decimalNegValPosExp
//  decimalNegMedium        -> decimalNegValZeroExp
//  decimalNegSmall         -> decimalNegValNegExp
//  decimalZero             -> decimalZero
//  decimalPosSmall         -> decimalPosValNegExp
//  decimalPosMedium        -> decimalPosValZeroExp
//  decimalPosLarge         -> decimalPosValPosExp
//  decimalInfinity         -> decimalInfinity
//  decimalNaNDesc          -> decimalNaNDesc
//
func EncodeNonsortingDecimal(b []byte, d *inf.Dec) []byte {
	tmp := b[len(b):]
	neg := false
	bi := d.UnscaledBig()
	switch bi.Sign() {
	case -1:
		neg = true

		// Make a deep copy of the decimal's big.Int by calling Neg.
		// We shouldn't be modifying the provided argument's
		// internal big.Int, so this works like a copy-on-write scheme.
		bi = new(big.Int)
		bi = bi.Neg(d.UnscaledBig())
	case 0:
		return append(b, decimalZero)
	}

	// Determine the exponent of the decimal, with the
	// exponent defined as .xyz * 10^exp.
	nDigits, formatted := decimal.NumDigits(bi, tmp)
	e := nDigits - int(d.Scale())

	// Handle big.Int having zeros at the end of its
	// string by dividing them off (ie. 12300 -> 123).
	bi = normalizeBigInt(bi, bi == d.UnscaledBig(), formatted, tmp)
	bNat := bi.Bits()

	var buf []byte
	if n := UpperBoundNonsortingDecimalSize(d); n <= cap(b)-len(b) {
		// We append the marker directly to the input buffer b below, so
		// we are off by 1 for each of these, which explains the adjustments.
		buf = b[len(b)+1 : len(b)+1]
	} else {
		buf = make([]byte, 0, n-1)
	}

	switch {
	case neg && e > 0:
		b = append(b, decimalNegLarge)
		buf = encodeNonsortingDecimalValue(uint64(e), bNat, buf)
		return append(b, buf...)
	case neg && e == 0:
		b = append(b, decimalNegMedium)
		buf = encodeNonsortingDecimalValueWithoutExp(bNat, buf)
		return append(b, buf...)
	case neg && e < 0:
		b = append(b, decimalNegSmall)
		buf = encodeNonsortingDecimalValue(uint64(-e), bNat, buf)
		return append(b, buf...)
	case !neg && e < 0:
		b = append(b, decimalPosSmall)
		buf = encodeNonsortingDecimalValue(uint64(-e), bNat, buf)
		return append(b, buf...)
	case !neg && e == 0:
		b = append(b, decimalPosMedium)
		buf = encodeNonsortingDecimalValueWithoutExp(bNat, buf)
		return append(b, buf...)
	case !neg && e > 0:
		b = append(b, decimalPosLarge)
		buf = encodeNonsortingDecimalValue(uint64(e), bNat, buf)
		return append(b, buf...)
	}
	panic("unreachable")
}