示例#1
0
// decimalMandE computes and returns the mantissa M and exponent E for d.
//
// The mantissa is a base-100 representation of the value. The exponent E
// determines where to put the decimal point.
//
// Each centimal digit of the mantissa is stored in a byte. If the value of the
// centimal digit is X (hence X>=0 and X<=99) then the byte value will be 2*X+1
// for every byte of the mantissa, except for the last byte which will be
// 2*X+0. The mantissa must be the minimum number of bytes necessary to
// represent the value; trailing X==0 digits are omitted.  This means that the
// mantissa will never contain a byte with the value 0x00.
//
// If we assume all digits of the mantissa occur to the right of the decimal
// point, then the exponent E is the power of one hundred by which one must
// multiply the mantissa to recover the original value.
func decimalMandE(d decimal.Decimal, tmp []byte) (int, []byte) {
	bs := d.BigInt().String()
	if bs[0] == '-' {
		bs = bs[1:]
	}

	// The exponent will be the combination of the decimal's exponent, and the
	// number of digits in the big.Int.
	e10 := int(d.Exponent()) + len(bs)

	// Strip off trailing zeros in big.Int's string representation.
	for bs[len(bs)-1] == '0' {
		bs = bs[:len(bs)-1]
	}

	// Make sure b is large enough to hold the smallest even number of bytes
	// greater than or equal to the size of bs + 1.
	if n := 2 * ((len(bs) + 2) / 2); n <= cap(tmp) {
		tmp = tmp[:len(bs)+1]
	} else {
		tmp = make([]byte, len(bs)+1, n)
	}
	tmp[0] = '0'
	copy(tmp[1:], []byte(bs))

	// Convert the power-10 exponent to a power of 100 exponent.
	var e100 int
	if e10 >= 0 {
		e100 = (e10 + 1) / 2
	} else {
		e100 = e10 / 2
	}
	// Strip the leading 0 if the conversion to e100 did not add a multiple of
	// 10.
	if e100*2 == e10 {
		tmp = tmp[1:]
	}

	// Ensure that the number of digits is even.
	if len(tmp)%2 != 0 {
		tmp = append(tmp, '0')
	}

	// Convert the base-10 'b' slice to a base-100 'm' slice. We do this
	// conversion in place to avoid an allocation.
	m := tmp[:len(tmp)/2]
	for i := 0; i < len(tmp); i += 2 {
		accum := 10*int(tmp[i]-'0') + int(tmp[i+1]-'0')
		// The bytes are encoded as 2n+1.
		m[i/2] = byte(2*accum + 1)
	}
	// The last byte is encoded as 2n+0.
	m[len(m)-1]--

	return e100, m
}
示例#2
0
// SetDecimal encodes the specified decimal value into the bytes field of
// the receiver, sets the tag and clears the checksum.
func (v *Value) SetDecimal(d decimal.Decimal) error {
	// TODO(nvanbenschoten) Deal with exponent normalization.
	bb, err := d.BigInt().GobEncode()
	if err != nil {
		return fmt.Errorf("failed to Gob encode decimal's big.Int: %v", err)
	}
	v.RawBytes = make([]byte, headerSize+binary.MaxVarintLen64+len(bb))
	n := binary.PutVarint(v.RawBytes[headerSize:], int64(d.Exponent()))
	copy(v.RawBytes[headerSize+n:], bb)
	v.RawBytes = v.RawBytes[:headerSize+n+len(bb)]
	v.setTag(ValueType_DECIMAL)
	return nil
}