func makeFloatFromLiteral(lit string) Value {
if f, ok := newFloat().SetString(lit); ok {
- if f.MantExp(nil) < maxExp {
+ if smallRat(f) {
// ok to use rationals
r, _ := newRat().SetString(lit)
- return makeRat(r)
+ return ratVal{r}
}
// otherwise use floats
return makeFloat(f)
return nil
}
+// smallRat reports whether x would lead to "reasonably"-sized fraction
+// if converted to a *big.Rat.
+func smallRat(x *big.Float) bool {
+ if !x.IsInf() {
+ e := x.MantExp(nil)
+ return -maxExp < e && e < maxExp
+ }
+ return false
+}
+
// ----------------------------------------------------------------------------
// Factories
return makeInt(newInt().SetBits(words[:i]))
}
-// toRat returns the fraction corresponding to x, or nil
-// if x cannot be represented as a fraction a/b because
-// its components a or b are too large.
-func toRat(x *big.Float) *big.Rat {
- m := newFloat()
- e := x.MantExp(m)
-
- // fail to convert if fraction components are too large
- if e <= maxExp || e >= maxExp {
- return nil
- }
-
- // convert mantissa to big.Int value by shifting by ecorr
- ecorr := int(m.MinPrec())
- a, _ := m.SetMantExp(m, ecorr).Int(nil)
- e -= ecorr // correct exponent
-
- // compute actual fraction
- b := big.NewInt(1)
- switch {
- case e < 0:
- b.Lsh(b, uint(-e))
- case e > 0:
- a.Lsh(a, uint(e))
- }
-
- return new(big.Rat).SetFrac(a, b)
-}
-
// Num returns the numerator of x; x must be Int, Float, or Unknown.
// If x is Unknown, or if it is too large or small to represent as a
// fraction, the result is Unknown. Otherwise the result is an Int
case ratVal:
return makeInt(x.val.Num())
case floatVal:
- if r := toRat(x.val); r != nil {
+ if smallRat(x.val) {
+ r, _ := x.val.Rat(nil)
return makeInt(r.Num())
}
case unknownVal:
case ratVal:
return makeInt(x.val.Denom())
case floatVal:
- if r := toRat(x.val); r != nil {
+ if smallRat(x.val) {
+ r, _ := x.val.Rat(nil)
return makeInt(r.Denom())
}
case unknownVal:
case floatVal:
// avoid creation of huge integers
- // (existing tests require permitting exponents of at least 1024)
- if x.val.MantExp(nil) <= 1024 {
+ // (Existing tests require permitting exponents of at least 1024;
+ // allow any value that would also be permissible as a fraction.)
+ if smallRat(x.val) {
i := newInt()
if _, acc := x.val.Int(i); acc == big.Exact {
return makeInt(i)
{"2.1", "2.1", "21/10"},
{"-2.1", "-2.1", "-21/10"},
{"1e9999", "1e+9999", "0x.f8d4a9da224650a8cb2959e10d985ad92adbd44c62917e608b1f24c0e1b76b6f61edffeb15c135a4b601637315f7662f325f82325422b244286a07663c9415d2p+33216"},
+ {"1e-9999", "1e-9999", "0x.83b01ba6d8c0425eec1b21e96f7742d63c2653ed0a024cf8a2f9686df578d7b07d7a83d84df6a2ec70a921d1f6cd5574893a7eda4d28ee719e13a5dce2700759p-33215"},
{"2.71828182845904523536028747135266249775724709369995957496696763", "2.71828", "271828182845904523536028747135266249775724709369995957496696763/100000000000000000000000000000000000000000000000000000000000000"},
// Complex