mirror of
https://github.com/golang/go.git
synced 2026-06-27 03:11:23 +00:00
math/big: add Int.Divide and RoundingMode aliases
Adds method Int.Divide to compute quotient and remainder of two Ints.
Adds RoundingMode aliases Trunc, Floor, Round and Ceil.
Fixes #76821
Change-Id: I7de80d76450f851d262b43a0685a0dc2218493f6
GitHub-Last-Rev: b52200bb94
GitHub-Pull-Request: golang/go#76820
Reviewed-on: https://go-review.googlesource.com/c/go/+/729860
Reviewed-by: Robert Griesemer <gri@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
TryBot-Bypass: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Peter Weinberger <pjw@google.com>
This commit is contained in:
parent
2677fe9bbe
commit
8f7f951965
4 changed files with 178 additions and 0 deletions
9
api/next/76821.txt
Normal file
9
api/next/76821.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
pkg math/big, method (*Int) Divide(*Int, *Int, *Int, RoundingMode) (*Int, *Int) #76821
|
||||
pkg math/big, const Trunc = 2 #76821
|
||||
pkg math/big, const Trunc RoundingMode #76821
|
||||
pkg math/big, const Floor = 4 #76821
|
||||
pkg math/big, const Floor RoundingMode #76821
|
||||
pkg math/big, const Round = 0 #76821
|
||||
pkg math/big, const Round RoundingMode #76821
|
||||
pkg math/big, const Ceil = 5 #76821
|
||||
pkg math/big, const Ceil RoundingMode #76821
|
||||
3
doc/next/6-stdlib/99-minor/math/big/76821.md
Normal file
3
doc/next/6-stdlib/99-minor/math/big/76821.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<!-- go.dev/issue/76821 -->
|
||||
[Int] now has method [Int.Divide] to compute quotient and remainder of two [Int] values.
|
||||
It supports rounding modes [Trunc], [Floor], [Round] and [Ceil].
|
||||
|
|
@ -1308,3 +1308,85 @@ func (z *Int) Sqrt(x *Int) *Int {
|
|||
z.abs = z.abs.sqrt(nil, x.abs)
|
||||
return z
|
||||
}
|
||||
|
||||
// Rounding modes that determine how the integer quotient is adjusted in an integer division.
|
||||
// See Daan Leijen, “Division and Modulus for Computer Scientists”, for details.
|
||||
const (
|
||||
Trunc = ToZero // T-division (same as Go division)
|
||||
Floor = ToNegativeInf // F-division
|
||||
Round = ToNearestEven // R-division
|
||||
Ceil = ToPositiveInf // C-division
|
||||
)
|
||||
|
||||
// Divide computes the integer quotient q and remainder r such that
|
||||
//
|
||||
// q = f(x/y)
|
||||
// r = x - y*q
|
||||
//
|
||||
// where f is described by the rounding mode,
|
||||
// which must be one of [Trunc], [Floor], [Round] or [Ceil].
|
||||
// Divide sets z to q if z != nil, updates r if r != nil,
|
||||
// and returns the pair (z, r) if y != 0.
|
||||
// If y == 0, a division-by-zero run-time panic occurs.
|
||||
func (z *Int) Divide(x, y, r *Int, mode RoundingMode) (*Int, *Int) {
|
||||
var z_abs nat
|
||||
if z != nil {
|
||||
z_abs = z.abs
|
||||
}
|
||||
var r_neg bool
|
||||
var r_abs nat
|
||||
if r != nil {
|
||||
r_abs = r.abs
|
||||
}
|
||||
y_abs := y.abs // save y
|
||||
if z == y || alias(z_abs, y.abs) {
|
||||
y_abs = nat(nil).set(y.abs)
|
||||
}
|
||||
neg := x.neg != y.neg
|
||||
z_abs, r_abs = z_abs.div(nil, r_abs, x.abs, y.abs)
|
||||
if len(r_abs) > 0 {
|
||||
switch mode {
|
||||
case Trunc:
|
||||
r_neg = x.neg
|
||||
case Floor:
|
||||
r_neg = y.neg
|
||||
if neg {
|
||||
z_abs = z_abs.add(z_abs, natOne)
|
||||
r_abs = r_abs.sub(y_abs, r_abs)
|
||||
}
|
||||
case Ceil:
|
||||
r_neg = !y.neg
|
||||
if !neg {
|
||||
z_abs = z_abs.add(z_abs, natOne)
|
||||
r_abs = r_abs.sub(y_abs, r_abs)
|
||||
}
|
||||
case Round:
|
||||
switch nat(nil).mul(nil, r_abs, natTwo).cmp(y_abs) {
|
||||
case -1:
|
||||
r_neg = x.neg
|
||||
case 0:
|
||||
even := len(z_abs) == 0 || z_abs[0]&1 == 0
|
||||
if even {
|
||||
r_neg = x.neg
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
case 1:
|
||||
r_neg = !x.neg
|
||||
z_abs = z_abs.add(z_abs, natOne)
|
||||
r_abs = r_abs.sub(y_abs, r_abs)
|
||||
}
|
||||
default:
|
||||
panic("unsupported rounding mode")
|
||||
}
|
||||
}
|
||||
if z != nil {
|
||||
z.abs = z_abs
|
||||
z.neg = neg && len(z_abs) > 0 // 0 has no sign
|
||||
}
|
||||
if r != nil {
|
||||
r.abs = r_abs
|
||||
r.neg = r_neg
|
||||
}
|
||||
return z, r
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2011,3 +2011,87 @@ func TestFloat64(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntDivide(t *testing.T) {
|
||||
x := new(Int)
|
||||
y := new(Int)
|
||||
q := new(Int)
|
||||
r := new(Int)
|
||||
qExp := new(Int)
|
||||
rExp := new(Int)
|
||||
factor, _ := new(Int).SetString("123_456_789_012_345_678_901", 0)
|
||||
msg := "%v(%v/%v): got q = %v r = %v, want q = %v r = %v"
|
||||
for i := int64(-10); i <= 10; i++ {
|
||||
for j := int64(-10); j <= 10; j++ {
|
||||
if j == 0 {
|
||||
continue
|
||||
}
|
||||
x.SetInt64(i)
|
||||
y.SetInt64(j)
|
||||
qExp.SetInt64(i / j)
|
||||
rExp.SetInt64(i % j)
|
||||
q, r = q.Divide(x, y, r, Trunc)
|
||||
if q.Cmp(qExp) != 0 || r.Cmp(rExp) != 0 {
|
||||
t.Errorf(msg, "trunc", x, y, q, r, qExp, rExp)
|
||||
}
|
||||
x.Mul(x, factor)
|
||||
y.Mul(y, factor)
|
||||
rExp.Mul(rExp, factor)
|
||||
q, r = q.Divide(x, y, r, Trunc)
|
||||
if q.Cmp(qExp) != 0 || r.Cmp(rExp) != 0 {
|
||||
t.Errorf(msg, "trunc", x, y, q, r, qExp, rExp)
|
||||
}
|
||||
|
||||
x.SetInt64(i)
|
||||
y.SetInt64(j)
|
||||
floor := int64(math.Floor(float64(i) / float64(j)))
|
||||
qExp.SetInt64(floor)
|
||||
rExp.SetInt64(i - j*floor)
|
||||
q, r = q.Divide(x, y, r, Floor)
|
||||
if q.Cmp(qExp) != 0 || r.Cmp(rExp) != 0 {
|
||||
t.Errorf(msg, "floor", x, y, q, r, qExp, rExp)
|
||||
}
|
||||
x.Mul(x, factor)
|
||||
y.Mul(y, factor)
|
||||
rExp.Mul(rExp, factor)
|
||||
q, r = q.Divide(x, y, r, Floor)
|
||||
if q.Cmp(qExp) != 0 || r.Cmp(rExp) != 0 {
|
||||
t.Errorf(msg, "floor", x, y, q, r, qExp, rExp)
|
||||
}
|
||||
|
||||
x.SetInt64(i)
|
||||
y.SetInt64(j)
|
||||
ceil := int64(math.Ceil(float64(i) / float64(j)))
|
||||
qExp.SetInt64(ceil)
|
||||
rExp.SetInt64(i - j*ceil)
|
||||
q, r = q.Divide(x, y, r, Ceil)
|
||||
if q.Cmp(qExp) != 0 || r.Cmp(rExp) != 0 {
|
||||
t.Errorf(msg, "ceil", x, y, q, r, qExp, rExp)
|
||||
}
|
||||
x.Mul(x, factor)
|
||||
y.Mul(y, factor)
|
||||
rExp.Mul(rExp, factor)
|
||||
q, r = q.Divide(x, y, r, Ceil)
|
||||
if q.Cmp(qExp) != 0 || r.Cmp(rExp) != 0 {
|
||||
t.Errorf(msg, "ceil", x, y, q, r, qExp, rExp)
|
||||
}
|
||||
|
||||
x.SetInt64(i)
|
||||
y.SetInt64(j)
|
||||
round := int64(math.RoundToEven(float64(i) / float64(j)))
|
||||
qExp.SetInt64(round)
|
||||
rExp.SetInt64(i - j*round)
|
||||
q, r = q.Divide(x, y, r, Round)
|
||||
if q.Cmp(qExp) != 0 || r.Cmp(rExp) != 0 {
|
||||
t.Errorf(msg, "round", x, y, q, r, qExp, rExp)
|
||||
}
|
||||
x.Mul(x, factor)
|
||||
y.Mul(y, factor)
|
||||
rExp.Mul(rExp, factor)
|
||||
q, r = q.Divide(x, y, r, Round)
|
||||
if q.Cmp(qExp) != 0 || r.Cmp(rExp) != 0 {
|
||||
t.Errorf(msg, "round", x, y, q, r, qExp, rExp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue