mirror of
https://github.com/shopspring/decimal.git
synced 2024-11-23 04:40: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)
|
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
|
// StringFixed returns a rounded fixed-point string with places digits after
|
||||||
// the decimal point.
|
// the decimal point.
|
||||||
//
|
//
|
||||||
|
@ -406,24 +364,30 @@ func (d Decimal) StringFixed(places int32) string {
|
||||||
// NewFromFloat(545).Round(-1).String() // output: "550"
|
// NewFromFloat(545).Round(-1).String() // output: "550"
|
||||||
//
|
//
|
||||||
func (d Decimal) Round(places int32) Decimal {
|
func (d Decimal) Round(places int32) Decimal {
|
||||||
almost := d.rescale(-(places + 1))
|
// truncate to places + 1
|
||||||
if almost.value.Sign() < 0 {
|
ret := d.rescale(-(places + 1))
|
||||||
almost.value.Sub(almost.value, fiveInt)
|
|
||||||
|
// add sign(d) * 0.5
|
||||||
|
if ret.value.Sign() < 0 {
|
||||||
|
ret.value.Sub(ret.value, fiveInt)
|
||||||
} else {
|
} else {
|
||||||
almost.value.Add(almost.value, fiveInt)
|
ret.value.Add(ret.value, fiveInt)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, m := almost.value.DivMod(almost.value, tenInt, new(big.Int))
|
// floor for positive numbers, ceil for negative numbers
|
||||||
almost.exp += 1
|
_, m := ret.value.DivMod(ret.value, tenInt, new(big.Int))
|
||||||
if almost.value.Sign() < 0 && m.Cmp(zeroInt) != 0 {
|
ret.exp += 1
|
||||||
almost.value.Add(almost.value, oneInt)
|
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.
|
// Floor returns the nearest integer value less than or equal to d.
|
||||||
func (d Decimal) Floor() Decimal {
|
func (d Decimal) Floor() Decimal {
|
||||||
|
d.ensureInitialized()
|
||||||
|
|
||||||
exp := big.NewInt(10)
|
exp := big.NewInt(10)
|
||||||
exp.Exp(exp, big.NewInt(int64(-d.exp)), nil)
|
exp.Exp(exp, big.NewInt(int64(-d.exp)), nil)
|
||||||
z := new(big.Int).Div(d.value, exp)
|
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.
|
// Ceil returns the nearest integer value greater than or equal to d.
|
||||||
func (d Decimal) Ceil() Decimal {
|
func (d Decimal) Ceil() Decimal {
|
||||||
|
d.ensureInitialized()
|
||||||
|
|
||||||
exp := big.NewInt(10)
|
exp := big.NewInt(10)
|
||||||
exp.Exp(exp, big.NewInt(int64(-d.exp)), nil)
|
exp.Exp(exp, big.NewInt(int64(-d.exp)), nil)
|
||||||
z, m := new(big.Int).DivMod(d.value, exp, new(big.Int))
|
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()
|
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() {
|
func (d *Decimal) ensureInitialized() {
|
||||||
if d.value == nil {
|
if d.value == nil {
|
||||||
d.value = new(big.Int)
|
d.value = new(big.Int)
|
||||||
|
|
|
@ -423,12 +423,21 @@ func TestDecimal_Uninitialized(t *testing.T) {
|
||||||
a.Sub(b),
|
a.Sub(b),
|
||||||
a.Mul(b),
|
a.Mul(b),
|
||||||
a.Div(New(1, -1)),
|
a.Div(New(1, -1)),
|
||||||
|
a.Floor(),
|
||||||
|
a.Ceil(),
|
||||||
|
a.Round(2),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, d := range decs {
|
for _, d := range decs {
|
||||||
if d.String() != "0" {
|
if d.String() != "0" {
|
||||||
t.Errorf("expected 0, got %s", d.String())
|
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 {
|
if a.Cmp(b) != 0 {
|
||||||
|
|
Loading…
Reference in a new issue