func (p *exporter) fraction(x exact.Value) { sign := exact.Sign(x) p.int(sign) if sign == 0 { return } p.ufloat(exact.Num(x)) p.ufloat(exact.Denom(x)) }
// floatString returns the string representation for a // numeric value v in normalized floating-point format. func floatString(v exact.Value) string { if exact.Sign(v) == 0 { return "0.0" } // x != 0 // convert |v| into a big.Rat x x := new(big.Rat).SetFrac(absInt(exact.Num(v)), absInt(exact.Denom(v))) // normalize x and determine exponent e // (This is not very efficient, but also not speed-critical.) var e int for x.Cmp(ten) >= 0 { x.Quo(x, ten) e++ } for x.Cmp(one) < 0 { x.Mul(x, ten) e-- } // TODO(gri) Values such as 1/2 are easier to read in form 0.5 // rather than 5.0e-1. Similarly, 1.0e1 is easier to read as // 10.0. Fine-tune best exponent range for readability. s := x.FloatString(100) // good-enough precision // trim trailing 0's i := len(s) for i > 0 && s[i-1] == '0' { i-- } s = s[:i] // add a 0 if the number ends in decimal point if len(s) > 0 && s[len(s)-1] == '.' { s += "0" } // add exponent and sign if e != 0 { s += fmt.Sprintf("e%+d", e) } if exact.Sign(v) < 0 { s = "-" + s } // TODO(gri) If v is a "small" fraction (i.e., numerator and denominator // are just a small number of decimal digits), add the exact fraction as // a comment. For instance: 3.3333...e-1 /* = 1/3 */ return s }