44 "fmt"
55 "log"
66 "math"
7+ "math/big"
78 "strconv"
89
910 "github.com/stellar/go/price"
@@ -19,7 +20,8 @@ var NumberConstants = struct {
1920}
2021
2122// InvertPrecision is the precision of the number after it is inverted
22- const InvertPrecision = 15
23+ // this is only 11 becuase if we keep it larger such as 15 then inversions are inaccurate for larger numbers such as inverting 0.00002
24+ const InvertPrecision = 11
2325
2426// InternalCalculationsPrecision is the precision to be used for internal calculations in a function
2527const InternalCalculationsPrecision = 15
@@ -157,7 +159,19 @@ func InvertNumber(n *Number) *Number {
157159 if n == nil {
158160 return nil
159161 }
160- return NumberFromFloat (1.0 / n .AsFloat (), InvertPrecision )
162+
163+ // return 0 for the inverse of 0 to keep it safe
164+ if n .AsFloat () == 0 {
165+ log .Printf ("trying to invert the number 0, returning the same number to keep it safe" )
166+ return n
167+ }
168+
169+ bigNum := big .NewRat (1 , 1 )
170+ bigNum = bigNum .SetFloat64 (n .AsFloat ())
171+ bigInv := bigNum .Inv (bigNum )
172+
173+ bigInvFloat64 , _ := bigInv .Float64 ()
174+ return NumberFromFloat (bigInvFloat64 , InvertPrecision )
161175}
162176
163177// NumberByCappingPrecision returns a number with a precision that is at max the passed in precision
@@ -174,8 +188,7 @@ func round(num float64, rounding Rounding) int64 {
174188 } else if rounding == RoundTruncate {
175189 return int64 (num )
176190 } else {
177- // error
178- return - 1
191+ panic (fmt .Sprintf ("unknown rounding type %v" , rounding ))
179192 }
180193}
181194
@@ -189,8 +202,26 @@ const (
189202)
190203
191204func toFixed (num float64 , precision int8 , rounding Rounding ) float64 {
192- output := math .Pow (10 , float64 (precision ))
193- return float64 (round (num * output , rounding )) / output
205+ bigNum := big .NewRat (1 , 1 )
206+ bigNum = bigNum .SetFloat64 (num )
207+ bigPow := big .NewRat (1 , 1 )
208+ bigPow = bigPow .SetFloat64 (math .Pow (10 , float64 (precision )))
209+
210+ // multiply
211+ bigMultiply := bigNum .Mul (bigNum , bigPow )
212+
213+ // convert to int after rounding
214+ bigMultiplyFloat64 , _ := bigMultiply .Float64 ()
215+ roundedInt64 := round (bigMultiplyFloat64 , rounding )
216+ bigMultiplyIntFloat64 := big .NewRat (1 , 1 )
217+ bigMultiplyIntFloat64 = bigMultiplyIntFloat64 .SetInt64 (roundedInt64 )
218+
219+ // divide it
220+ bigPowInverse := bigPow .Inv (bigPow )
221+ bigResult := bigMultiply .Mul (bigMultiplyIntFloat64 , bigPowInverse )
222+
223+ br , _ := bigResult .Float64 ()
224+ return br
194225}
195226
196227func minPrecision (n1 Number , n2 Number ) int8 {
0 commit comments