mirror of
https://github.com/shopspring/decimal.git
synced 2024-11-22 12:30:49 +01:00
ensure decimal is initialized for new methods
This commit is contained in:
parent
5359bc7cb4
commit
54dc68463b
2 changed files with 68 additions and 51 deletions
110
decimal.go
110
decimal.go
|
@ -337,48 +337,6 @@ func (d Decimal) String() string {
|
|||
return d.string(true)
|
||||
}
|
||||
|
||||
func (d Decimal) string(trimTrailingZeros bool) string {
|
||||
if d.exp >= 0 {
|
||||
return d.rescale(0).value.String()
|
||||
}
|
||||
|
||||
abs := new(big.Int).Abs(d.value)
|
||||
str := abs.String()
|
||||
|
||||
var intPart, fractionalPart string
|
||||
dExpInt := int(d.exp)
|
||||
if len(str) > -dExpInt {
|
||||
intPart = str[:len(str)+dExpInt]
|
||||
fractionalPart = str[len(str)+dExpInt:]
|
||||
} else {
|
||||
intPart = "0"
|
||||
|
||||
num0s := -dExpInt - len(str)
|
||||
fractionalPart = strings.Repeat("0", num0s) + str
|
||||
}
|
||||
|
||||
if trimTrailingZeros {
|
||||
i := len(fractionalPart) - 1
|
||||
for ; i >= 0; i-- {
|
||||
if fractionalPart[i] != '0' {
|
||||
break
|
||||
}
|
||||
}
|
||||
fractionalPart = fractionalPart[:i+1]
|
||||
}
|
||||
|
||||
number := intPart
|
||||
if len(fractionalPart) > 0 {
|
||||
number += "." + fractionalPart
|
||||
}
|
||||
|
||||
if d.value.Sign() < 0 {
|
||||
return "-" + number
|
||||
}
|
||||
|
||||
return number
|
||||
}
|
||||
|
||||
// StringFixed returns a rounded fixed-point string with places digits after
|
||||
// the decimal point.
|
||||
//
|
||||
|
@ -406,24 +364,30 @@ func (d Decimal) StringFixed(places int32) string {
|
|||
// NewFromFloat(545).Round(-1).String() // output: "550"
|
||||
//
|
||||
func (d Decimal) Round(places int32) Decimal {
|
||||
almost := d.rescale(-(places + 1))
|
||||
if almost.value.Sign() < 0 {
|
||||
almost.value.Sub(almost.value, fiveInt)
|
||||
// truncate to places + 1
|
||||
ret := d.rescale(-(places + 1))
|
||||
|
||||
// add sign(d) * 0.5
|
||||
if ret.value.Sign() < 0 {
|
||||
ret.value.Sub(ret.value, fiveInt)
|
||||
} else {
|
||||
almost.value.Add(almost.value, fiveInt)
|
||||
ret.value.Add(ret.value, fiveInt)
|
||||
}
|
||||
|
||||
_, m := almost.value.DivMod(almost.value, tenInt, new(big.Int))
|
||||
almost.exp += 1
|
||||
if almost.value.Sign() < 0 && m.Cmp(zeroInt) != 0 {
|
||||
almost.value.Add(almost.value, oneInt)
|
||||
// floor for positive numbers, ceil for negative numbers
|
||||
_, m := ret.value.DivMod(ret.value, tenInt, new(big.Int))
|
||||
ret.exp += 1
|
||||
if ret.value.Sign() < 0 && m.Cmp(zeroInt) != 0 {
|
||||
ret.value.Add(ret.value, oneInt)
|
||||
}
|
||||
|
||||
return almost
|
||||
return ret
|
||||
}
|
||||
|
||||
// Floor returns the nearest integer value less than or equal to d.
|
||||
func (d Decimal) Floor() Decimal {
|
||||
d.ensureInitialized()
|
||||
|
||||
exp := big.NewInt(10)
|
||||
exp.Exp(exp, big.NewInt(int64(-d.exp)), nil)
|
||||
z := new(big.Int).Div(d.value, exp)
|
||||
|
@ -432,6 +396,8 @@ func (d Decimal) Floor() Decimal {
|
|||
|
||||
// Ceil returns the nearest integer value greater than or equal to d.
|
||||
func (d Decimal) Ceil() Decimal {
|
||||
d.ensureInitialized()
|
||||
|
||||
exp := big.NewInt(10)
|
||||
exp.Exp(exp, big.NewInt(int64(-d.exp)), nil)
|
||||
z, m := new(big.Int).DivMod(d.value, exp, new(big.Int))
|
||||
|
@ -518,6 +484,48 @@ func (d Decimal) StringScaled(exp int32) string {
|
|||
return d.rescale(exp).String()
|
||||
}
|
||||
|
||||
func (d Decimal) string(trimTrailingZeros bool) string {
|
||||
if d.exp >= 0 {
|
||||
return d.rescale(0).value.String()
|
||||
}
|
||||
|
||||
abs := new(big.Int).Abs(d.value)
|
||||
str := abs.String()
|
||||
|
||||
var intPart, fractionalPart string
|
||||
dExpInt := int(d.exp)
|
||||
if len(str) > -dExpInt {
|
||||
intPart = str[:len(str)+dExpInt]
|
||||
fractionalPart = str[len(str)+dExpInt:]
|
||||
} else {
|
||||
intPart = "0"
|
||||
|
||||
num0s := -dExpInt - len(str)
|
||||
fractionalPart = strings.Repeat("0", num0s) + str
|
||||
}
|
||||
|
||||
if trimTrailingZeros {
|
||||
i := len(fractionalPart) - 1
|
||||
for ; i >= 0; i-- {
|
||||
if fractionalPart[i] != '0' {
|
||||
break
|
||||
}
|
||||
}
|
||||
fractionalPart = fractionalPart[:i+1]
|
||||
}
|
||||
|
||||
number := intPart
|
||||
if len(fractionalPart) > 0 {
|
||||
number += "." + fractionalPart
|
||||
}
|
||||
|
||||
if d.value.Sign() < 0 {
|
||||
return "-" + number
|
||||
}
|
||||
|
||||
return number
|
||||
}
|
||||
|
||||
func (d *Decimal) ensureInitialized() {
|
||||
if d.value == nil {
|
||||
d.value = new(big.Int)
|
||||
|
|
|
@ -423,12 +423,21 @@ func TestDecimal_Uninitialized(t *testing.T) {
|
|||
a.Sub(b),
|
||||
a.Mul(b),
|
||||
a.Div(New(1, -1)),
|
||||
a.Floor(),
|
||||
a.Ceil(),
|
||||
a.Round(2),
|
||||
}
|
||||
|
||||
for _, d := range decs {
|
||||
if d.String() != "0" {
|
||||
t.Errorf("expected 0, got %s", d.String())
|
||||
}
|
||||
if d.StringFixed(3) != "0.000" {
|
||||
t.Errorf("expected 0, got %s", d.StringFixed(3))
|
||||
}
|
||||
if d.StringScaled(-2) != "0" {
|
||||
t.Errorf("expected 0, got %s", d.StringScaled(-2))
|
||||
}
|
||||
}
|
||||
|
||||
if a.Cmp(b) != 0 {
|
||||
|
|
Loading…
Reference in a new issue