-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathfinite.go
76 lines (66 loc) · 1.77 KB
/
finite.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package rounding
import (
"fmt"
"math/big"
)
// Wrapper around QuoRem that returns the remainder
func remQuo(x, y, q, r *big.Int) *big.Int {
q.QuoRem(x, y, r)
return r
}
// Finite returns true if x has a finite decimal representation.
// x is finite if the Denom can be represented as (2**x) * (5**y).
func Finite(x *big.Rat) bool {
// calling x.Denom() can modify x (populates b) so be extra careful
xx := new(big.Rat).Set(x)
d := xx.Denom()
i := new(big.Int)
m := new(big.Int)
for {
switch {
case d.Cmp(big1) == 0:
return true
case remQuo(d, big2, i, m).Sign() == 0:
d.Set(i)
case remQuo(d, big5, i, m).Sign() == 0:
d.Set(i)
default:
return false
}
}
}
// FinitePrec returns the precision of the finite decimal representation of x.
// WARNING: Running this on a value that does not have a finite decimal
// representation will panic.
func FinitePrec(x *big.Rat) int {
if !Finite(x) {
panic(fmt.Errorf("rounding.FinitePrec: called with non-finite value: %v", x))
}
// calling x.Denom() can modify x (populates b) so be extra careful
xx := new(big.Rat).Set(x)
d := xx.Denom()
n := xx.Num()
m := new(big.Int)
var i int
for m.Mod(n, d).Sign() != 0 {
i++
n.Mul(n, big10)
}
return i
}
// FiniteString returns the equivalent of x.FloatString(FinitePrec(x)).
// WARNING: Running this on a value that does not have a finite decimal
// representation will panic.
func FiniteString(x *big.Rat) string {
return x.FloatString(FinitePrec(x))
}
// FiniteStringMin returns the equivalent of x.FloatString(max(FinitePrec(x), prec)).
// WARNING: Running this on a value that does not have a finite decimal
// representation will panic.
func FiniteStringMin(x *big.Rat, prec int) string {
p := FinitePrec(x)
if p < prec {
p = prec
}
return x.FloatString(p)
}