| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 | package mssqlimport (	"encoding/binary"	"errors"	"math"	"math/big")// http://msdn.microsoft.com/en-us/library/ee780893.aspxtype Decimal struct {	integer  [4]uint32	positive bool	prec     uint8	scale    uint8}var scaletblflt64 [39]float64func (d Decimal) ToFloat64() float64 {	val := float64(0)	for i := 3; i >= 0; i-- {		val *= 0x100000000		val += float64(d.integer[i])	}	if !d.positive {		val = -val	}	if d.scale != 0 {		val /= scaletblflt64[d.scale]	}	return val}func Float64ToDecimal(f float64) (Decimal, error) {	var dec Decimal	if math.IsNaN(f) {		return dec, errors.New("NaN")	}	if math.IsInf(f, 0) {		return dec, errors.New("Infinity can't be converted to decimal")	}	dec.positive = f >= 0	if !dec.positive {		f = math.Abs(f)	}	if f > 3.402823669209385e+38 {		return dec, errors.New("Float value is out of range")	}	dec.prec = 20	var integer float64	for dec.scale = 0; dec.scale <= 20; dec.scale++ {		integer = f * scaletblflt64[dec.scale]		_, frac := math.Modf(integer)		if frac == 0 {			break		}	}	for i := 0; i < 4; i++ {		mod := math.Mod(integer, 0x100000000)		integer -= mod		integer /= 0x100000000		dec.integer[i] = uint32(mod)	}	return dec, nil}func init() {	var acc float64 = 1	for i := 0; i <= 38; i++ {		scaletblflt64[i] = acc		acc *= 10	}}func (d Decimal) Bytes() []byte {	bytes := make([]byte, 16)	binary.BigEndian.PutUint32(bytes[0:4], d.integer[3])	binary.BigEndian.PutUint32(bytes[4:8], d.integer[2])	binary.BigEndian.PutUint32(bytes[8:12], d.integer[1])	binary.BigEndian.PutUint32(bytes[12:16], d.integer[0])	var x big.Int	x.SetBytes(bytes)	if !d.positive {		x.Neg(&x)	}	return scaleBytes(x.String(), d.scale)}func scaleBytes(s string, scale uint8) []byte {	z := make([]byte, 0, len(s)+1)	if s[0] == '-' || s[0] == '+' {		z = append(z, byte(s[0]))		s = s[1:]	}	pos := len(s) - int(scale)	if pos <= 0 {		z = append(z, byte('0'))	} else if pos > 0 {		z = append(z, []byte(s[:pos])...)	}	if scale > 0 {		z = append(z, byte('.'))		for pos < 0 {			z = append(z, byte('0'))			pos++		}		z = append(z, []byte(s[pos:])...)	}	return z}func (d Decimal) String() string {	return string(d.Bytes())}
 |