Add division test + consistent Subtype conversion use
This commit is contained in:
parent
ac902b2a23
commit
6fd471f243
|
@ -10,11 +10,11 @@ proc `+=`*[T: MpUint](x: var T, y: T) {.noSideEffect.}=
|
|||
#
|
||||
# Optimized assembly should contain adc instruction (add with carry)
|
||||
# Clang on MacOS does with the -d:release switch and MpUint[uint32] (uint64)
|
||||
type MpBase = type x.lo
|
||||
type SubT = type x.lo
|
||||
let tmp = x.lo
|
||||
|
||||
x.lo += y.lo
|
||||
x.hi += MpBase(x.lo < tmp) + y.hi
|
||||
x.hi += SubT(x.lo < tmp) + y.hi
|
||||
|
||||
proc `+`*[T: MpUint](x, y: T): T {.noSideEffect, noInit, inline.}=
|
||||
# Addition for multi-precision unsigned int
|
||||
|
@ -26,11 +26,11 @@ proc `-=`*[T: MpUint](x: var T, y: T) {.noSideEffect.}=
|
|||
#
|
||||
# Optimized assembly should contain sbb instruction (substract with borrow)
|
||||
# Clang on MacOS does with the -d:release switch and MpUint[uint32] (uint64)
|
||||
type MpBase = type x.lo
|
||||
type SubT = type x.lo
|
||||
let tmp = x.lo
|
||||
|
||||
x.lo -= y.lo
|
||||
x.hi -= MpBase(x.lo > tmp) + y.hi
|
||||
x.hi -= SubT(x.lo > tmp) + y.hi
|
||||
|
||||
proc `-`*[T: MpUint](x, y: T): T {.noSideEffect, noInit, inline.}=
|
||||
# Substraction for multi-precision unsigned int
|
||||
|
@ -148,4 +148,12 @@ proc divmod*[T: BaseUint](x, y: T): tuple[quot, rem: T] {.noSideEffect.}=
|
|||
# - Python implementation: https://bugs.python.org/file11060/fast_div.py and discussion https://bugs.python.org/issue3451
|
||||
# - C++ implementation: https://github.com/linbox-team/givaro/blob/master/src/kernel/recint/rudiv.h
|
||||
# - The Handbook of Elliptic and Hyperelliptic Cryptography Algorithm 10.35 on page 188 has a more explicit version of the div2NxN algorithm. This algorithm is directly recursive and avoids the mutual recursion of the original paper's calls between div2NxN and div3Nx2N.
|
||||
# - Comparison of fast division algorithms fro large integers: http://bioinfo.ict.ac.cn/~dbu/AlgorithmCourses/Lectures/Hasselstrom2003.pdf
|
||||
# - Comparison of fast division algorithms fro large integers: http://bioinfo.ict.ac.cn/~dbu/AlgorithmCourses/Lectures/Hasselstrom2003.pdf
|
||||
|
||||
proc `div`*[T: BaseUint](x, y: T): T {.inline, noSideEffect.} =
|
||||
## Division operation for multi-precision unsigned uint
|
||||
divmod(x,y).quot
|
||||
|
||||
proc `mod`*[T: BaseUint](x, y: T): T {.inline, noSideEffect.} =
|
||||
## Division operation for multi-precision unsigned uint
|
||||
divmod(x,y).rem
|
|
@ -29,24 +29,26 @@ proc `shr`*[T: MpUint](x: T, y: SomeInteger): T {.noInit, noSideEffect.}
|
|||
|
||||
proc `shl`*[T: MpUint](x: T, y: SomeInteger): T {.noInit, noSideEffect.}=
|
||||
## Compute the `shift left` operation of x and y
|
||||
# Note: inlining this poses codegen/aliasing issue when doing `x = x shl 1`
|
||||
let
|
||||
halfSize = T.sizeof * 4
|
||||
|
||||
type Sub = type x.lo
|
||||
type SubT = type x.lo
|
||||
|
||||
result.hi = (x.hi shl y) or (x.lo shl (y - halfSize))
|
||||
result.lo = if y < halfSize: x.lo shl y
|
||||
else: 0.Sub
|
||||
else: 0.SubT
|
||||
|
||||
|
||||
proc `shr`*[T: MpUint](x: T, y: SomeInteger): T {.noInit, noSideEffect.}=
|
||||
## Compute the `shift right` operation of x and y
|
||||
# Note: inlining this poses codegen/aliasing issue when doing `x = x shl 1`
|
||||
let
|
||||
halfSize = T.sizeof * 4
|
||||
|
||||
type Sub = type x.lo
|
||||
type SubT = type x.lo
|
||||
|
||||
result.lo = (x.lo shr y) or (x.hi shl (y - halfSize)) # the shl is not a mistake
|
||||
result.hi = if y < halfSize: x.hi shr y
|
||||
else: 0.Sub
|
||||
else: 0.SubT
|
||||
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
# Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT).$
|
||||
|
||||
import test_endianness,
|
||||
test_comparison,
|
||||
test_addsub,
|
||||
test_mul,
|
||||
test_comparison
|
||||
test_muldiv
|
|
@ -24,4 +24,15 @@ suite "Testing multiplication implementation":
|
|||
let b = initMpUint(1_000_000_000, uint32)
|
||||
let c = initMpUint(1_000, uint32)
|
||||
|
||||
check: cast[uint64](a*b*c) == 1_000_000_000_000_000_000_000'u64 # need 70-bits
|
||||
check: cast[uint64](a*b*c) == 1_000_000_000_000_000_000_000'u64 # need 70-bits
|
||||
|
||||
|
||||
suite "Testing division and modulo implementation":
|
||||
test "Divmod returns the correct result":
|
||||
|
||||
let a = initMpUint(100, uint32)
|
||||
let b = initMpUint(13, uint32)
|
||||
let qr = a.divmod(b)
|
||||
|
||||
check: cast[uint64](qr.quot) == 7'u64
|
||||
check: cast[uint64](qr.rem) == 9'u64
|
Loading…
Reference in New Issue