fix: NumFractionalDigits in legacy fixedpoint and dnum fixedpoint

This commit is contained in:
zenix 2022-02-17 12:45:06 +09:00
parent ced2afaed8
commit 20cccf57e5
5 changed files with 69 additions and 2 deletions

View File

@ -381,6 +381,9 @@ func (a Value) NumIntDigits() int {
// TODO: speedup // TODO: speedup
func (a Value) NumFractionalDigits() int { func (a Value) NumFractionalDigits() int {
if a == 0 {
return 0
}
numPow := 0 numPow := 0
for pow := int64(DefaultPow); pow%10 != 1; pow /= 10 { for pow := int64(DefaultPow); pow%10 != 1; pow /= 10 {
numPow++ numPow++

View File

@ -314,7 +314,7 @@ func (dn Value) String() string {
// scientific notation // scientific notation
after := "" after := ""
if nd > 1 { if nd > 1 {
after = "0." + digits[1:] after = "." + digits[1:]
} }
return sign + digits[:1] + after + "e" + strconv.Itoa(int(dn.exp-1)) return sign + digits[:1] + after + "e" + strconv.Itoa(int(dn.exp-1))
} }
@ -350,7 +350,7 @@ func (dn Value) Percentage() string {
// scientific notation // scientific notation
after := "" after := ""
if nd > 1 { if nd > 1 {
after = "0." + digits[1:] after = "." + digits[1:]
} }
return sign + digits[:1] + after + "e" + strconv.Itoa(int(dn.exp-1)) + "%" return sign + digits[:1] + after + "e" + strconv.Itoa(int(dn.exp-1)) + "%"
} }
@ -484,6 +484,18 @@ func NewFromString(s string) (Value, error) {
if isPercentage { if isPercentage {
exp -= 2 exp -= 2
} }
atmax := false
for coef > coefMax {
coef = (coef + 5) / 10
exp++
atmax = true
}
if !atmax {
p := maxShift(coef)
coef *= pow10[p]
exp -= p
}
//check(coefMin <= coef && coef <= coefMax) //check(coefMin <= coef && coef <= coefMax)
return Value{coef, sign, exp}, nil return Value{coef, sign, exp}, nil
} }
@ -519,6 +531,18 @@ func NewFromBytes(s []byte) (Value, error) {
if isPercentage { if isPercentage {
exp -= 2 exp -= 2
} }
atmax := false
for coef > coefMax {
coef = (coef + 5) / 10
exp++
atmax = true
}
if !atmax {
p := maxShift(coef)
coef *= pow10[p]
exp -= p
}
//check(coefMin <= coef && coef <= coefMax) //check(coefMin <= coef && coef <= coefMax)
return Value{coef, sign, exp}, nil return Value{coef, sign, exp}, nil
} }

View File

@ -12,3 +12,24 @@ func TestDelta(t *testing.T) {
f2 := NewFromInt(42300) f2 := NewFromInt(42300)
assert.InDelta(t, f1.Mul(f2).Float64(), 41.3, 1e-14) assert.InDelta(t, f1.Mul(f2).Float64(), 41.3, 1e-14)
} }
func TestInternal(t *testing.T) {
r := &reader{"1.1e-15", 0}
c, e := r.getCoef()
assert.Equal(t, uint64(1100000000000000), c)
assert.Equal(t, 1, e)
f := MustNewFromString("1.1e-15")
digits := getDigits(f.coef)
assert.Equal(t, "11", digits)
f = MustNewFromString("1.00000000000000111")
assert.Equal(t, "1.000000000000001", f.String())
f = MustNewFromString("1.1e-15")
assert.Equal(t, "1.1e-15", f.String())
assert.Equal(t, 16, f.NumFractionalDigits())
f = MustNewFromString("1.00000000000000111")
assert.Equal(t, "1.000000000000001", f.String())
f = MustNewFromString("0.0000000001000111")
assert.Equal(t, "1.000111e-10", f.String())
f = MustNewFromString("1e-100")
assert.Equal(t, 100, f.NumFractionalDigits())
}

View File

@ -17,6 +17,11 @@ func TestNumFractionalDigitsLegacy(t *testing.T) {
v: MustNewFromString("0.123456789"), v: MustNewFromString("0.123456789"),
want: 8, want: 8,
}, },
{
name: "zero underflow",
v: MustNewFromString("1e-100"),
want: 0,
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {

View File

@ -89,6 +89,10 @@ func TestFromString(t *testing.T) {
f = MustNewFromString("0.75%") f = MustNewFromString("0.75%")
assert.Equal(t, "0.0075", f.String()) assert.Equal(t, "0.0075", f.String())
f = MustNewFromString("1.1e-7")
assert.Equal(t, "0.00000011", f.String())
f = MustNewFromString(".0%")
assert.Equal(t, Zero, f)
} }
func TestNumFractionalDigits(t *testing.T) { func TestNumFractionalDigits(t *testing.T) {
@ -132,6 +136,16 @@ func TestNumFractionalDigits(t *testing.T) {
v: MustNewFromString("0.075%"), // 0.075 * 0.01 v: MustNewFromString("0.075%"), // 0.075 * 0.01
want: 5, want: 5,
}, },
{
name: "scientific notation",
v: MustNewFromString("1.1e-7"),
want: 8,
},
{
name: "zero",
v: MustNewFromString("0"),
want: 0,
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {