Skip to content

Commit

Permalink
skip trailing zeros
Browse files Browse the repository at this point in the history
  • Loading branch information
nikolaydubina committed Oct 24, 2023
1 parent c561db8 commit 35aaba2
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 18 deletions.
35 changes: 25 additions & 10 deletions fpdecimal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"log"
"math"
"strconv"
"testing"
"unsafe"

Expand Down Expand Up @@ -78,7 +79,7 @@ func FuzzArithmetics(f *testing.F) {
}

func FuzzParse_StringSameAsFloat(f *testing.F) {
tests := []float32{
tests := []float64{
0,
0.100,
0.101,
Expand All @@ -100,27 +101,28 @@ func FuzzParse_StringSameAsFloat(f *testing.F) {
f.Add(tc)
f.Add(-tc)
}
f.Fuzz(func(t *testing.T, r float32) {
f.Fuzz(func(t *testing.T, r float64) {
if r > math.MaxInt64/1000 || r < math.MinInt64/1000 {
t.Skip()
}

s := fmt.Sprintf("%.3f", r)
rs, _ := strconv.ParseFloat(s, 64)

v, err := fp.FromString(s)
if err != nil {
t.Errorf(err.Error())
t.Error(err)
}

if s == "-0.000" || s == "0.000" || r == 0 || r == -0 {
if s == "-0.000" || s == "0.000" || rs == 0 || rs == -0 || (rs > -0.001 && rs < 0.001) {
if v.String() != "0" {
t.Errorf("s('0') != Decimal.String(%#v) of fp3(%#v) float32(%#v) .3f-float32(%#v)", v.String(), v, r, s)
}
return
}

if s != v.String() {
t.Errorf("s(%#v) != Decimal.String(%#v) of fp3(%#v) float32(%#v)", s, v.String(), v, r)
if s, fs := strconv.FormatFloat(rs, 'f', -1, 64), v.String(); s != fs {
t.Error(s, fs, r, v)
}
})
}
Expand Down Expand Up @@ -362,22 +364,23 @@ func FuzzJSON(f *testing.F) {
}

b := fmt.Sprintf("%.3f", v)
s := `{"a":` + b + `}`
rs, _ := strconv.ParseFloat(b, 64)
s := `{"a":` + strconv.FormatFloat(rs, 'f', -1, 64) + `}`

var x MyType
err := json.Unmarshal([]byte(s), &x)
if err != nil {
t.Error(err, s)
}

if b == "-0.000" || b == "0.000" || v == 0 || v == -0 {
if b == "-0.000" || b == "0.000" || rs == 0 || rs == -0 || (rs > 0.001 && rs < 0.001) {
if x.A.String() != "0" {
t.Error(b, x)
}
return
}

if a := x.A.String(); a != b {
if a := x.A.String(); a != strconv.FormatFloat(rs, 'f', -1, 64) {
t.Error(a, b)
}

Expand Down Expand Up @@ -413,6 +416,18 @@ func ExampleDecimal() {
// Output: 18000.046
}

func ExampleDecimal_skip_whole_fraction() {
v, _ := fp.FromString("1013.0000")
fmt.Println(v)
// Output: 1013
}

func ExampleDecimal_skip_trailing_zeros() {
v, _ := fp.FromString("102.0020")
fmt.Println(v)
// Output: 102.002
}

func ExampleDecimal_Div_remainder() {
x, _ := fp.FromString("1.000")

Expand All @@ -426,7 +441,7 @@ func ExampleDecimal_Div_whole() {

a, r := x.DivMod(fp.FromInt(5))
fmt.Println(a, r)
// Output: 0.200 0
// Output: 0.2 0
}

func BenchmarkArithmetic(b *testing.B) {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module github.com/nikolaydubina/fpdecimal

go 1.20
go 1.21
19 changes: 17 additions & 2 deletions printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ func FixedPointDecimalToString(v int64, p int) string {
// AppendFixedPointDecimal appends formatted fixed point decimal to destination buffer.
// Returns appended slice.
// This is efficient for avoiding memory copy.
// strconv.AppendInt is very efficient.
// Efficient converting int64 to ASCII is not as trivial.
func AppendFixedPointDecimal(b []byte, v int64, p int) []byte {
if v == 0 {
return append(b, '0')
Expand All @@ -35,15 +33,20 @@ func AppendFixedPointDecimal(b []byte, v int64, p int) []byte {
b = append(b, '-')
}

// strconv.AppendInt is very efficient.
// Efficient converting int64 to ASCII is not as trivial.
s := len(b)
b = strconv.AppendInt(b, v, 10)

// has whole?
if len(b)-s > p {
// place decimal point
i := len(b) - p
b = append(b, 0)
copy(b[i+1:], b[i:])
b[i] = '.'
} else {
// append zeroes and decimal point
i := 2 + p - (len(b) - s)
for j := 0; j < i; j++ {
b = append(b, 0)
Expand All @@ -52,5 +55,17 @@ func AppendFixedPointDecimal(b []byte, v int64, p int) []byte {
copy(b[s:], []byte(zeroPrefix[:i]))
}

// remove trailing zeros
n := 0
for i, q := range b {
if q != '0' {
n = i
}
}
if b[n] == '.' {
n--
}
b = b[:n+1]

return b
}
11 changes: 6 additions & 5 deletions printer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func FuzzFixedPointDecimalToString(f *testing.F) {
tests := []float32{
tests := []float64{
0,
0.100,
0.101,
Expand All @@ -33,27 +33,28 @@ func FuzzFixedPointDecimalToString(f *testing.F) {
f.Add(tc)
f.Add(-tc)
}
f.Fuzz(func(t *testing.T, r float32) {
f.Fuzz(func(t *testing.T, r float64) {
if r > math.MaxInt64/1000 || r < math.MinInt64/1000 {
t.Skip()
}

s := fmt.Sprintf("%.3f", r)
rs, _ := strconv.ParseFloat(s, 64)

v, err := fpdecimal.ParseFixedPointDecimal(s, 3)
if err != nil {
t.Errorf(err.Error())
}

if s == "-0.000" || s == "0.000" || r == 0 || r == -0 {
if s == "-0.000" || s == "0.000" || rs == 0 || rs == -0 || (rs > -0.001 && rs < 0.001) {
if q := fpdecimal.FixedPointDecimalToString(v, 3); q != "0" {
t.Error(r, s, q)
}
return
}

if fs := fpdecimal.FixedPointDecimalToString(v, 3); s != fs {
t.Error(s, fs, f, r, v)
if s, fs := strconv.FormatFloat(rs, 'f', -1, 64), fpdecimal.FixedPointDecimalToString(v, 3); s != fs {
t.Error(s, fs, r, v)
}
})
}
Expand Down

0 comments on commit 35aaba2

Please sign in to comment.