Skip to content

Commit 5a81d8a

Browse files
authored
math.big: add mod_euclid() and mod_euclid_checked, similar to libgmp's mpz_mod(), add tests (#24764)
1 parent f732091 commit 5a81d8a

2 files changed

Lines changed: 48 additions & 0 deletions

File tree

‎vlib/math/big/big_test.v‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,21 @@ const div_test_data = [
300300
]
301301
// vfmt on
302302

303+
struct ModEuclidTest {
304+
dividend TestInteger
305+
divisor TestInteger
306+
modulus TestInteger
307+
}
308+
309+
// vfmt off
310+
const mod_euclid_test_data = [
311+
ModEuclidTest{-7, 3, 2},
312+
ModEuclidTest{7, 3, 1},
313+
ModEuclidTest{7, -3, 1},
314+
ModEuclidTest{-7, -3, 2},
315+
]
316+
// vfmt on
317+
303318
enum Comparison {
304319
less = -1
305320
equal = 0
@@ -655,6 +670,12 @@ fn test_mod() {
655670
}
656671
}
657672

673+
fn test_mod_euclid() {
674+
for t in mod_euclid_test_data {
675+
assert t.dividend.parse().mod_euclid(t.divisor.parse()) == t.modulus.parse()
676+
}
677+
}
678+
658679
fn test_mod_sign() {
659680
for a in -10 .. 10 {
660681
for b in -10 .. 10 {

‎vlib/math/big/integer.v‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,33 @@ pub fn (dividend Integer) mod_checked(divisor Integer) !Integer {
513513
return r
514514
}
515515

516+
// modulo_euclid returns the result of mathematical modulus.
517+
// The result is always non-negative for positive `divisor`.
518+
//
519+
// WARNING: this method will panic if `divisor == 0`.
520+
@[inline]
521+
pub fn (dividend Integer) mod_euclid(divisor Integer) Integer {
522+
r := dividend % divisor
523+
if r < zero_int {
524+
return r + divisor.abs()
525+
} else {
526+
return r
527+
}
528+
}
529+
530+
// mod_euclid_checked returns the result of mathematical modulus.
531+
// The result is always non-negative for positive `divisor`
532+
// or an error if `divisor == 0`.
533+
@[inline]
534+
pub fn (dividend Integer) mod_euclid_checked(divisor Integer) !Integer {
535+
r := dividend.mod_checked(divisor)!
536+
if r < zero_int {
537+
return r + divisor.abs()
538+
} else {
539+
return r
540+
}
541+
}
542+
516543
// mask_bits is the equivalent of `a % 2^n` (only when `a >= 0`), however doing a full division
517544
// run for this would be a lot of work when we can simply "cut off" all bits to the left of
518545
// the `n`th bit.

0 commit comments

Comments
 (0)