#!/usr/bin/ruby

#
## Tests for the modulo operator
#

var m = 5;
var x = (100! + m);
var y = 23;

assert_eq( x %  y,     m);
assert_eq(-x % -y,    -m);
assert_eq( x % -y, m - y);
assert_eq(-x %  y, y - m);

assert_eq( x.rat %   y.rat,   m);
assert_eq(-x.rat %  -y.rat,  -m);
assert_eq( x.rat %  -y.rat,  m - y);
assert_eq(-x.rat %   y.rat,  y - m);

var f1 = 399.8;
var f2 = 41.2;

assert_eq( f1 %  f2 -> roundf( 0),    29);
assert_eq(-f1 % -f2 -> roundf( 0),   -29);
assert_eq( f1 % -f2 -> roundf(-1), -12.2);
assert_eq(-f1 %  f2 -> roundf(-1),  12.2);

for a,b in [[657512488, -20663738120], [-657512488, -20663738120], [-657512488, 20663738120]] {
    assert_eq([divmod(a,b)], [floor(a/b), a%b], [a,b])
}

for n in (31..33, 63..65), k in (31..33, 63..65), m in (31..33, 63..65) {

    var a = irand(1 << n)*[1,-1].rand
    var b = irand(1 << k)*[1,-1].rand
    var c = irand(1 << [k,n].rand)*[1,-1].rand
    var M = irand(1 << m)

    M || next

    assert_eq(imod(a - b, M),      (a - b) %  M, [a,b,M])
    assert_eq(imod(a - b,-M) % -M, (a - b) % -M, [a,b,-M])

    assert_eq(addmod(a, b, M),      (a+b) %  M, [a,b,M])
    assert_eq(addmod(a, b,-M) % -M, (a+b) % -M, [a,b,-M])

    assert_eq(submod(a, b, M),      (a-b) %  M, [a,b,M])
    assert_eq(submod(a, b,-M) % -M, (a-b) % -M, [a,b,-M])

    assert_eq(mulmod(a, b, M),      (a*b) %  M, [a,b,M])
    assert_eq(mulmod(a, b,-M) % -M, (a*b) % -M, [a,b,-M])

    assert_eq(addmulmod(a, b, c, M),      (a + b*c) %  M, [a,b,c,M])
    assert_eq(addmulmod(a, b, c,-M) % -M, (a + b*c) % -M, [a,b,c,-M])

    assert_eq(submulmod(a, b, c, M),      (a - b*c) %  M, [a,b,c,M])
    assert_eq(submulmod(a, b, c,-M) % -M, (a - b*c) % -M, [a,b,c,-M])

    assert_eq(muladdmod(a, b, c, M),      (a*b + c) %  M, [a,b,c,M])
    assert_eq(muladdmod(a, b, c,-M) % -M, (a*b + c) % -M, [a,b,c,M])

    assert_eq(mulsubmod(a, b, c, M),      (a*b - c) %  M, [a,b,c,M])
    assert_eq(mulsubmod(a, b, c,-M) % -M, (a*b - c) % -M, [a,b,c,M])

    if (b != 0) {
        assert_eq([divmod(a,b)], [floor(a/b), a%b], [a,b])
        assert_eq([divmod(a,b)], [idiv(a,b), imod(a,b)], [a,b])
    }

    if (b.is_coprime(M)) {
        assert_eq(divmod(a, b, M), (a*invmod(b,M))%M, [a,b,M])
        assert_eq(divmod(a, b, -M) % -M, (a*invmod(b,-M)) % -M, [a,b,-M])
    }
}

say "** Test passed!";