mirror of
https://github.com/golang/go
synced 2024-11-12 05:30:21 -07:00
math/big: added (internal) Float.form field for easier case distinctions
This is a fairly significant _internal_ representation change. Instead of encoding 0, finite, infinite, and NaN values with special mantissa and exponent values, a new (1 byte) 'form' field is used (without making the Float struct bigger). The form field permits simpler and faster case distinctions. As a side benefit, for zero and non-finite floats, fewer fields need to be set. Also, the exponent range is not the full int32 range (in the old format, infExp and nanExp were used to represent Inf and NaN values and tests for those values sometimes didn't test for the empty mantissa, so the range was reduced by 2 values). The correspondence between the old and new fields is as follows. Old representation: x neg mant exp --------------------------------------------------------------- +/-0 sign empty 0 0 < |x| < +Inf sign mantissa exponent +/-Inf sign empty infExp NaN false empty nanExp New representation (- stands for ignored fields): x neg mant exp form --------------------------------------------------------------- +/-0 sign - - zero 0 < |x| < +Inf sign mantissa exponent finite +/-Inf sign - - inf NaN - - - nan Client should not be affected by this change. Change-Id: I7e355894d602ceb23f9ec01da755fe6e0386b101 Reviewed-on: https://go-review.googlesource.com/6870 Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
0ff7c3ea45
commit
363617c7d3
@ -37,6 +37,9 @@ const maxShift = _W - 4
|
||||
// precision argument and keeping track of when a number was truncated early
|
||||
// (equivalent of "sticky bit" in binary rounding).
|
||||
|
||||
// TODO(gri) Along the same lines, enforce some limit to shift magnitudes
|
||||
// to avoid "infinitely" long running conversions (until we run out of space).
|
||||
|
||||
// Init initializes x to the decimal representation of m << shift (for
|
||||
// shift >= 0), or m >> -shift (for shift < 0).
|
||||
func (x *decimal) init(m nat, shift int) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -90,15 +90,20 @@ func TestFloatZeroValue(t *testing.T) {
|
||||
|
||||
func makeFloat(s string) *Float {
|
||||
var x Float
|
||||
if s == "Inf" || s == "+Inf" {
|
||||
|
||||
switch s {
|
||||
case "0":
|
||||
return &x
|
||||
case "-0":
|
||||
return x.Neg(&x)
|
||||
case "Inf", "+Inf":
|
||||
return x.SetInf(+1)
|
||||
}
|
||||
if s == "-Inf" {
|
||||
case "-Inf":
|
||||
return x.SetInf(-1)
|
||||
}
|
||||
if s == "NaN" || s == "-NaN" {
|
||||
case "NaN", "-NaN":
|
||||
return x.SetNaN()
|
||||
}
|
||||
|
||||
x.SetPrec(1000)
|
||||
if _, ok := x.SetString(s); !ok {
|
||||
panic(fmt.Sprintf("%q is not a valid float", s))
|
||||
@ -146,13 +151,6 @@ func TestFloatSetPrec(t *testing.T) {
|
||||
if got, acc := x.String(), x.Acc(); got != test.want || acc != test.acc {
|
||||
t.Errorf("%s.SetPrec(%d) = %s (%s); want %s (%s)", test.x, test.prec, got, acc, test.want, test.acc)
|
||||
}
|
||||
// look inside x and check correct value for x.exp
|
||||
if len(x.mant) == 0 {
|
||||
// ±0, ±Inf, or NaN
|
||||
if x.exp != 0 && x.exp > MinExp {
|
||||
t.Errorf("%s.SetPrec(%d): incorrect exponent %d", test.x, test.prec, x.exp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,7 +207,7 @@ func feq(x, y *Float) bool {
|
||||
if x.IsNaN() || y.IsNaN() {
|
||||
return x.IsNaN() && y.IsNaN()
|
||||
}
|
||||
return x.Cmp(y) == 0 && x.neg == y.neg
|
||||
return x.Cmp(y) == 0 && x.IsNeg() == y.IsNeg()
|
||||
}
|
||||
|
||||
func TestFloatMantExp(t *testing.T) {
|
||||
@ -261,11 +259,11 @@ func TestFloatSetMantExp(t *testing.T) {
|
||||
{"Inf", 1234, "+Inf"},
|
||||
{"+Inf", -1234, "+Inf"},
|
||||
{"-Inf", -1234, "-Inf"},
|
||||
{"0", -MaxExp - 1, "0"},
|
||||
{"0.5", -MaxExp - 1, "+0"}, // exponent underflow
|
||||
{"-0.5", -MaxExp - 1, "-0"}, // exponent underflow
|
||||
{"1", MaxExp, "+Inf"}, // exponent overflow
|
||||
{"2", MaxExp - 1, "+Inf"}, // exponent overflow
|
||||
{"0", MinExp, "0"},
|
||||
{"0.25", MinExp, "+0"}, // exponent underflow
|
||||
{"-0.25", MinExp, "-0"}, // exponent underflow
|
||||
{"1", MaxExp, "+Inf"}, // exponent overflow
|
||||
{"2", MaxExp - 1, "+Inf"}, // exponent overflow
|
||||
{"0.75", 1, "1.5"},
|
||||
{"0.5", 11, "1024"},
|
||||
{"-0.5", -2, "-0.125"},
|
||||
|
@ -96,11 +96,13 @@ func (z *Float) Scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
|
||||
// special-case 0
|
||||
if len(z.mant) == 0 {
|
||||
z.acc = Exact
|
||||
z.exp = 0
|
||||
z.form = zero
|
||||
return
|
||||
}
|
||||
// len(z.mant) > 0
|
||||
|
||||
z.form = finite
|
||||
|
||||
// The mantissa may have a decimal point (fcount <= 0) and there
|
||||
// may be a nonzero exponent exp. The decimal point amounts to a
|
||||
// division by b**(-fcount). An exponent means multiplication by
|
||||
@ -275,9 +277,13 @@ func (x *Float) bstring(buf []byte) []byte {
|
||||
if x.neg {
|
||||
buf = append(buf, '-')
|
||||
}
|
||||
if len(x.mant) == 0 {
|
||||
if x.form == zero {
|
||||
return append(buf, '0')
|
||||
}
|
||||
|
||||
if debugFloat && x.form != finite {
|
||||
panic("non-finite float")
|
||||
}
|
||||
// x != 0
|
||||
|
||||
// adjust mantissa to use exactly x.prec bits
|
||||
@ -306,9 +312,13 @@ func (x *Float) pstring(buf []byte) []byte {
|
||||
if x.neg {
|
||||
buf = append(buf, '-')
|
||||
}
|
||||
if len(x.mant) == 0 {
|
||||
if x.form == zero {
|
||||
return append(buf, '0')
|
||||
}
|
||||
|
||||
if debugFloat && x.form != finite {
|
||||
panic("non-finite float")
|
||||
}
|
||||
// x != 0
|
||||
|
||||
// remove trailing 0 words early
|
||||
|
@ -19,11 +19,17 @@ import "strconv"
|
||||
|
||||
// bigFtoa formats a float for the %e, %E, %f, %g, and %G formats.
|
||||
func (f *Float) bigFtoa(buf []byte, fmt byte, prec int) []byte {
|
||||
// TODO(gri) handle Inf.
|
||||
if debugFloat && !f.IsFinite() {
|
||||
panic("non-finite float")
|
||||
}
|
||||
|
||||
// 1) convert Float to multiprecision decimal
|
||||
var mant nat
|
||||
if f.form == finite {
|
||||
mant = f.mant
|
||||
}
|
||||
var d decimal
|
||||
d.init(f.mant, int(f.exp)-f.mant.bitLen())
|
||||
d.init(mant, int(f.exp)-f.mant.bitLen())
|
||||
|
||||
// 2) round to desired precision
|
||||
shortest := false
|
||||
|
Loading…
Reference in New Issue
Block a user