Add division test + consistent Subtype conversion use

This commit is contained in:
mratsim 2018-02-17 12:44:51 +01:00
parent ac902b2a23
commit 6fd471f243
4 changed files with 33 additions and 12 deletions

View File

@ -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
@ -149,3 +149,11 @@ proc divmod*[T: BaseUint](x, y: T): tuple[quot, rem: T] {.noSideEffect.}=
# - 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
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

View File

@ -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

View File

@ -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

View File

@ -25,3 +25,14 @@ suite "Testing multiplication implementation":
let c = initMpUint(1_000, uint32)
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