nim-stint/tests/test_uint_muldiv.nim

315 lines
11 KiB
Nim
Raw Normal View History

# Stint
2018-03-02 10:48:08 +00:00
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
2019-10-23 02:20:06 +00:00
import ../stint, unittest, test_helpers
template chkMul(chk: untyped, a, b, c: string, bits: int) =
chk (fromHex(Stuint[bits], a) * fromHex(Stuint[bits], b)) == fromHex(Stuint[bits], c)
template chkDiv(chk: untyped, a, b, c: string, bits: int) =
chk (fromHex(Stuint[bits], a) div fromHex(Stuint[bits], b)) == fromHex(Stuint[bits], c)
template chkMod(chk: untyped, a, b, c: string, bits: int) =
chk (fromHex(Stuint[bits], a) mod fromHex(Stuint[bits], b)) == fromHex(Stuint[bits], c)
template chkDivMod(chk: untyped, a, b, c, d: string, bits: int) =
chk divmod(fromHex(Stuint[bits], a), fromHex(Stuint[bits], b)) == (fromHex(Stuint[bits], c), fromHex(Stuint[bits], d))
template testMuldiv(chk, tst: untyped) =
tst "operator `mul`":
chkMul(chk, "0", "3", "0", 8)
chkMul(chk, "1", "3", "3", 8)
chkMul(chk, "64", "3", "2C", 8) # overflow
chkMul(chk, "0", "3", "0", 16)
chkMul(chk, "1", "3", "3", 16)
chkMul(chk, "64", "3", "12C", 16)
chkMul(chk, "1770", "46", "68A0", 16) # overflow
chkMul(chk, "0", "3", "0", 32)
chkMul(chk, "1", "3", "3", 32)
chkMul(chk, "64", "3", "12C", 32)
chkMul(chk, "1770", "46", "668A0", 32)
chkMul(chk, "13880", "13880", "7D784000", 32) # overflow
chkMul(chk, "0", "3", "0", 64)
chkMul(chk, "1", "3", "3", 64)
chkMul(chk, "64", "3", "12C", 64)
chkMul(chk, "1770", "46", "668A0", 64)
chkMul(chk, "13880", "13880", "17D784000", 64)
chkMul(chk, "3B9ACA00", "E8D4A51000", "35C9ADC5DEA00000", 64) # overflow
chkMul(chk, "0", "3", "0", 128)
chkMul(chk, "1", "3", "3", 128)
chkMul(chk, "64", "3", "12C", 128)
chkMul(chk, "1770", "46", "668A0", 128)
chkMul(chk, "13880", "13880", "17D784000", 128)
chkMul(chk, "3B9ACA00", "E8D4A51000", "3635C9ADC5DEA00000", 128)
chkMul(chk, "25295F0D1", "10", "25295F0D10", 128)
chkMul(chk, "123456789ABCDEF00", "123456789ABCDEF00", "4b66dc33f6acdca5e20890f2a5210000", 128) # overflow
chkMul(chk, "123456789ABCDEF00", "123456789ABCDEF00", "14b66dc33f6acdca5e20890f2a5210000", 256)
tst "operator `div`":
chkDiv(chk, "0", "3", "0", 8)
chkDiv(chk, "1", "3", "0", 8)
chkDiv(chk, "3", "3", "1", 8)
chkDiv(chk, "3", "1", "3", 8)
chkDiv(chk, "FF", "3", "55", 8)
chkDiv(chk, "0", "3", "0", 16)
chkDiv(chk, "1", "3", "0", 16)
chkDiv(chk, "3", "3", "1", 16)
chkDiv(chk, "3", "1", "3", 16)
chkDiv(chk, "FF", "3", "55", 16)
chkDiv(chk, "FFFF", "3", "5555", 16)
chkDiv(chk, "0", "3", "0", 32)
chkDiv(chk, "1", "3", "0", 32)
chkDiv(chk, "3", "3", "1", 32)
chkDiv(chk, "3", "1", "3", 32)
chkDiv(chk, "FF", "3", "55", 32)
chkDiv(chk, "FFFF", "3", "5555", 32)
chkDiv(chk, "FFFFFFFF", "3", "55555555", 32)
chkDiv(chk, "0", "3", "0", 64)
chkDiv(chk, "1", "3", "0", 64)
chkDiv(chk, "3", "3", "1", 64)
chkDiv(chk, "3", "1", "3", 64)
chkDiv(chk, "FF", "3", "55", 64)
chkDiv(chk, "FFFF", "3", "5555", 64)
chkDiv(chk, "FFFFFFFF", "3", "55555555", 64)
chkDiv(chk, "FFFFFFFFFFFFFFFF", "3", "5555555555555555", 64)
chkDiv(chk, "0", "3", "0", 128)
chkDiv(chk, "1", "3", "0", 128)
chkDiv(chk, "3", "3", "1", 128)
chkDiv(chk, "3", "1", "3", 128)
chkDiv(chk, "FF", "3", "55", 128)
chkDiv(chk, "FFFF", "3", "5555", 128)
chkDiv(chk, "FFFFFFFF", "3", "55555555", 128)
chkDiv(chk, "FFFFFFFFFFFFFFFF", "3", "5555555555555555", 128)
chkDiv(chk, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", "3", "55555555555555555555555555555555", 128)
tst "operator `mod`":
chkMod(chk, "0", "3", "0", 8)
chkMod(chk, "1", "3", "1", 8)
chkMod(chk, "3", "3", "0", 8)
chkMod(chk, "3", "1", "0", 8)
chkMod(chk, "FF", "3", "0", 8)
chkMod(chk, "FF", "4", "3", 8)
chkMod(chk, "0", "3", "0", 16)
chkMod(chk, "1", "3", "1", 16)
chkMod(chk, "3", "3", "0", 16)
chkMod(chk, "3", "1", "0", 16)
chkMod(chk, "FF", "3", "0", 16)
chkMod(chk, "FF", "4", "3", 16)
chkMod(chk, "FFFF", "3", "0", 16)
chkMod(chk, "FFFF", "4", "3", 16)
chkMod(chk, "FFFF", "17", "8", 16)
chkMod(chk, "0", "3", "0", 32)
chkMod(chk, "1", "3", "1", 32)
chkMod(chk, "3", "3", "0", 32)
chkMod(chk, "3", "1", "0", 32)
chkMod(chk, "FF", "3", "0", 32)
chkMod(chk, "FF", "4", "3", 32)
chkMod(chk, "FFFF", "3", "0", 32)
chkMod(chk, "FFFF", "17", "8", 32)
chkMod(chk, "FFFFFFFF", "3", "0", 32)
chkMod(chk, "FFFFFFFF", "23", "A", 32)
chkMod(chk, "FFFFFFFF", "27", "15", 32)
chkMod(chk, "0", "3", "0", 64)
chkMod(chk, "1", "3", "1", 64)
chkMod(chk, "3", "3", "0", 64)
chkMod(chk, "3", "1", "0", 64)
chkMod(chk, "FF", "3", "0", 64)
chkMod(chk, "FF", "4", "3", 64)
chkMod(chk, "FFFF", "3", "0", 64)
chkMod(chk, "FFFF", "17", "8", 64)
chkMod(chk, "FFFFFFFF", "3", "0", 64)
chkMod(chk, "FFFFFFFF", "23", "A", 64)
chkMod(chk, "FFFFFFFF", "27", "15", 64)
chkMod(chk, "FFFFFFFFFFFFFFFF", "27", "F", 64)
chkMod(chk, "0", "3", "0", 128)
chkMod(chk, "1", "3", "1", 128)
chkMod(chk, "3", "3", "0", 128)
chkMod(chk, "3", "1", "0", 128)
chkMod(chk, "FF", "3", "0", 128)
chkMod(chk, "FF", "4", "3", 128)
chkMod(chk, "FFFF", "3", "0", 128)
chkMod(chk, "FFFF", "17", "8", 128)
chkMod(chk, "FFFFFFFF", "3", "0", 128)
chkMod(chk, "FFFFFFFF", "23", "A", 128)
chkMod(chk, "FFFFFFFF", "27", "15", 128)
chkMod(chk, "FFFFFFFFFFFFFFFF", "27", "F", 128)
chkMod(chk, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", "27", "15", 128)
tst "operator `divmod`":
chkDivMod(chk, "0", "3", "0", "0", 8)
chkDivMod(chk, "1", "3", "0", "1", 8)
chkDivMod(chk, "3", "3", "1", "0", 8)
chkDivMod(chk, "3", "1", "3", "0", 8)
chkDivMod(chk, "FF", "3", "55", "0", 8)
chkDivMod(chk, "FF", "4", "3F", "3", 8)
chkDivMod(chk, "0", "3", "0", "0", 16)
chkDivMod(chk, "1", "3", "0", "1", 16)
chkDivMod(chk, "3", "3", "1", "0", 16)
chkDivMod(chk, "3", "1", "3", "0", 16)
chkDivMod(chk, "FF", "3", "55", "0", 16)
chkDivMod(chk, "FF", "4", "3F", "3", 16)
chkDivMod(chk, "FFFF", "3", "5555", "0", 16)
chkDivMod(chk, "FFFF", "4", "3FFF", "3", 16)
chkDivMod(chk, "FFFF", "17", "B21", "8", 16)
chkDivMod(chk, "0", "3", "0", "0", 32)
chkDivMod(chk, "1", "3", "0", "1", 32)
chkDivMod(chk, "3", "3", "1", "0", 32)
chkDivMod(chk, "3", "1", "3", "0", 32)
chkDivMod(chk, "FF", "3", "55", "0", 32)
chkDivMod(chk, "FF", "4", "3F", "3", 32)
chkDivMod(chk, "FFFF", "3", "5555", "0", 32)
chkDivMod(chk, "FFFF", "17", "B21", "8", 32)
chkDivMod(chk, "FFFFFFFF", "3", "55555555", "0", 32)
chkDivMod(chk, "FFFFFFFF", "23", "7507507", "0A", 32)
chkDivMod(chk, "FFFFFFFF", "27", "6906906", "15", 32)
chkDivMod(chk, "0", "3", "0", "0", 64)
chkDivMod(chk, "1", "3", "0", "1", 64)
chkDivMod(chk, "3", "3", "1", "0", 64)
chkDivMod(chk, "3", "1", "3", "0", 64)
chkDivMod(chk, "FF", "3", "55", "0", 64)
chkDivMod(chk, "FF", "4", "3F", "3", 64)
chkDivMod(chk, "FFFF", "3", "5555", "0", 64)
chkDivMod(chk, "FFFF", "17", "B21", "8", 64)
chkDivMod(chk, "FFFFFFFF", "3", "55555555", "0", 64)
chkDivMod(chk, "FFFFFFFF", "23", "7507507", "0A", 64)
chkDivMod(chk, "FFFFFFFF", "27", "6906906", "15", 64)
chkDivMod(chk, "FFFFFFFFFFFFFFFF", "27", "690690690690690", "F", 64)
chkDivMod(chk, "0", "3", "0", "0", 128)
chkDivMod(chk, "1", "3", "0", "1", 128)
chkDivMod(chk, "3", "3", "1", "0", 128)
chkDivMod(chk, "3", "1", "3", "0", 128)
chkDivMod(chk, "FF", "3", "55", "0", 128)
chkDivMod(chk, "FF", "4", "3F", "3", 128)
chkDivMod(chk, "FFFF", "3", "5555", "0", 128)
chkDivMod(chk, "FFFF", "17", "B21", "8", 128)
chkDivMod(chk, "FFFFFFFF", "3", "55555555", "0", 128)
chkDivMod(chk, "FFFFFFFF", "23", "7507507", "0A", 128)
chkDivMod(chk, "FFFFFFFF", "27", "6906906", "15", 128)
chkDivMod(chk, "FFFFFFFFFFFFFFFF", "27", "690690690690690", "F", 128)
chkDivMod(chk, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", "27", "6906906906906906906906906906906", "15", 128)
static:
2019-10-23 02:20:06 +00:00
testMuldiv(ctCheck, ctTest)
suite "Wider unsigned int muldiv coverage":
testMuldiv(check, test)
suite "Testing unsigned int multiplication implementation":
test "Multiplication with result fitting in low half":
let a = 10000.stuint(64)
let b = 10000.stuint(64)
check: cast[uint64](a*b) == 100_000_000'u64 # need 27-bits
test "Multiplication with result overflowing low half":
let a = 1_000_000.stuint(64)
let b = 1_000_000.stuint(64)
check: cast[uint64](a*b) == 1_000_000_000_000'u64 # need 40 bits
test "Full overflow is handled like native unsigned types":
let a = 1_000_000_000.stuint(64)
let b = 1_000_000_000.stuint(64)
let c = 1_000.stuint(64)
let x = 1_000_000_000'u64
let y = 1_000_000_000'u64
let z = 1_000'u64
let w = x*y*z
#check: cast[uint64](a*b*c) == 1_000_000_000_000_000_000_000'u64 # need 70-bits
check: cast[uint64](a*b*c) == w
test "Nim v1.0.2 32 bit type inference rule changed":
let x = 9975492817.stuint(256)
let y = 16.stuint(256)
check x * y == 159607885072.stuint(256)
suite "Testing unsigned int division and modulo implementation":
test "Divmod(100, 13) returns the correct result":
let a = 100.stuint(64)
let b = 13.stuint(64)
let qr = divmod(a, b)
check: cast[uint64](qr.quot) == 7'u64
check: cast[uint64](qr.rem) == 9'u64
test "Divmod(2^64, 3) returns the correct result":
let a = 1.stuint(128) shl 64
let b = 3.stuint(128)
let qr = divmod(a, b)
2018-04-25 10:52:00 +00:00
let q = cast[UintImpl[uint64]](qr.quot)
let r = cast[UintImpl[uint64]](qr.rem)
check: q.lo == 6148914691236517205'u64
check: q.hi == 0'u64
check: r.lo == 1'u64
check: r.hi == 0'u64
test "Divmod(1234567891234567890, 10) returns the correct result":
let a = cast[StUint[64]](1234567891234567890'u64)
let b = cast[StUint[64]](10'u64)
let qr = divmod(a, b)
let q = cast[uint64](qr.quot)
let r = cast[uint64](qr.rem)
check: q == 123456789123456789'u64
check: r == 0'u64
suite "Testing specific failures highlighted by property-based testing":
test "Modulo: 65696211516342324 mod 174261910798982":
let u = 65696211516342324'u64
let v = 174261910798982'u64
let a = cast[Stuint[64]](u)
let b = cast[Stuint[64]](v)
let z = u mod v
let tz = cast[uint64](a mod b)
check: z == tz
test "Modulo: 15080397990160655 mod 600432699691":
let u = 15080397990160655'u64
let v = 600432699691'u64
let a = cast[Stuint[64]](u)
let b = cast[Stuint[64]](v)
let z = u mod v
let tz = cast[uint64](a mod b)
check: z == tz