Commit 2b0213d5 authored by Robert Griesemer's avatar Robert Griesemer

math/big: incorporated feedback from prior TBR reviews

Change-Id: Ida847365223ef09b4a3846e240b4bb6919cb0fe9
Reviewed-on: https://go-review.googlesource.com/5610Reviewed-by: default avatarAlan Donovan <adonovan@google.com>
parent 828129fd
...@@ -39,10 +39,10 @@ const debugFloat = true // enable for debugging ...@@ -39,10 +39,10 @@ const debugFloat = true // enable for debugging
// and according to its rounding mode, unless specified otherwise. If the // and according to its rounding mode, unless specified otherwise. If the
// result precision is 0 (see below), it is set to the precision of the // result precision is 0 (see below), it is set to the precision of the
// argument with the largest precision value before any rounding takes // argument with the largest precision value before any rounding takes
// place. The rounding mode remains unchanged, thus uninitialized Floats // place, and the rounding mode remains unchanged. Thus, uninitialized Floats
// provided as result arguments will "inherit" a reasonble precision from // provided as result arguments will have their precision set to a reasonable
// the incoming arguments and their mode is the zero value for RoundingMode // value determined by the operands and their mode is the zero value for
// (ToNearestEven). // RoundingMode (ToNearestEven).
// //
// By setting the desired precision to 24 or 53 and using ToNearestEven // By setting the desired precision to 24 or 53 and using ToNearestEven
// rounding, Float operations produce the same results as the corresponding // rounding, Float operations produce the same results as the corresponding
...@@ -62,6 +62,9 @@ type Float struct { ...@@ -62,6 +62,9 @@ type Float struct {
prec uint // TODO(gri) make this a 32bit field prec uint // TODO(gri) make this a 32bit field
} }
// TODO(gri) provide a couple of Example tests showing typical Float intialization
// and use.
// Internal representation: The mantissa bits x.mant of a Float x are stored // Internal representation: The mantissa bits x.mant of a Float x are stored
// in a nat slice long enough to hold up to x.prec bits; the slice may (but // in a nat slice long enough to hold up to x.prec bits; the slice may (but
// doesn't have to) be shorter if the mantissa contains trailing 0 bits. // doesn't have to) be shorter if the mantissa contains trailing 0 bits.
...@@ -158,7 +161,7 @@ func (z *Float) SetPrec(prec uint) *Float { ...@@ -158,7 +161,7 @@ func (z *Float) SetPrec(prec uint) *Float {
// SetMode sets z's rounding mode to mode and returns an exact z. // SetMode sets z's rounding mode to mode and returns an exact z.
// z remains unchanged otherwise. // z remains unchanged otherwise.
func (z *Float) SetMode(mode RoundingMode) *Float { func (z *Float) SetMode(mode RoundingMode) *Float {
z.acc = Exact z.acc = Exact // TODO(gri) should we not do this? what's the general rule for setting accuracy?
z.mode = mode z.mode = mode
return z return z
} }
...@@ -274,23 +277,21 @@ func (z *Float) setExp(e int64) { ...@@ -274,23 +277,21 @@ func (z *Float) setExp(e int64) {
} }
// debugging support // debugging support
func validate(args ...*Float) { func validate(x *Float) {
for i, x := range args { const msb = 1 << (_W - 1)
const msb = 1 << (_W - 1) m := len(x.mant)
m := len(x.mant) if m == 0 {
if m == 0 { // 0.0 or Inf
// 0.0 or Inf if x.exp != 0 && x.exp != infExp {
if x.exp != 0 && x.exp != infExp { panic(fmt.Sprintf("%empty matissa with invalid exponent %d", x.exp))
panic(fmt.Sprintf("#%d: %empty matissa with invalid exponent %d", i, x.exp))
}
continue
}
if x.mant[m-1]&msb == 0 {
panic(fmt.Sprintf("#%d: msb not set in last word %#x of %s", i, x.mant[m-1], x.Format('p', 0)))
}
if x.prec <= 0 {
panic(fmt.Sprintf("#%d: invalid precision %d", i, x.prec))
} }
return
}
if x.mant[m-1]&msb == 0 {
panic(fmt.Sprintf("msb not set in last word %#x of %s", x.mant[m-1], x.Format('p', 0)))
}
if x.prec <= 0 {
panic(fmt.Sprintf("invalid precision %d", x.prec))
} }
} }
...@@ -1064,7 +1065,8 @@ func (x *Float) ucmp(y *Float) int { ...@@ -1064,7 +1065,8 @@ func (x *Float) ucmp(y *Float) int {
// result. // result.
func (z *Float) Add(x, y *Float) *Float { func (z *Float) Add(x, y *Float) *Float {
if debugFloat { if debugFloat {
validate(x, y) validate(x)
validate(y)
} }
if z.prec == 0 { if z.prec == 0 {
...@@ -1104,7 +1106,8 @@ func (z *Float) Add(x, y *Float) *Float { ...@@ -1104,7 +1106,8 @@ func (z *Float) Add(x, y *Float) *Float {
// Precision, rounding, and accuracy reporting are as for Add. // Precision, rounding, and accuracy reporting are as for Add.
func (z *Float) Sub(x, y *Float) *Float { func (z *Float) Sub(x, y *Float) *Float {
if debugFloat { if debugFloat {
validate(x, y) validate(x)
validate(y)
} }
if z.prec == 0 { if z.prec == 0 {
...@@ -1143,7 +1146,8 @@ func (z *Float) Sub(x, y *Float) *Float { ...@@ -1143,7 +1146,8 @@ func (z *Float) Sub(x, y *Float) *Float {
// Precision, rounding, and accuracy reporting are as for Add. // Precision, rounding, and accuracy reporting are as for Add.
func (z *Float) Mul(x, y *Float) *Float { func (z *Float) Mul(x, y *Float) *Float {
if debugFloat { if debugFloat {
validate(x, y) validate(x)
validate(y)
} }
if z.prec == 0 { if z.prec == 0 {
...@@ -1171,7 +1175,8 @@ func (z *Float) Mul(x, y *Float) *Float { ...@@ -1171,7 +1175,8 @@ func (z *Float) Mul(x, y *Float) *Float {
// Precision, rounding, and accuracy reporting are as for Add. // Precision, rounding, and accuracy reporting are as for Add.
func (z *Float) Quo(x, y *Float) *Float { func (z *Float) Quo(x, y *Float) *Float {
if debugFloat { if debugFloat {
validate(x, y) validate(x)
validate(y)
} }
if z.prec == 0 { if z.prec == 0 {
...@@ -1251,7 +1256,8 @@ func (z *Float) Rsh(x *Float, s uint) *Float { ...@@ -1251,7 +1256,8 @@ func (z *Float) Rsh(x *Float, s uint) *Float {
// Infinities with matching sign are equal. // Infinities with matching sign are equal.
func (x *Float) Cmp(y *Float) int { func (x *Float) Cmp(y *Float) int {
if debugFloat { if debugFloat {
validate(x, y) validate(x)
validate(y)
} }
mx := x.ord() mx := x.ord()
......
...@@ -1077,6 +1077,8 @@ func TestFloatQuoSmoke(t *testing.T) { ...@@ -1077,6 +1077,8 @@ func TestFloatQuoSmoke(t *testing.T) {
} }
} }
// TODO(gri) Add tests that check correctness in the presence of aliasing.
// For rounding modes ToNegativeInf and ToPositiveInf, rounding is affected // For rounding modes ToNegativeInf and ToPositiveInf, rounding is affected
// by the sign of the value to be rounded. Test that rounding happens after // by the sign of the value to be rounded. Test that rounding happens after
// the sign of a result has been set. // the sign of a result has been set.
......
...@@ -361,7 +361,7 @@ func (x *Int) Uint64() uint64 { ...@@ -361,7 +361,7 @@ func (x *Int) Uint64() uint64 {
// and returns z and a boolean indicating success. If SetString fails, // and returns z and a boolean indicating success. If SetString fails,
// the value of z is undefined but the returned value is nil. // the value of z is undefined but the returned value is nil.
// //
// The base argument must be 0 or a value from 2 through MaxBase. If the base // The base argument must be 0 or a value between 2 and MaxBase. If the base
// is 0, the string prefix determines the actual conversion base. A prefix of // is 0, the string prefix determines the actual conversion base. A prefix of
// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a // ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10. // ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
......
...@@ -60,7 +60,7 @@ func pow(x Word, n int) (p Word) { ...@@ -60,7 +60,7 @@ func pow(x Word, n int) (p Word) {
// digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" . // digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
// //
// Unless fracOk is set, the base argument must be 0 or a value between // Unless fracOk is set, the base argument must be 0 or a value between
// 2 through MaxBase. If fracOk is set, the base argument must be one of // 2 and MaxBase. If fracOk is set, the base argument must be one of
// 0, 2, 10, or 16. Providing an invalid base argument leads to a run- // 0, 2, 10, or 16. Providing an invalid base argument leads to a run-
// time panic. // time panic.
// //
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment