| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 | 
							- package mssql
 
- import (
 
- 	"encoding/binary"
 
- 	"errors"
 
- 	"math"
 
- 	"math/big"
 
- )
 
- // http://msdn.microsoft.com/en-us/library/ee780893.aspx
 
- type Decimal struct {
 
- 	integer  [4]uint32
 
- 	positive bool
 
- 	prec     uint8
 
- 	scale    uint8
 
- }
 
- var scaletblflt64 [39]float64
 
- func (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())
 
- }
 
 
  |