Skip to content

Commit

Permalink
Make sure Rem returns NaN when QuoInt would
Browse files Browse the repository at this point in the history
Fixes: #72
  • Loading branch information
ericlagergren committed Jan 29, 2018
1 parent fc05899 commit 2517341
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 11 deletions.
38 changes: 27 additions & 11 deletions big_ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,8 @@ func (c Context) Quantize(z *Big, n int) *Big {
}
// shift < 0
} else if yc, ok := arith.Pow10(uint64(-shift)); ok {
return z.quo(m, z.compact, neg, yc, 0)
z.quo(m, z.compact, neg, yc, 0)
return z
}
z.unscaled.SetUint64(z.compact)
z.compact = cst.Inflated
Expand Down Expand Up @@ -425,7 +426,10 @@ func (c Context) Quo(z, x, y *Big) *Big {
z.exp = (x.exp - y.exp) - shift
if shift > 0 {
if sx, ok := checked.MulPow10(x.compact, uint64(shift)); ok {
return z.quo(m, sx, x.form, y.compact, y.form)
if z.quo(m, sx, x.form, y.compact, y.form) {
c.Reduce(z)
}
return z
}
xb := z.unscaled.SetUint64(x.compact)
xb = checked.MulBigPow10(xb, xb, uint64(shift))
Expand All @@ -437,15 +441,19 @@ func (c Context) Quo(z, x, y *Big) *Big {
}
if shift < 0 {
if sy, ok := checked.MulPow10(y.compact, uint64(-shift)); ok {
return z.quo(m, x.compact, x.form, sy, y.form)
if z.quo(m, x.compact, x.form, sy, y.form) {
c.Reduce(z)
}
return z
}
yb := z.unscaled.SetUint64(y.compact)
yb = checked.MulBigPow10(yb, yb, uint64(-shift))
xb := new(big.Int).SetUint64(x.compact)
z.quoBig(m, xb, x.form, yb, y.form)
return z
}
return z.quo(m, x.compact, x.form, y.compact, y.form)
z.quo(m, x.compact, x.form, y.compact, y.form)
return z
}

xb, yb := &x.unscaled, &y.unscaled
Expand Down Expand Up @@ -475,19 +483,19 @@ func (c Context) Quo(z, x, y *Big) *Big {
return z
}

func (z *Big) quo(m RoundingMode, x uint64, xneg form, y uint64, yneg form) *Big {
func (z *Big) quo(m RoundingMode, x uint64, xneg form, y uint64, yneg form) bool {
z.form = xneg ^ yneg
z.compact = x / y
r := x % y
if r == 0 {
z.precision = arith.Length(z.compact)
return z
return true
}

z.Context.Conditions |= Inexact | Rounded
if m == ToZero {
z.precision = arith.Length(z.compact)
return z
return false
}

rc := 1
Expand All @@ -496,15 +504,15 @@ func (z *Big) quo(m RoundingMode, x uint64, xneg form, y uint64, yneg form) *Big
}

if m == unnecessary {
return z.setNaN(
InvalidOperation|InvalidContext|InsufficientStorage, qnan, quotermexp)
z.setNaN(InvalidOperation|InvalidContext|InsufficientStorage, qnan, quotermexp)
return false
}
if m.needsInc(z.compact&1 != 0, rc, xneg == yneg) {
z.Context.Conditions |= Rounded
z.compact++
}
z.precision = arith.Length(z.compact)
return z
return false
}

func (z *Big) quoBig(m RoundingMode, x *big.Int, xneg form, y *big.Int, yneg form) bool {
Expand Down Expand Up @@ -825,6 +833,8 @@ func (c Context) Reduce(z *Big) *Big {
return z
}

var I int

// Rem sets z to the remainder x % y. See QuoRem for more details.
func (c Context) Rem(z, x, y *Big) *Big {
if debug {
Expand All @@ -848,8 +858,14 @@ func (c Context) Rem(z, x, y *Big) *Big {
// 0 / y
return z.setZero(x.form&signbit, min(x.exp, y.exp))
}
_, z = c.quorem(nil, z, x, y)
// TODO(eric): See if we can get rid of tmp. See issue #72.
var tmp Big
_, z = c.quorem(&tmp, z, x, y)
z.exp = min(x.exp, y.exp)
tmp.exp = 0
if tmp.Precision() > precision(c) {
return z.setNaN(DivisionImpossible, qnan, quointprec)
}
return c.round(z)
}

Expand Down
14 changes: 14 additions & 0 deletions issues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,17 @@ got : %s (%d)
`, x, y, r, -r.Scale(), z, -z.Scale())
}
}

func TestIssue72(t *testing.T) {
x, _ := new(Big).SetString("-8.45632792449080367076920780185655231664817924617196338687858969707575095137356626097186102468204972266270655439471710162223657196797091956190618036249568250856310899052975275153410779062120467574000771085625757386351708361318971283364474972153263288762761014798575650687906566E+474")
y, _ := new(Big).SetString("4394389707820271499500265597691058417332780189928068605060129835915231607024733174128123086028964659911263805538968425927408117535552905751413991847682423230507052480632597367974353369255973450023914.06480266537851511912348920528179447782332532576762774258658035423323623047681531444628650113938865866058071268742035039370988065347285125745597527162817805470262344343643075954571122548882320506470664701832116848314413975179616459225485097673077072340532232446317251990415268245406080149594165531067657351225251495644780695372152557650401209918010537469259193951365404947434164664325966741900020673085975334136592934327584453217952431999450960191719318690339387778325911")
z := new(Big)
ctx := Context{Precision: 276}
ctx.Rem(z, x, y)
if !z.IsNaN(+1) {
t.Fatalf(`Rem(%s, %s)
wanted: NaN
got : %s
`, x, y, z)
}
}

0 comments on commit 2517341

Please sign in to comment.