make dnum support negative precision

This commit is contained in:
gx578007 2023-03-20 22:34:02 +08:00
parent 8c337cddec
commit aa419e8468
2 changed files with 135 additions and 56 deletions

View File

@ -1,66 +1,124 @@
package fixedpoint
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func Test_FormatString(t *testing.T) {
assert := assert.New(t)
cases := []struct {
input string
prec int
expected string
}{
{input: "0.57", prec: 5, expected: "0.57000"},
{input: "-0.57", prec: 5, expected: "-0.57000"},
{input: "0.57123456", prec: 8, expected: "0.57123456"},
{input: "-0.57123456", prec: 8, expected: "-0.57123456"},
{input: "0.57123456", prec: 5, expected: "0.57123"},
{input: "-0.57123456", prec: 5, expected: "-0.57123"},
{input: "0.57123456", prec: 0, expected: "0"},
{input: "-0.57123456", prec: 0, expected: "0"},
{input: "0.57123456", prec: -1, expected: "0"},
{input: "-0.57123456", prec: -1, expected: "0"},
{input: "0.57123456", prec: -5, expected: "0"},
{input: "-0.57123456", prec: -5, expected: "0"},
{input: "0.57123456", prec: -9, expected: "0"},
{input: "-0.57123456", prec: -9, expected: "0"},
t.Run("0.57 with prec = 5, expected 0.57", func(t *testing.T) {
v := MustNewFromString("0.57")
s := v.FormatString(5)
assert.Equal("0.57000", s)
})
{input: "1.23456789", prec: 9, expected: "1.234567890"},
{input: "-1.23456789", prec: 9, expected: "-1.234567890"},
{input: "1.02345678", prec: 9, expected: "1.023456780"},
{input: "-1.02345678", prec: 9, expected: "-1.023456780"},
{input: "1.02345678", prec: 2, expected: "1.02"},
{input: "-1.02345678", prec: 2, expected: "-1.02"},
{input: "1.02345678", prec: 0, expected: "1"},
{input: "-1.02345678", prec: 0, expected: "-1"},
{input: "1.02345678", prec: -1, expected: "0"},
{input: "-1.02345678", prec: -1, expected: "0"},
{input: "1.02345678", prec: -10, expected: "0"},
{input: "-1.02345678", prec: -10, expected: "0"},
t.Run("0.57123456 with prec = 5, expected 0.57123", func(t *testing.T) {
v := MustNewFromString("0.57123456")
s := v.FormatString(5)
assert.Equal("0.57123", s)
})
{input: "0.0001234", prec: 9, expected: "0.000123400"},
{input: "-0.0001234", prec: 9, expected: "-0.000123400"},
{input: "0.0001234", prec: 7, expected: "0.0001234"},
{input: "-0.0001234", prec: 7, expected: "-0.0001234"},
{input: "0.0001234", prec: 5, expected: "0.00012"},
{input: "-0.0001234", prec: 5, expected: "-0.00012"},
{input: "0.0001234", prec: 3, expected: "0.000"},
{input: "-0.0001234", prec: 3, expected: "0.000"},
{input: "0.0001234", prec: 2, expected: "0.00"},
{input: "-0.0001234", prec: 2, expected: "0.00"},
{input: "0.0001234", prec: 0, expected: "0"},
{input: "-0.0001234", prec: 0, expected: "0"},
{input: "0.00001234", prec: -1, expected: "0"},
{input: "-0.00001234", prec: -1, expected: "0"},
{input: "0.00001234", prec: -5, expected: "0"},
{input: "-0.00001234", prec: -5, expected: "0"},
{input: "0.00001234", prec: -9, expected: "0"},
{input: "-0.00001234", prec: -9, expected: "0"},
t.Run("1.23456789 with prec = 9, expected 1.23456789", func(t *testing.T) {
v := MustNewFromString("1.23456789")
s := v.FormatString(9)
assert.Equal("1.234567890", s)
})
{input: "12.3456789", prec: 10, expected: "12.3456789000"},
{input: "-12.3456789", prec: 10, expected: "-12.3456789000"},
{input: "12.3456789", prec: 9, expected: "12.345678900"},
{input: "-12.3456789", prec: 9, expected: "-12.345678900"},
{input: "12.3456789", prec: 7, expected: "12.3456789"},
{input: "-12.3456789", prec: 7, expected: "-12.3456789"},
{input: "12.3456789", prec: 5, expected: "12.34567"},
{input: "-12.3456789", prec: 5, expected: "-12.34567"},
{input: "12.3456789", prec: 1, expected: "12.3"},
{input: "-12.3456789", prec: 1, expected: "-12.3"},
{input: "12.3456789", prec: 0, expected: "12"},
{input: "-12.3456789", prec: 0, expected: "-12"},
{input: "12.3456789", prec: -1, expected: "10"},
{input: "-12.3456789", prec: -1, expected: "-10"},
{input: "12.3456789", prec: -2, expected: "0"},
{input: "-12.3456789", prec: -2, expected: "0"},
{input: "12.3456789", prec: -3, expected: "0"},
{input: "-12.3456789", prec: -3, expected: "0"},
t.Run("1.02345678 with prec = 9, expected 1.02345678", func(t *testing.T) {
v := MustNewFromString("1.02345678")
s := v.FormatString(9)
assert.Equal("1.023456780", s)
})
{input: "12345678.9", prec: 10, expected: "12345678.9000000000"},
{input: "-12345678.9", prec: 10, expected: "-12345678.9000000000"},
{input: "12345678.9", prec: 3, expected: "12345678.900"},
{input: "-12345678.9", prec: 3, expected: "-12345678.900"},
{input: "12345678.9", prec: 1, expected: "12345678.9"},
{input: "-12345678.9", prec: 1, expected: "-12345678.9"},
{input: "12345678.9", prec: 0, expected: "12345678"},
{input: "-12345678.9", prec: 0, expected: "-12345678"},
{input: "12345678.9", prec: -2, expected: "12345600"},
{input: "-12345678.9", prec: -2, expected: "-12345600"},
{input: "12345678.9", prec: -5, expected: "12300000"},
{input: "-12345678.9", prec: -5, expected: "-12300000"},
{input: "12345678.9", prec: -7, expected: "10000000"},
{input: "-12345678.9", prec: -7, expected: "-10000000"},
{input: "12345678.9", prec: -8, expected: "0"},
{input: "-12345678.9", prec: -8, expected: "0"},
{input: "12345678.9", prec: -10, expected: "0"},
{input: "-12345678.9", prec: -10, expected: "0"},
t.Run("-0.57 with prec = 5, expected -0.57", func(t *testing.T) {
v := MustNewFromString("-0.57")
s := v.FormatString(5)
assert.Equal("-0.57000", s)
})
{input: "123000", prec: 7, expected: "123000.0000000"},
{input: "-123000", prec: 7, expected: "-123000.0000000"},
{input: "123000", prec: 2, expected: "123000.00"},
{input: "-123000", prec: 2, expected: "-123000.00"},
{input: "123000", prec: 0, expected: "123000"},
{input: "-123000", prec: 0, expected: "-123000"},
{input: "123000", prec: -1, expected: "123000"},
{input: "-123000", prec: -1, expected: "-123000"},
{input: "123000", prec: -5, expected: "100000"},
{input: "-123000", prec: -5, expected: "-100000"},
{input: "123000", prec: -6, expected: "0"},
{input: "-123000", prec: -6, expected: "0"},
{input: "123000", prec: -8, expected: "0"},
{input: "-123000", prec: -8, expected: "0"},
}
t.Run("-1.23456789 with prec = 9, expected 1.23456789", func(t *testing.T) {
v := MustNewFromString("-1.23456789")
s := v.FormatString(9)
assert.Equal("-1.234567890", s)
})
t.Run("-0.00001234 with prec = 3, expected = 0.000", func(t *testing.T) {
v := MustNewFromString("-0.0001234")
s := v.FormatString(3)
assert.Equal("0.000", s)
})
// comment out negative precision for dnum testing
t.Run("12.3456789 with prec = -1, expected 10", func(t *testing.T) {
v := MustNewFromString("12.3456789")
s := v.FormatString(-1)
assert.Equal("10", s)
})
t.Run("12.3456789 with prec = -3, expected = 0", func(t *testing.T) {
v := MustNewFromString("12.3456789")
s := v.FormatString(-2)
assert.Equal("0", s)
})
}
for _, c := range cases {
t.Run(fmt.Sprintf("%s with prec = %d, expected %s", c.input, c.prec, c.expected), func(t *testing.T) {
v := MustNewFromString(c.input)
s := v.FormatString(c.prec)
assert.Equal(t, c.expected, s)
})
}
}

View File

@ -270,25 +270,46 @@ func (dn Value) FormatString(prec int) string {
nd := len(digits)
e := int(dn.exp) - nd
if -maxLeadingZeros <= dn.exp && dn.exp <= 0 {
if prec < 0 {
return "0"
}
// decimal to the left
if prec+e+nd > 0 {
return sign + "0." + strings.Repeat("0", -e-nd) + digits[:min(prec+e+nd, nd)] + strings.Repeat("0", max(0, prec-nd+e+nd))
} else if -e-nd > 0 {
return "0." + strings.Repeat("0", -e-nd)
} else if -e-nd > 0 && prec != 0 {
return "0." + strings.Repeat("0", min(prec, -e-nd))
} else {
return "0"
}
} else if -nd < e && e <= -1 {
// decimal within
dec := nd + e
decimals := digits[dec:min(dec+prec, nd)]
return sign + digits[:dec] + "." + decimals + strings.Repeat("0", max(0, prec-len(decimals)))
if prec > 0 {
decimals := digits[dec:min(dec+prec, nd)]
return sign + digits[:dec] + "." + decimals + strings.Repeat("0", max(0, prec-len(decimals)))
} else if prec == 0 {
return sign + digits[:dec]
}
sigFigures := digits[0:max(dec+prec, 0)]
if len(sigFigures) == 0 {
return "0"
}
return sign + sigFigures + strings.Repeat("0", max(-prec, 0))
} else if 0 < dn.exp && dn.exp <= digitsMax {
// decimal to the right
if prec > 0 {
return sign + digits + strings.Repeat("0", e) + "." + strings.Repeat("0", prec)
} else {
} else if prec+e >= 0 {
return sign + digits + strings.Repeat("0", e)
} else {
if len(digits) <= -prec-e {
return "0"
}
return sign + digits[0:len(digits)+prec+e] + strings.Repeat("0", -prec)
}
} else {
// scientific notation