Skip to content

Commit 6e271b2

Browse files
authored
math.big: change the handling of negatives in div_mod() to match gmp and Julia, add tests (#24713)
1 parent 12c20e3 commit 6e271b2

2 files changed

Lines changed: 32 additions & 25 deletions

File tree

‎vlib/math/big/big_test.v‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,20 @@ struct DivModTest {
248248

249249
// vfmt off
250250
const div_mod_test_data = [
251+
DivModTest{0, 7, 0, 0},
252+
DivModTest{0, -7, 0, 0},
253+
DivModTest{3, 7, 0, 3},
254+
DivModTest{-3, -7, 0, -3},
255+
DivModTest{-3, 7, 0, -3},
256+
DivModTest{3, -7, 0, 3},
257+
DivModTest{7, 3, 2, 1},
258+
DivModTest{-7, -3, 2, -1},
259+
DivModTest{-7, 3, -2, -1},
260+
DivModTest{7, -3, -2, 1},
261+
DivModTest{8, 2, 4, 0},
262+
DivModTest{-8, -2, 4, 0},
263+
DivModTest{-8, 2, -4, 0},
264+
DivModTest{8, -2, -4, 0},
251265
DivModTest{13, 10, 1, 3},
252266
DivModTest{13, 9, 1, 4},
253267
DivModTest{7, 5, 1, 2},

‎vlib/math/big/integer.v‎

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -415,38 +415,31 @@ pub fn (multiplicand Integer) * (multiplier Integer) Integer {
415415
//
416416
// DO NOT use this method if the divisor has any chance of being 0.
417417
fn (dividend Integer) div_mod_internal(divisor Integer) (Integer, Integer) {
418-
$if debug {
419-
assert divisor.signum != 0
420-
}
421-
422-
if dividend.signum == 0 {
423-
return zero_int, zero_int
424-
}
425-
if divisor == one_int {
426-
return dividend.clone(), zero_int
427-
}
428-
if divisor.signum == -1 {
429-
q, r := dividend.div_mod_internal(divisor.neg())
430-
return q.neg(), r
431-
}
432-
if dividend.signum == -1 {
433-
q, r := dividend.neg().div_mod_internal(divisor)
434-
if r.signum == 0 {
435-
return q.neg(), zero_int
436-
} else {
437-
return q.neg() - one_int, divisor - r
438-
}
439-
}
440-
// Division for positive integers
441418
mut q := []u32{cap: int_max(1, dividend.digits.len - divisor.digits.len + 1)}
442419
mut r := []u32{cap: dividend.digits.len}
420+
mut q_signum := 0
421+
mut r_signum := 0
422+
443423
divide_digit_array(dividend.digits, divisor.digits, mut q, mut r)
424+
if dividend.signum > 0 && divisor.signum > 0 {
425+
q_signum = 1
426+
r_signum = 1
427+
} else if dividend.signum > 0 && divisor.signum < 0 {
428+
q_signum = -1
429+
r_signum = 1
430+
} else if dividend.signum < 0 && divisor.signum > 0 {
431+
q_signum = -1
432+
r_signum = -1
433+
} else {
434+
q_signum = 1
435+
r_signum = -1
436+
}
444437
quotient := Integer{
445-
signum: if q.len == 0 { 0 } else { 1 }
438+
signum: if q.len == 0 { 0 } else { q_signum }
446439
digits: q
447440
}
448441
remainder := Integer{
449-
signum: if r.len == 0 { 0 } else { 1 }
442+
signum: if r.len == 0 { 0 } else { r_signum }
450443
digits: r
451444
}
452445
return quotient, remainder

0 commit comments

Comments
 (0)