Skip to content
This repository was archived by the owner on Feb 1, 2024. It is now read-only.

Commit 59cabd6

Browse files
authored
improve number.AsRatio() conversion using stellar/go/price (#272), closes #264
1 parent c18c97f commit 59cabd6

2 files changed

Lines changed: 14 additions & 48 deletions

File tree

model/number.go

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"log"
66
"math"
77
"strconv"
8+
9+
"github.com/stellar/go/price"
810
)
911

1012
// NumberConstants holds some useful constants
@@ -39,32 +41,11 @@ func (n Number) AsString() string {
3941

4042
// AsRatio returns an integer numerator and denominator
4143
func (n Number) AsRatio() (int32, int32, error) {
42-
denominator64 := uint64(math.Pow(10, float64(n.Precision())))
43-
44-
var numerator64 uint64
45-
// add an adjustment because the computed value should not have any digits beyond the decimal
46-
// and we want to roll over values that are not computed correctly rather than using the expensive math/big library
47-
unsignedPartial := n.AsFloat() * float64(denominator64)
48-
if n.AsFloat() < 0 {
49-
unsignedPartial *= -1
50-
}
51-
numerator64 = uint64(unsignedPartial + 0.1)
52-
53-
for numerator64%10 == 0 && denominator64 > 1 {
54-
numerator64 /= 10
55-
denominator64 /= 10
56-
}
57-
58-
numerator, denominator := int32(numerator64), int32(denominator64)
59-
if n.AsFloat() < 0 {
60-
numerator *= -1
61-
}
62-
63-
if float64(numerator)/float64(denominator) != n.AsFloat() {
64-
return 0, 0, fmt.Errorf("invalid conversion to a ratio probably caused by an overflow, float input: %f, numerator: %d, denominator: %d", n.AsFloat(), numerator, denominator)
44+
p, e := price.Parse(n.AsString())
45+
if e != nil {
46+
return 0, 0, fmt.Errorf("unable to convert number to ratio: %s", e)
6547
}
66-
67-
return numerator, denominator, nil
48+
return int32(p.N), int32(p.D), nil
6849
}
6950

7051
// Abs returns the absolute of the number

model/number_test.go

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -289,12 +289,12 @@ func TestAsRatio(t *testing.T) {
289289
wantD: 1000000,
290290
}, {
291291
n: NumberFromFloat(5274.26, 8),
292-
wantN: 527426,
293-
wantD: 100,
292+
wantN: 263713,
293+
wantD: 50,
294294
}, {
295295
n: NumberFromFloat(-5274.26, 8),
296-
wantN: -527426,
297-
wantD: 100,
296+
wantN: -263713,
297+
wantD: 50,
298298
}, {
299299
n: NumberFromFloat(10.0, 4),
300300
wantN: 10,
@@ -303,6 +303,10 @@ func TestAsRatio(t *testing.T) {
303303
n: NumberFromFloat(-10.0, 4),
304304
wantN: -10,
305305
wantD: 1,
306+
}, {
307+
n: NumberFromFloat(2.599999999, 9),
308+
wantN: 1039999997,
309+
wantD: 399999999,
306310
},
307311
}
308312

@@ -320,22 +324,3 @@ func TestAsRatio(t *testing.T) {
320324
})
321325
}
322326
}
323-
324-
func TestAsRatio_Error(t *testing.T) {
325-
testCases := []struct {
326-
n *Number
327-
}{
328-
{
329-
n: NumberFromFloat(2.599999999, 9),
330-
},
331-
}
332-
333-
for _, kase := range testCases {
334-
t.Run(kase.n.AsString(), func(t *testing.T) {
335-
num, den, e := kase.n.AsRatio()
336-
if !assert.Error(t, e, fmt.Sprintf("got back num=%d, den=%d, expected an error", num, den)) {
337-
return
338-
}
339-
})
340-
}
341-
}

0 commit comments

Comments
 (0)