mirror of
https://github.com/status-im/nim-stint.git
synced 2025-02-21 03:18:13 +00:00
Rename the library to Stint (#26)
This commit is contained in:
parent
52a1849075
commit
102a1b0f0c
27
README.md
27
README.md
@ -1,20 +1,29 @@
|
|||||||
# Mpint (Multi-precision integers)
|
# Stint (Stack-based multiprecision integers)
|
||||||
|
|
||||||
[")](https://travis-ci.org/status-im/mpint)
|
[")](https://travis-ci.org/status-im/stint)
|
||||||
[](https://opensource.org/licenses/Apache-2.0)
|
[](https://opensource.org/licenses/Apache-2.0)
|
||||||
[](https://opensource.org/licenses/MIT)
|
[](https://opensource.org/licenses/MIT)
|
||||||

|

|
||||||
|
|
||||||
A fast and portable multi-precision integer library in pure Nim
|
A fast and portable stack-based multi-precision integer library in pure Nim
|
||||||
|
|
||||||
Main focus:
|
Main focus:
|
||||||
- no heap/dynamic allocation
|
- Portability
|
||||||
- uint256 for cryptographic and ethereum blockchain usage.
|
- 32 and 64 bit arch
|
||||||
- ARM portability for usage on mobile phones
|
- ARM for usage on mobile phones
|
||||||
|
- Additionally RISC-V and MIPS for open hardware and low power IoT devices.
|
||||||
|
- Speed, library is carefully tuned to produce the best assembly given the current compilers.
|
||||||
|
However, the library itself does not resort to assembly for portability.
|
||||||
|
- No heap/dynamic allocation
|
||||||
|
- Ethereum applications
|
||||||
|
- Uint256/Int256 for Ethereum Virtual Machine usage.
|
||||||
|
- Uint2048 for Ethereum Bloom filters
|
||||||
- Ease of use:
|
- Ease of use:
|
||||||
- casting to and from array of bytes
|
- Use traditional `+`, `-`, `+=`, etc operators like on native types
|
||||||
- converting to and from Hex
|
- Representation of numbers in memory is the exact same as native types and endianness aware.
|
||||||
- converting to and from decimal strings
|
- In practice that means that interfacing with binary blobs representing numbers from cryptographic libraries can be done with a `cast` if it represents a Uint256, Uint512, Uint1024, Uint2048.
|
||||||
|
- converting to and from Hex
|
||||||
|
- converting to and from decimal strings
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
@ -18,10 +18,10 @@ echo "Warmup: " & $(stop - start) & "s"
|
|||||||
|
|
||||||
start = cpuTime()
|
start = cpuTime()
|
||||||
block:
|
block:
|
||||||
var foo = 123.initMpUint(256)
|
var foo = 123.u(256)
|
||||||
for i in 0 ..< 10_000_000:
|
for i in 0 ..< 10_000_000:
|
||||||
foo += i.initMpUint(256) * i.initMpUint(256) mod 456.initMpUint(256)
|
foo += i.u(256) * i.u(256) mod 456.u(256)
|
||||||
foo = foo mod 789.initMpUint(256)
|
foo = foo mod 789.u(256)
|
||||||
|
|
||||||
stop = cpuTime()
|
stop = cpuTime()
|
||||||
echo "Library: " & $(stop - start) & "s"
|
echo "Library: " & $(stop - start) & "s"
|
||||||
|
@ -27,7 +27,7 @@ func tohexBE*[T: uint8 or uint16 or uint32 or uint64](x: T): string =
|
|||||||
for i in 0 ..< T.sizeof:
|
for i in 0 ..< T.sizeof:
|
||||||
result.add toHex(bytes[i])
|
result.add toHex(bytes[i])
|
||||||
|
|
||||||
func tohexBE*(x: MpUintImpl): string =
|
func tohexBE*(x: UintImpl): string =
|
||||||
## Stringify an uint to hex, Most significant byte on the left
|
## Stringify an uint to hex, Most significant byte on the left
|
||||||
## i.e. a (2.uint128)^64 + 1 will be 0000000100000001
|
## i.e. a (2.uint128)^64 + 1 will be 0000000100000001
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ proc isUint(x: NimNode): static[bool] =
|
|||||||
elif eqIdent(x, "uint8"): true
|
elif eqIdent(x, "uint8"): true
|
||||||
else: false
|
else: false
|
||||||
|
|
||||||
macro asWords*[T](n: MpUintImpl[T], ignoreEndianness: static[bool], loopBody: untyped): untyped =
|
macro asWords*[T](n: UintImpl[T], ignoreEndianness: static[bool], loopBody: untyped): untyped =
|
||||||
## Iterates over n, as an array of words.
|
## Iterates over n, as an array of words.
|
||||||
## Input:
|
## Input:
|
||||||
## - n: The Multiprecision int
|
## - n: The Multiprecision int
|
||||||
@ -96,7 +96,7 @@ macro asWords*[T](n: MpUintImpl[T], ignoreEndianness: static[bool], loopBody: un
|
|||||||
else:
|
else:
|
||||||
assert false, "Not implemented"
|
assert false, "Not implemented"
|
||||||
|
|
||||||
macro asWordsZip*[T](x, y: MpUintImpl[T], ignoreEndianness: static[bool], loopBody: untyped): untyped =
|
macro asWordsZip*[T](x, y: UintImpl[T], ignoreEndianness: static[bool], loopBody: untyped): untyped =
|
||||||
## Iterates over x and y, as an array of words.
|
## Iterates over x and y, as an array of words.
|
||||||
## Input:
|
## Input:
|
||||||
## - x, y: The multiprecision ints
|
## - x, y: The multiprecision ints
|
||||||
@ -155,7 +155,7 @@ macro asWordsZip*[T](x, y: MpUintImpl[T], ignoreEndianness: static[bool], loopBo
|
|||||||
for `idx` in countdown(`inner_x`[].len - 1, 0):
|
for `idx` in countdown(`inner_x`[].len - 1, 0):
|
||||||
`replacedAST`
|
`replacedAST`
|
||||||
|
|
||||||
macro m_asWordsZip*[T](m: var MpUintImpl[T], x: MpUintImpl[T], ignoreEndianness: static[bool], loopBody: untyped): untyped =
|
macro m_asWordsZip*[T](m: var UintImpl[T], x: UintImpl[T], ignoreEndianness: static[bool], loopBody: untyped): untyped =
|
||||||
## Iterates over a mutable int m and x as an array of words.
|
## Iterates over a mutable int m and x as an array of words.
|
||||||
## returning a !! Pointer !! of the proper type to m.
|
## returning a !! Pointer !! of the proper type to m.
|
||||||
## Input:
|
## Input:
|
||||||
@ -217,7 +217,7 @@ macro m_asWordsZip*[T](m: var MpUintImpl[T], x: MpUintImpl[T], ignoreEndianness:
|
|||||||
`replacedAST`
|
`replacedAST`
|
||||||
|
|
||||||
|
|
||||||
macro m_asWordsZip*[T](m: var MpUintImpl[T], x, y: MpUintImpl[T], ignoreEndianness: static[bool], loopBody: untyped): untyped =
|
macro m_asWordsZip*[T](m: var UintImpl[T], x, y: UintImpl[T], ignoreEndianness: static[bool], loopBody: untyped): untyped =
|
||||||
## Iterates over a mutable int m and x as an array of words.
|
## Iterates over a mutable int m and x as an array of words.
|
||||||
## returning a !! Pointer !! of the proper type to m.
|
## returning a !! Pointer !! of the proper type to m.
|
||||||
## Input:
|
## Input:
|
||||||
|
@ -14,7 +14,7 @@ export stdlib_bitops
|
|||||||
# MpInt rely on no undefined behaviour as often we scan 0. (if 1 is stored in a uint128 for example)
|
# MpInt rely on no undefined behaviour as often we scan 0. (if 1 is stored in a uint128 for example)
|
||||||
# Also countLeadingZeroBits must return the size of the type and not 0 like in the stdlib
|
# Also countLeadingZeroBits must return the size of the type and not 0 like in the stdlib
|
||||||
|
|
||||||
func countLeadingZeroBits*(n: MpUintImpl): int {.inline.} =
|
func countLeadingZeroBits*(n: UintImpl): int {.inline.} =
|
||||||
## Returns the number of leading zero bits in integer.
|
## Returns the number of leading zero bits in integer.
|
||||||
|
|
||||||
const maxHalfRepr = getSize(n) div 2
|
const maxHalfRepr = getSize(n) div 2
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
import ./uint_type,
|
import ./uint_type,
|
||||||
macros, typetraits
|
macros, typetraits
|
||||||
|
|
||||||
func initMpUintImpl*[InType, OutType](x: InType, _: typedesc[OutType]): OutType {.inline.} =
|
func initUintImpl*[InType, OutType](x: InType, _: typedesc[OutType]): OutType {.inline.} =
|
||||||
|
|
||||||
const
|
const
|
||||||
size_in = getSize(x)
|
size_in = getSize(x)
|
||||||
@ -27,12 +27,12 @@ func initMpUintImpl*[InType, OutType](x: InType, _: typedesc[OutType]): OutType
|
|||||||
elif size_in == size_out:
|
elif size_in == size_out:
|
||||||
result = cast[type result](x)
|
result = cast[type result](x)
|
||||||
else:
|
else:
|
||||||
result.lo = initMpUintImpl(x, type result.lo)
|
result.lo = initUintImpl(x, type result.lo)
|
||||||
|
|
||||||
func toSubtype*[T: SomeInteger](b: bool, _: typedesc[T]): T {.inline.}=
|
func toSubtype*[T: SomeInteger](b: bool, _: typedesc[T]): T {.inline.}=
|
||||||
b.T
|
b.T
|
||||||
|
|
||||||
func toSubtype*[T: MpUintImpl](b: bool, _: typedesc[T]): T {.inline.}=
|
func toSubtype*[T: UintImpl](b: bool, _: typedesc[T]): T {.inline.}=
|
||||||
type SubTy = type result.lo
|
type SubTy = type result.lo
|
||||||
result.lo = toSubtype(b, SubTy)
|
result.lo = toSubtype(b, SubTy)
|
||||||
|
|
||||||
@ -49,12 +49,12 @@ func one*[T: BaseUint](_: typedesc[T]): T {.inline.}=
|
|||||||
else:
|
else:
|
||||||
r_ptr[r_ptr[].len - 1] = 1
|
r_ptr[r_ptr[].len - 1] = 1
|
||||||
|
|
||||||
func toUint*(n: MpUIntImpl): auto {.inline.}=
|
func toUint*(n: UintImpl): auto {.inline.}=
|
||||||
## Casts a multiprecision integer to an uint of the same size
|
## Casts a multiprecision integer to an uint of the same size
|
||||||
|
|
||||||
# TODO: uint128 support
|
# TODO: uint128 support
|
||||||
when n.sizeof > 8:
|
when n.sizeof > 8:
|
||||||
raise newException("Unreachable. You are trying to cast a MpUint with more than 64-bit of precision")
|
raise newException("Unreachable. You are trying to cast a StUint with more than 64-bit of precision")
|
||||||
elif n.sizeof == 8:
|
elif n.sizeof == 8:
|
||||||
cast[uint64](n)
|
cast[uint64](n)
|
||||||
elif n.sizeof == 4:
|
elif n.sizeof == 4:
|
||||||
@ -62,14 +62,14 @@ func toUint*(n: MpUIntImpl): auto {.inline.}=
|
|||||||
elif n.sizeof == 2:
|
elif n.sizeof == 2:
|
||||||
cast[uint16](n)
|
cast[uint16](n)
|
||||||
else:
|
else:
|
||||||
raise newException("Unreachable. MpUInt must be 16-bit minimum and a power of 2")
|
raise newException("Unreachable. StUint must be 16-bit minimum and a power of 2")
|
||||||
|
|
||||||
func toUint*(n: SomeUnsignedInt): SomeUnsignedInt {.inline.}=
|
func toUint*(n: SomeUnsignedInt): SomeUnsignedInt {.inline.}=
|
||||||
## No-op overload of multi-precision int casting
|
## No-op overload of multi-precision int casting
|
||||||
n
|
n
|
||||||
|
|
||||||
func asDoubleUint*(n: BaseUint): auto {.inline.} =
|
func asDoubleUint*(n: BaseUint): auto {.inline.} =
|
||||||
## Convert an integer or MpUint to an uint with double the size
|
## Convert an integer or StUint to an uint with double the size
|
||||||
|
|
||||||
type Double = (
|
type Double = (
|
||||||
when n.sizeof == 4: uint64
|
when n.sizeof == 4: uint64
|
||||||
@ -80,17 +80,17 @@ func asDoubleUint*(n: BaseUint): auto {.inline.} =
|
|||||||
n.toUint.Double
|
n.toUint.Double
|
||||||
|
|
||||||
|
|
||||||
func toMpUintImpl*(n: uint16|uint32|uint64): auto {.inline.} =
|
func toUintImpl*(n: uint16|uint32|uint64): auto {.inline.} =
|
||||||
## Cast an integer to the corresponding size MpUintImpl
|
## Cast an integer to the corresponding size UintImpl
|
||||||
# Sometimes direct casting doesn't work and we must cast through a pointer
|
# Sometimes direct casting doesn't work and we must cast through a pointer
|
||||||
|
|
||||||
when n is uint64:
|
when n is uint64:
|
||||||
return (cast[ptr [MpUintImpl[uint32]]](unsafeAddr n))[]
|
return (cast[ptr [UintImpl[uint32]]](unsafeAddr n))[]
|
||||||
elif n is uint32:
|
elif n is uint32:
|
||||||
return (cast[ptr [MpUintImpl[uint16]]](unsafeAddr n))[]
|
return (cast[ptr [UintImpl[uint16]]](unsafeAddr n))[]
|
||||||
elif n is uint16:
|
elif n is uint16:
|
||||||
return (cast[ptr [MpUintImpl[uint8]]](unsafeAddr n))[]
|
return (cast[ptr [UintImpl[uint8]]](unsafeAddr n))[]
|
||||||
|
|
||||||
func toMpUintImpl*(n: MpUintImpl): MpUintImpl {.inline.} =
|
func toUintImpl*(n: UintImpl): UintImpl {.inline.} =
|
||||||
## No op
|
## No op
|
||||||
n
|
n
|
||||||
|
@ -14,25 +14,25 @@ import ./bithacks, ./conversion,
|
|||||||
|
|
||||||
# ############ Addition & Substraction ############ #
|
# ############ Addition & Substraction ############ #
|
||||||
|
|
||||||
proc `+=`*(x: var MpUintImpl, y: MpUintImpl) {.noSideEffect, inline.}=
|
proc `+=`*(x: var UintImpl, y: UintImpl) {.noSideEffect, inline.}=
|
||||||
## In-place addition for multi-precision unsigned int
|
## In-place addition for multi-precision unsigned int
|
||||||
|
|
||||||
type SubTy = type x.lo
|
type SubTy = type x.lo
|
||||||
x.lo += y.lo
|
x.lo += y.lo
|
||||||
x.hi += (x.lo < y.lo).toSubtype(SubTy) + y.hi
|
x.hi += (x.lo < y.lo).toSubtype(SubTy) + y.hi
|
||||||
|
|
||||||
proc `+`*(x, y: MpUintImpl): MpUintImpl {.noSideEffect, noInit, inline.}=
|
proc `+`*(x, y: UintImpl): UintImpl {.noSideEffect, noInit, inline.}=
|
||||||
# Addition for multi-precision unsigned int
|
# Addition for multi-precision unsigned int
|
||||||
result = x
|
result = x
|
||||||
result += y
|
result += y
|
||||||
|
|
||||||
proc `-`*(x, y: MpUintImpl): MpUintImpl {.noSideEffect, noInit, inline.}=
|
proc `-`*(x, y: UintImpl): UintImpl {.noSideEffect, noInit, inline.}=
|
||||||
# Substraction for multi-precision unsigned int
|
# Substraction for multi-precision unsigned int
|
||||||
|
|
||||||
type SubTy = type x.lo
|
type SubTy = type x.lo
|
||||||
result.lo = x.lo - y.lo
|
result.lo = x.lo - y.lo
|
||||||
result.hi = x.hi - y.hi - (x.lo < y.lo).toSubtype(SubTy)
|
result.hi = x.hi - y.hi - (x.lo < y.lo).toSubtype(SubTy)
|
||||||
|
|
||||||
proc `-=`*(x: var MpUintImpl, y: MpUintImpl) {.noSideEffect, inline.}=
|
proc `-=`*(x: var UintImpl, y: UintImpl) {.noSideEffect, inline.}=
|
||||||
## In-place substraction for multi-precision unsigned int
|
## In-place substraction for multi-precision unsigned int
|
||||||
x = x - y
|
x = x - y
|
||||||
|
@ -10,30 +10,30 @@
|
|||||||
import ./uint_type, ./as_words
|
import ./uint_type, ./as_words
|
||||||
|
|
||||||
|
|
||||||
func `not`*(x: MpUintImpl): MpUintImpl {.noInit, inline.}=
|
func `not`*(x: UintImpl): UintImpl {.noInit, inline.}=
|
||||||
## Bitwise complement of unsigned integer x
|
## Bitwise complement of unsigned integer x
|
||||||
m_asWordsZip(result, x, ignoreEndianness = true):
|
m_asWordsZip(result, x, ignoreEndianness = true):
|
||||||
result = not x
|
result = not x
|
||||||
|
|
||||||
func `or`*(x, y: MpUintImpl): MpUintImpl {.noInit, inline.}=
|
func `or`*(x, y: UintImpl): UintImpl {.noInit, inline.}=
|
||||||
## `Bitwise or` of numbers x and y
|
## `Bitwise or` of numbers x and y
|
||||||
m_asWordsZip(result, x, y, ignoreEndianness = true):
|
m_asWordsZip(result, x, y, ignoreEndianness = true):
|
||||||
result = x or y
|
result = x or y
|
||||||
|
|
||||||
func `and`*(x, y: MpUintImpl): MpUintImpl {.noInit, inline.}=
|
func `and`*(x, y: UintImpl): UintImpl {.noInit, inline.}=
|
||||||
## `Bitwise and` of numbers x and y
|
## `Bitwise and` of numbers x and y
|
||||||
m_asWordsZip(result, x, y, ignoreEndianness = true):
|
m_asWordsZip(result, x, y, ignoreEndianness = true):
|
||||||
result = x and y
|
result = x and y
|
||||||
|
|
||||||
func `xor`*(x, y: MpUintImpl): MpUintImpl {.noInit, inline.}=
|
func `xor`*(x, y: UintImpl): UintImpl {.noInit, inline.}=
|
||||||
## `Bitwise xor` of numbers x and y
|
## `Bitwise xor` of numbers x and y
|
||||||
m_asWordsZip(result, x, y, ignoreEndianness = true):
|
m_asWordsZip(result, x, y, ignoreEndianness = true):
|
||||||
result = x xor y
|
result = x xor y
|
||||||
|
|
||||||
func `shr`*(x: MpUintImpl, y: SomeInteger): MpUintImpl {.inline.}
|
func `shr`*(x: UintImpl, y: SomeInteger): UintImpl {.inline.}
|
||||||
# Forward declaration
|
# Forward declaration
|
||||||
|
|
||||||
func `shl`*(x: MpUintImpl, y: SomeInteger): MpUintImpl {.inline.}=
|
func `shl`*(x: UintImpl, y: SomeInteger): UintImpl {.inline.}=
|
||||||
## Compute the `shift left` operation of x and y
|
## Compute the `shift left` operation of x and y
|
||||||
# Note: inlining this poses codegen/aliasing issue when doing `x = x shl 1`
|
# Note: inlining this poses codegen/aliasing issue when doing `x = x shl 1`
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ func `shl`*(x: MpUintImpl, y: SomeInteger): MpUintImpl {.inline.}=
|
|||||||
else:
|
else:
|
||||||
result.hi = x.lo shl (y - halfSize)
|
result.hi = x.lo shl (y - halfSize)
|
||||||
|
|
||||||
func `shr`*(x: MpUintImpl, y: SomeInteger): MpUintImpl {.inline.}=
|
func `shr`*(x: UintImpl, y: SomeInteger): UintImpl {.inline.}=
|
||||||
## Compute the `shift right` operation of x and y
|
## Compute the `shift right` operation of x and y
|
||||||
const halfSize = getSize(x) div 2
|
const halfSize = getSize(x) div 2
|
||||||
|
|
||||||
|
@ -12,27 +12,27 @@ import ./uint_type, ./as_words
|
|||||||
func isZero*(n: SomeUnsignedInt): bool {.inline.} =
|
func isZero*(n: SomeUnsignedInt): bool {.inline.} =
|
||||||
n == 0
|
n == 0
|
||||||
|
|
||||||
func isZero*(n: MpUintImpl): bool {.inline.} =
|
func isZero*(n: UintImpl): bool {.inline.} =
|
||||||
asWords(n, ignoreEndianness = true):
|
asWords(n, ignoreEndianness = true):
|
||||||
if n != 0:
|
if n != 0:
|
||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
func `<`*(x, y: MpUintImpl): bool {.inline.}=
|
func `<`*(x, y: UintImpl): bool {.inline.}=
|
||||||
# Lower comparison for multi-precision integers
|
# Lower comparison for multi-precision integers
|
||||||
asWordsZip(x, y, ignoreEndianness = false):
|
asWordsZip(x, y, ignoreEndianness = false):
|
||||||
if x != y:
|
if x != y:
|
||||||
return x < y
|
return x < y
|
||||||
return false # they're equal
|
return false # they're equal
|
||||||
|
|
||||||
func `==`*(x, y: MpUintImpl): bool {.inline.}=
|
func `==`*(x, y: UintImpl): bool {.inline.}=
|
||||||
# Equal comparison for multi-precision integers
|
# Equal comparison for multi-precision integers
|
||||||
asWordsZip(x, y, ignoreEndianness = true):
|
asWordsZip(x, y, ignoreEndianness = true):
|
||||||
if x != y:
|
if x != y:
|
||||||
return false
|
return false
|
||||||
return true # they're equal
|
return true # they're equal
|
||||||
|
|
||||||
func `<=`*(x, y: MpUintImpl): bool {.inline.}=
|
func `<=`*(x, y: UintImpl): bool {.inline.}=
|
||||||
# Lower or equal comparison for multi-precision integers
|
# Lower or equal comparison for multi-precision integers
|
||||||
asWordsZip(x, y, ignoreEndianness = false):
|
asWordsZip(x, y, ignoreEndianness = false):
|
||||||
if x != y:
|
if x != y:
|
||||||
|
@ -45,24 +45,24 @@ import ./bithacks, ./conversion,
|
|||||||
###################################################################################################################
|
###################################################################################################################
|
||||||
|
|
||||||
func div2n1n[T: SomeunsignedInt](q, r: var T, n_hi, n_lo, d: T)
|
func div2n1n[T: SomeunsignedInt](q, r: var T, n_hi, n_lo, d: T)
|
||||||
func div2n1n(q, r: var MpUintImpl, ah, al, b: MpUintImpl)
|
func div2n1n(q, r: var UintImpl, ah, al, b: UintImpl)
|
||||||
# Forward declaration
|
# Forward declaration
|
||||||
|
|
||||||
proc divmod*(x, y: SomeInteger): tuple[quot, rem: SomeInteger] {.noSideEffect, inline.}=
|
proc divmod*(x, y: SomeInteger): tuple[quot, rem: SomeInteger] {.noSideEffect, inline.}=
|
||||||
# hopefully the compiler fuse that in a single op
|
# hopefully the compiler fuse that in a single op
|
||||||
(x div y, x mod y)
|
(x div y, x mod y)
|
||||||
|
|
||||||
func divmod*[T](x, y: MpUintImpl[T]): tuple[quot, rem: MpUintImpl[T]]
|
func divmod*[T](x, y: UintImpl[T]): tuple[quot, rem: UintImpl[T]]
|
||||||
# Forward declaration
|
# Forward declaration
|
||||||
|
|
||||||
func div3n2n[T]( q: var MpUintImpl[T],
|
func div3n2n[T]( q: var UintImpl[T],
|
||||||
r: var MpUintImpl[MpUintImpl[T]],
|
r: var UintImpl[UintImpl[T]],
|
||||||
a2, a1, a0: MpUintImpl[T],
|
a2, a1, a0: UintImpl[T],
|
||||||
b: MpUintImpl[MpUintImpl[T]]) =
|
b: UintImpl[UintImpl[T]]) =
|
||||||
|
|
||||||
var
|
var
|
||||||
c: MpUintImpl[T]
|
c: UintImpl[T]
|
||||||
d: MpUintImpl[MpUintImpl[T]]
|
d: UintImpl[UintImpl[T]]
|
||||||
carry: bool
|
carry: bool
|
||||||
|
|
||||||
if a2 < b.hi:
|
if a2 < b.hi:
|
||||||
@ -74,7 +74,7 @@ func div3n2n[T]( q: var MpUintImpl[T],
|
|||||||
carry = true
|
carry = true
|
||||||
|
|
||||||
extPrecMul[T](d, q, b.lo)
|
extPrecMul[T](d, q, b.lo)
|
||||||
let ca0 = MpUintImpl[type c](hi: c, lo: a0)
|
let ca0 = UintImpl[type c](hi: c, lo: a0)
|
||||||
|
|
||||||
r = ca0 - d
|
r = ca0 - d
|
||||||
|
|
||||||
@ -89,13 +89,13 @@ func div3n2n[T]( q: var MpUintImpl[T],
|
|||||||
|
|
||||||
proc div3n2n[T: SomeUnsignedInt](
|
proc div3n2n[T: SomeUnsignedInt](
|
||||||
q: var T,
|
q: var T,
|
||||||
r: var MpUintImpl[T],
|
r: var UintImpl[T],
|
||||||
a2, a1, a0: T,
|
a2, a1, a0: T,
|
||||||
b: MpUintImpl[T]) =
|
b: UintImpl[T]) =
|
||||||
|
|
||||||
var
|
var
|
||||||
c: T
|
c: T
|
||||||
d: MpUintImpl[T]
|
d: UintImpl[T]
|
||||||
carry: bool
|
carry: bool
|
||||||
|
|
||||||
if a2 < b.hi:
|
if a2 < b.hi:
|
||||||
@ -108,7 +108,7 @@ proc div3n2n[T: SomeUnsignedInt](
|
|||||||
carry = true
|
carry = true
|
||||||
|
|
||||||
extPrecMul[T](d, q, b.lo)
|
extPrecMul[T](d, q, b.lo)
|
||||||
let ca0 = MpUintImpl[T](hi: c, lo: a0)
|
let ca0 = UintImpl[T](hi: c, lo: a0)
|
||||||
r = ca0 - d
|
r = ca0 - d
|
||||||
|
|
||||||
if (not carry) and d > ca0:
|
if (not carry) and d > ca0:
|
||||||
@ -120,11 +120,11 @@ proc div3n2n[T: SomeUnsignedInt](
|
|||||||
dec q
|
dec q
|
||||||
r += b
|
r += b
|
||||||
|
|
||||||
func div2n1n(q, r: var MpUintImpl, ah, al, b: MpUintImpl) =
|
func div2n1n(q, r: var UintImpl, ah, al, b: UintImpl) =
|
||||||
|
|
||||||
# assert countLeadingZeroBits(b) == 0, "Divisor was not normalized"
|
# assert countLeadingZeroBits(b) == 0, "Divisor was not normalized"
|
||||||
|
|
||||||
var s: MpUintImpl
|
var s: UintImpl
|
||||||
div3n2n(q.hi, s, ah.hi, ah.lo, al.hi, b)
|
div3n2n(q.hi, s, ah.hi, ah.lo, al.hi, b)
|
||||||
div3n2n(q.lo, r, s.hi, s.lo, al.lo, b)
|
div3n2n(q.lo, r, s.hi, s.lo, al.lo, b)
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ func div2n1n[T: SomeunsignedInt](q, r: var T, n_hi, n_lo, d: T) =
|
|||||||
q = (q1 shl halfSize) or q2
|
q = (q1 shl halfSize) or q2
|
||||||
r = r2
|
r = r2
|
||||||
|
|
||||||
func divmodBZ[T](x, y: MpUintImpl[T], q, r: var MpUintImpl[T])=
|
func divmodBZ[T](x, y: UintImpl[T], q, r: var UintImpl[T])=
|
||||||
|
|
||||||
assert y.isZero.not() # This should be checked on release mode in the divmod caller proc
|
assert y.isZero.not() # This should be checked on release mode in the divmod caller proc
|
||||||
|
|
||||||
@ -209,7 +209,7 @@ func divmodBZ[T](x, y: MpUintImpl[T], q, r: var MpUintImpl[T])=
|
|||||||
let clz = countLeadingZeroBits(y)
|
let clz = countLeadingZeroBits(y)
|
||||||
|
|
||||||
let
|
let
|
||||||
xx = MpUintImpl[type x](lo: x) shl clz
|
xx = UintImpl[type x](lo: x) shl clz
|
||||||
yy = y shl clz
|
yy = y shl clz
|
||||||
|
|
||||||
# Compute
|
# Compute
|
||||||
@ -218,7 +218,7 @@ func divmodBZ[T](x, y: MpUintImpl[T], q, r: var MpUintImpl[T])=
|
|||||||
# Undo normalization
|
# Undo normalization
|
||||||
r = r shr clz
|
r = r shr clz
|
||||||
|
|
||||||
func divmodBS(x, y: MpUintImpl, q, r: var MpuintImpl) =
|
func divmodBS(x, y: UintImpl, q, r: var UintImpl) =
|
||||||
## Division for multi-precision unsigned uint
|
## Division for multi-precision unsigned uint
|
||||||
## Implementation through binary shift division
|
## Implementation through binary shift division
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ func divmodBS(x, y: MpUintImpl, q, r: var MpuintImpl) =
|
|||||||
const BinaryShiftThreshold = 8 # If the difference in bit-length is below 8
|
const BinaryShiftThreshold = 8 # If the difference in bit-length is below 8
|
||||||
# binary shift is probably faster
|
# binary shift is probably faster
|
||||||
|
|
||||||
func divmod*[T](x, y: MpUintImpl[T]): tuple[quot, rem: MpUintImpl[T]]=
|
func divmod*[T](x, y: UintImpl[T]): tuple[quot, rem: UintImpl[T]]=
|
||||||
|
|
||||||
let x_clz = x.countLeadingZeroBits
|
let x_clz = x.countLeadingZeroBits
|
||||||
let y_clz = y.countLeadingZeroBits
|
let y_clz = y.countLeadingZeroBits
|
||||||
@ -266,7 +266,7 @@ func divmod*[T](x, y: MpUintImpl[T]): tuple[quot, rem: MpUintImpl[T]]=
|
|||||||
# It is a bit tricky with recursive types. An empty n.lo means 0 or sizeof(n.lo)
|
# It is a bit tricky with recursive types. An empty n.lo means 0 or sizeof(n.lo)
|
||||||
let y_ctz = getSize(y) - y_clz - 1
|
let y_ctz = getSize(y) - y_clz - 1
|
||||||
result.quot = x shr y_ctz
|
result.quot = x shr y_ctz
|
||||||
result.rem = y_ctz.initMpUintImpl(MpUintImpl[T])
|
result.rem = y_ctz.initUintImpl(UintImpl[T])
|
||||||
result.rem = result.rem and x
|
result.rem = result.rem and x
|
||||||
elif x == y:
|
elif x == y:
|
||||||
result.quot.lo = one(T)
|
result.quot.lo = one(T)
|
||||||
@ -277,11 +277,11 @@ func divmod*[T](x, y: MpUintImpl[T]): tuple[quot, rem: MpUintImpl[T]]=
|
|||||||
else:
|
else:
|
||||||
divmodBZ(x, y, result.quot, result.rem)
|
divmodBZ(x, y, result.quot, result.rem)
|
||||||
|
|
||||||
func `div`*(x, y: MpUintImpl): MpUintImpl {.inline.} =
|
func `div`*(x, y: UintImpl): UintImpl {.inline.} =
|
||||||
## Division operation for multi-precision unsigned uint
|
## Division operation for multi-precision unsigned uint
|
||||||
divmod(x,y).quot
|
divmod(x,y).quot
|
||||||
|
|
||||||
func `mod`*(x, y: MpUintImpl): MpUintImpl {.inline.} =
|
func `mod`*(x, y: UintImpl): UintImpl {.inline.} =
|
||||||
## Division operation for multi-precision unsigned uint
|
## Division operation for multi-precision unsigned uint
|
||||||
divmod(x,y).rem
|
divmod(x,y).rem
|
||||||
|
|
||||||
|
@ -26,24 +26,24 @@ func hi[T:SomeUnsignedInt](x: T): T {.inline.} =
|
|||||||
p = T.sizeof * 8 div 2
|
p = T.sizeof * 8 div 2
|
||||||
result = x shr p
|
result = x shr p
|
||||||
|
|
||||||
# No generic, somehow Nim is given ambiguous call with the T: MpUintImpl overload
|
# No generic, somehow Nim is given ambiguous call with the T: UintImpl overload
|
||||||
func extPrecMul*(result: var MpUintImpl[uint8], x, y: uint8) =
|
func extPrecMul*(result: var UintImpl[uint8], x, y: uint8) =
|
||||||
## Extended precision multiplication
|
## Extended precision multiplication
|
||||||
result = cast[type result](x.asDoubleUint * y.asDoubleUint)
|
result = cast[type result](x.asDoubleUint * y.asDoubleUint)
|
||||||
|
|
||||||
func extPrecMul*(result: var MpUintImpl[uint16], x, y: uint16) =
|
func extPrecMul*(result: var UintImpl[uint16], x, y: uint16) =
|
||||||
## Extended precision multiplication
|
## Extended precision multiplication
|
||||||
result = cast[type result](x.asDoubleUint * y.asDoubleUint)
|
result = cast[type result](x.asDoubleUint * y.asDoubleUint)
|
||||||
|
|
||||||
func extPrecMul*(result: var MpUintImpl[uint32], x, y: uint32) =
|
func extPrecMul*(result: var UintImpl[uint32], x, y: uint32) =
|
||||||
## Extended precision multiplication
|
## Extended precision multiplication
|
||||||
result = cast[type result](x.asDoubleUint * y.asDoubleUint)
|
result = cast[type result](x.asDoubleUint * y.asDoubleUint)
|
||||||
|
|
||||||
func extPrecAddMul[T: uint8 or uint16 or uint32](result: var MpUintImpl[T], x, y: T) =
|
func extPrecAddMul[T: uint8 or uint16 or uint32](result: var UintImpl[T], x, y: T) =
|
||||||
## Extended precision fused in-place addition & multiplication
|
## Extended precision fused in-place addition & multiplication
|
||||||
result += cast[type result](x.asDoubleUint * y.asDoubleUint)
|
result += cast[type result](x.asDoubleUint * y.asDoubleUint)
|
||||||
|
|
||||||
template extPrecMulImpl(result: var MpUintImpl[uint64], op: untyped, u, v: uint64) =
|
template extPrecMulImpl(result: var UintImpl[uint64], op: untyped, u, v: uint64) =
|
||||||
const
|
const
|
||||||
p = 64 div 2
|
p = 64 div 2
|
||||||
base = 1 shl p
|
base = 1 shl p
|
||||||
@ -70,15 +70,15 @@ template extPrecMulImpl(result: var MpUintImpl[uint64], op: untyped, u, v: uint6
|
|||||||
op(result.hi, x3 + x1.hi)
|
op(result.hi, x3 + x1.hi)
|
||||||
op(result.lo, (x1 shl p) or x0.lo)
|
op(result.lo, (x1 shl p) or x0.lo)
|
||||||
|
|
||||||
func extPrecMul*(result: var MpUintImpl[uint64], u, v: uint64) =
|
func extPrecMul*(result: var UintImpl[uint64], u, v: uint64) =
|
||||||
## Extended precision multiplication
|
## Extended precision multiplication
|
||||||
extPrecMulImpl(result, `=`, u, v)
|
extPrecMulImpl(result, `=`, u, v)
|
||||||
|
|
||||||
func extPrecAddMul(result: var MpUintImpl[uint64], u, v: uint64) =
|
func extPrecAddMul(result: var UintImpl[uint64], u, v: uint64) =
|
||||||
## Extended precision fused in-place addition & multiplication
|
## Extended precision fused in-place addition & multiplication
|
||||||
extPrecMulImpl(result, `+=`, u, v)
|
extPrecMulImpl(result, `+=`, u, v)
|
||||||
|
|
||||||
func extPrecMul*[T](result: var MpUintImpl[MpUintImpl[T]], x, y: MpUintImpl[T]) =
|
func extPrecMul*[T](result: var UintImpl[UintImpl[T]], x, y: UintImpl[T]) =
|
||||||
# See details at
|
# See details at
|
||||||
# https://en.wikipedia.org/wiki/Karatsuba_algorithm
|
# https://en.wikipedia.org/wiki/Karatsuba_algorithm
|
||||||
# https://locklessinc.com/articles/256bit_arithmetic/
|
# https://locklessinc.com/articles/256bit_arithmetic/
|
||||||
@ -93,7 +93,7 @@ func extPrecMul*[T](result: var MpUintImpl[MpUintImpl[T]], x, y: MpUintImpl[T])
|
|||||||
# and introduce branching
|
# and introduce branching
|
||||||
# - More total operations means more register moves
|
# - More total operations means more register moves
|
||||||
|
|
||||||
var z1: MpUintImpl[T]
|
var z1: UintImpl[T]
|
||||||
|
|
||||||
# Low part - z0
|
# Low part - z0
|
||||||
extPrecMul(result.lo, x.lo, y.lo)
|
extPrecMul(result.lo, x.lo, y.lo)
|
||||||
@ -112,9 +112,9 @@ func extPrecMul*[T](result: var MpUintImpl[MpUintImpl[T]], x, y: MpUintImpl[T])
|
|||||||
# Finalize low part
|
# Finalize low part
|
||||||
result.lo.hi += z1.lo
|
result.lo.hi += z1.lo
|
||||||
if result.lo.hi < z1.lo:
|
if result.lo.hi < z1.lo:
|
||||||
result.hi += one(MpUintImpl[T])
|
result.hi += one(UintImpl[T])
|
||||||
|
|
||||||
func `*`*[T](x, y: MpUintImpl[T]): MpUintImpl[T] {.inline.}=
|
func `*`*[T](x, y: UintImpl[T]): UintImpl[T] {.inline.}=
|
||||||
## Multiplication for multi-precision unsigned uint
|
## Multiplication for multi-precision unsigned uint
|
||||||
#
|
#
|
||||||
# For our representation, it is similar to school grade multiplication
|
# For our representation, it is similar to school grade multiplication
|
||||||
|
@ -12,34 +12,34 @@
|
|||||||
import macros
|
import macros
|
||||||
|
|
||||||
|
|
||||||
# The macro getMpUintImpl must be exported
|
# The macro getUintImpl must be exported
|
||||||
|
|
||||||
when defined(mpint_test):
|
when defined(mpint_test):
|
||||||
macro getMpUintImpl*(bits: static[int]): untyped =
|
macro getUintImpl*(bits: static[int]): untyped =
|
||||||
# Test version, mpuint[64] = 2 uint32. Test the logic of the library
|
# Test version, StUint[64] = 2 uint32. Test the logic of the library
|
||||||
assert (bits and (bits-1)) == 0, $bits & " is not a power of 2"
|
assert (bits and (bits-1)) == 0, $bits & " is not a power of 2"
|
||||||
assert bits >= 16, "The number of bits in a should be greater or equal to 16"
|
assert bits >= 16, "The number of bits in a should be greater or equal to 16"
|
||||||
|
|
||||||
if bits >= 128:
|
if bits >= 128:
|
||||||
let inner = getAST(getMpUintImpl(bits div 2))
|
let inner = getAST(getUintImpl(bits div 2))
|
||||||
result = newTree(nnkBracketExpr, ident("MpUintImpl"), inner)
|
result = newTree(nnkBracketExpr, ident("UintImpl"), inner)
|
||||||
elif bits == 64:
|
elif bits == 64:
|
||||||
result = newTree(nnkBracketExpr, ident("MpUintImpl"), ident("uint32"))
|
result = newTree(nnkBracketExpr, ident("UintImpl"), ident("uint32"))
|
||||||
elif bits == 32:
|
elif bits == 32:
|
||||||
result = newTree(nnkBracketExpr, ident("MpUintImpl"), ident("uint16"))
|
result = newTree(nnkBracketExpr, ident("UintImpl"), ident("uint16"))
|
||||||
elif bits == 16:
|
elif bits == 16:
|
||||||
result = newTree(nnkBracketExpr, ident("MpUintImpl"), ident("uint8"))
|
result = newTree(nnkBracketExpr, ident("UintImpl"), ident("uint8"))
|
||||||
else:
|
else:
|
||||||
error "Fatal: unreachable"
|
error "Fatal: unreachable"
|
||||||
else:
|
else:
|
||||||
macro getMpUintImpl*(bits: static[int]): untyped =
|
macro getUintImpl*(bits: static[int]): untyped =
|
||||||
# Release version, mpuint[64] = uint64.
|
# Release version, StUint[64] = uint64.
|
||||||
assert (bits and (bits-1)) == 0, $bits & " is not a power of 2"
|
assert (bits and (bits-1)) == 0, $bits & " is not a power of 2"
|
||||||
assert bits >= 8, "The number of bits in a should be greater or equal to 8"
|
assert bits >= 8, "The number of bits in a should be greater or equal to 8"
|
||||||
|
|
||||||
if bits >= 128:
|
if bits >= 128:
|
||||||
let inner = getAST(getMpUintImpl(bits div 2))
|
let inner = getAST(getUintImpl(bits div 2))
|
||||||
result = newTree(nnkBracketExpr, ident("MpUintImpl"), inner)
|
result = newTree(nnkBracketExpr, ident("UintImpl"), inner)
|
||||||
elif bits == 64:
|
elif bits == 64:
|
||||||
result = ident("uint64")
|
result = ident("uint64")
|
||||||
elif bits == 32:
|
elif bits == 32:
|
||||||
@ -59,7 +59,7 @@ proc getSize*(x: NimNode): static[int] =
|
|||||||
var node = x.getTypeInst
|
var node = x.getTypeInst
|
||||||
|
|
||||||
while node.kind == nnkBracketExpr:
|
while node.kind == nnkBracketExpr:
|
||||||
assert eqIdent(node[0], "MpuintImpl")
|
assert eqIdent(node[0], "UintImpl")
|
||||||
multiplier *= 2
|
multiplier *= 2
|
||||||
node = node[1]
|
node = node[1]
|
||||||
|
|
||||||
@ -86,15 +86,15 @@ type
|
|||||||
# ### Private ### #
|
# ### Private ### #
|
||||||
# If this is not in the same type section
|
# If this is not in the same type section
|
||||||
# the compiler has trouble
|
# the compiler has trouble
|
||||||
BaseUint* = MpUintImpl or SomeUnsignedInt
|
BaseUint* = UintImpl or SomeUnsignedInt
|
||||||
|
|
||||||
MpUintImpl*[Baseuint] = object
|
UintImpl*[Baseuint] = object
|
||||||
when system.cpuEndian == littleEndian:
|
when system.cpuEndian == littleEndian:
|
||||||
lo*, hi*: BaseUint
|
lo*, hi*: BaseUint
|
||||||
else:
|
else:
|
||||||
hi*, lo*: BaseUint
|
hi*, lo*: BaseUint
|
||||||
# ### Private ### #
|
# ### Private ### #
|
||||||
|
|
||||||
MpUint*[bits: static[int]] = object
|
StUint*[bits: static[int]] = object
|
||||||
data*: getMpUintImpl(bits)
|
data*: getUintImpl(bits)
|
||||||
# wrapped in object to avoid recursive calls
|
# wrapped in object to avoid recursive calls
|
||||||
|
@ -13,17 +13,17 @@ import ./private/uint_type
|
|||||||
|
|
||||||
import typetraits
|
import typetraits
|
||||||
|
|
||||||
func initMpUint*[T: SomeInteger](n: T, bits: static[int]): MpUint[bits] {.inline.}=
|
func u*[T: SomeInteger](n: T, bits: static[int]): StUint[bits] {.inline.}=
|
||||||
assert n >= 0.T
|
assert n >= 0.T
|
||||||
when result.data is MpuintImpl:
|
when result.data is UintImpl:
|
||||||
when getSize(n) > bits:
|
when getSize(n) > bits:
|
||||||
# To avoid a costly runtime check, we refuse storing into MpUint types smaller
|
# To avoid a costly runtime check, we refuse storing into StUint types smaller
|
||||||
# than the input type.
|
# than the input type.
|
||||||
raise newException(ValueError, "Input " & $n & " (" & $T &
|
raise newException(ValueError, "Input " & $n & " (" & $T &
|
||||||
") cannot be stored in a multi-precision " &
|
") cannot be stored in a multi-precision " &
|
||||||
$bits & "-bit integer." &
|
$bits & "-bit integer." &
|
||||||
"\nUse a smaller input type instead. This is a compile-time check" &
|
"\nUse a smaller input type instead. This is a compile-time check" &
|
||||||
" to avoid a costly run-time bit_length check at each MpUint initialization.")
|
" to avoid a costly run-time bit_length check at each StUint initialization.")
|
||||||
else:
|
else:
|
||||||
let r_ptr = cast[ptr array[bits div (sizeof(T) * 8), T]](result.addr)
|
let r_ptr = cast[ptr array[bits div (sizeof(T) * 8), T]](result.addr)
|
||||||
when system.cpuEndian == littleEndian:
|
when system.cpuEndian == littleEndian:
|
||||||
|
@ -8,55 +8,55 @@
|
|||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import ./private/uint_type, macros
|
import ./private/uint_type, macros
|
||||||
export MpUint, MpUintImpl, getMpUintImpl # TODO remove the need to export MpUintImpl and this macro
|
export StUint, UintImpl, getUintImpl # TODO remove the need to export UintImpl and this macro
|
||||||
|
|
||||||
type
|
type
|
||||||
UInt128* = MpUint[128]
|
UInt128* = StUint[128]
|
||||||
UInt256* = MpUint[256]
|
UInt256* = StUint[256]
|
||||||
|
|
||||||
template make_conv(conv_name: untyped, size: int): untyped =
|
template make_conv(conv_name: untyped, size: int): untyped =
|
||||||
func `convname`*(n: SomeInteger): MpUint[size] {.inline, noInit.}=
|
func `convname`*(n: SomeInteger): StUint[size] {.inline, noInit.}=
|
||||||
n.initMpUint(size)
|
n.u(size)
|
||||||
|
|
||||||
make_conv(u128, 128)
|
make_conv(u128, 128)
|
||||||
make_conv(u256, 256)
|
make_conv(u256, 256)
|
||||||
|
|
||||||
template make_unary(op, ResultTy): untyped =
|
template make_unary(op, ResultTy): untyped =
|
||||||
func `op`*(x: MpUint): ResultTy {.noInit, inline.} =
|
func `op`*(x: StUint): ResultTy {.noInit, inline.} =
|
||||||
when ResultTy is MpUint:
|
when ResultTy is StUint:
|
||||||
result.data = op(x.data)
|
result.data = op(x.data)
|
||||||
else:
|
else:
|
||||||
op(x.data)
|
op(x.data)
|
||||||
export op
|
export op
|
||||||
|
|
||||||
template make_binary(op, ResultTy): untyped =
|
template make_binary(op, ResultTy): untyped =
|
||||||
func `op`*(x, y: MpUint): ResultTy {.noInit, inline.} =
|
func `op`*(x, y: StUint): ResultTy {.noInit, inline.} =
|
||||||
when ResultTy is MpUint:
|
when ResultTy is StUint:
|
||||||
result.data = op(x.data, y.data)
|
result.data = op(x.data, y.data)
|
||||||
else:
|
else:
|
||||||
op(x.data, y.data)
|
op(x.data, y.data)
|
||||||
export `op`
|
export `op`
|
||||||
|
|
||||||
template make_binary_inplace(op): untyped =
|
template make_binary_inplace(op): untyped =
|
||||||
func `op`*(x: var MpUint, y: MpUint) {.inline.} =
|
func `op`*(x: var StUint, y: StUint) {.inline.} =
|
||||||
op(x.data, y.data)
|
op(x.data, y.data)
|
||||||
export op
|
export op
|
||||||
|
|
||||||
import ./private/uint_addsub
|
import ./private/uint_addsub
|
||||||
|
|
||||||
make_binary(`+`, MpUint)
|
make_binary(`+`, StUint)
|
||||||
make_binary_inplace(`+=`)
|
make_binary_inplace(`+=`)
|
||||||
make_binary(`-`, MpUint)
|
make_binary(`-`, StUint)
|
||||||
make_binary_inplace(`-=`)
|
make_binary_inplace(`-=`)
|
||||||
|
|
||||||
import ./private/uint_mul
|
import ./private/uint_mul
|
||||||
make_binary(`*`, MpUint)
|
make_binary(`*`, StUint)
|
||||||
|
|
||||||
import ./private/uint_div
|
import ./private/uint_div
|
||||||
|
|
||||||
make_binary(`div`, MpUint)
|
make_binary(`div`, StUint)
|
||||||
make_binary(`mod`, MpUint)
|
make_binary(`mod`, StUint)
|
||||||
func divmod*(x, y: MpUint): tuple[quot, rem: MpUint] {.noInit, inline.} =
|
func divmod*(x, y: StUint): tuple[quot, rem: StUint] {.noInit, inline.} =
|
||||||
(result.quot.data, result.rem.data) = divmod(x.data, y.data)
|
(result.quot.data, result.rem.data) = divmod(x.data, y.data)
|
||||||
|
|
||||||
import ./private/uint_comparison
|
import ./private/uint_comparison
|
||||||
@ -64,15 +64,15 @@ import ./private/uint_comparison
|
|||||||
make_binary(`<`, bool)
|
make_binary(`<`, bool)
|
||||||
make_binary(`<=`, bool)
|
make_binary(`<=`, bool)
|
||||||
make_binary(`==`, bool)
|
make_binary(`==`, bool)
|
||||||
func isZero*(x: MpUint): bool {.inline.} = isZero x.data
|
func isZero*(x: StUint): bool {.inline.} = isZero x.data
|
||||||
|
|
||||||
import ./private/uint_bitwise_ops
|
import ./private/uint_bitwise_ops
|
||||||
|
|
||||||
make_unary(`not`, MpUint)
|
make_unary(`not`, StUint)
|
||||||
make_binary(`or`, MpUint)
|
make_binary(`or`, StUint)
|
||||||
make_binary(`and`, MpUint)
|
make_binary(`and`, StUint)
|
||||||
make_binary(`xor`, MpUint)
|
make_binary(`xor`, StUint)
|
||||||
proc `shr`*(x: Mpuint, y: SomeInteger): MpUint {.noInit, inline, noSideEffect.} =
|
proc `shr`*(x: StUint, y: SomeInteger): StUint {.noInit, inline, noSideEffect.} =
|
||||||
result.data = x.data shr y
|
result.data = x.data shr y
|
||||||
proc `shl`*(x: Mpuint, y: SomeInteger): MpUint {.noInit, inline, noSideEffect.} =
|
proc `shl`*(x: StUint, y: SomeInteger): StUint {.noInit, inline, noSideEffect.} =
|
||||||
result.data = x.data shl y
|
result.data = x.data shl y
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
packageName = "mpint"
|
packageName = "stint"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
author = "Status Research & Development GmbH"
|
author = "Status Research & Development GmbH"
|
||||||
description = "Efficient multiprecision int in Nim"
|
description = "Efficient stack-based multiprecision int in Nim"
|
||||||
license = "Apache License 2.0 or MIT"
|
license = "Apache License 2.0 or MIT"
|
||||||
srcDir = "src"
|
srcDir = "src"
|
||||||
|
|
||||||
@ -20,19 +20,19 @@ proc test(name: string, lang: string = "c") =
|
|||||||
switch("out", ("./build/" & name))
|
switch("out", ("./build/" & name))
|
||||||
setCommand lang, "tests/" & name & ".nim"
|
setCommand lang, "tests/" & name & ".nim"
|
||||||
|
|
||||||
task test_debug, "Run all tests - test implementation (MpUint[64] = 2x uint32":
|
task test_debug, "Run all tests - test implementation (StUint[64] = 2x uint32":
|
||||||
switch("define", "mpint_test")
|
switch("define", "mpint_test")
|
||||||
test "all_tests"
|
test "all_tests"
|
||||||
|
|
||||||
task test_release, "Run all tests - prod implementation (MpUint[64] = uint64":
|
task test_release, "Run all tests - prod implementation (StUint[64] = uint64":
|
||||||
test "all_tests"
|
test "all_tests"
|
||||||
|
|
||||||
task test_property_debug, "Run random tests (normal mode) - test implementation (MpUint[64] = 2x uint32)":
|
task test_property_debug, "Run random tests (normal mode) - test implementation (StUint[64] = 2x uint32)":
|
||||||
requires "quicktest > 0.0.8"
|
requires "quicktest > 0.0.8"
|
||||||
switch("define", "mpint_test")
|
switch("define", "mpint_test")
|
||||||
test "property_based"
|
test "property_based"
|
||||||
|
|
||||||
task test_property_release, "Run random tests (release mode) - test implementation (MpUint[64] = 2x uint32)":
|
task test_property_release, "Run random tests (release mode) - test implementation (StUint[64] = 2x uint32)":
|
||||||
requires "quicktest > 0.0.8"
|
requires "quicktest > 0.0.8"
|
||||||
switch("define", "mpint_test")
|
switch("define", "mpint_test")
|
||||||
switch("define", "release")
|
switch("define", "release")
|
@ -24,13 +24,13 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
when sizeof(int) == 8:
|
when sizeof(int) == 8:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[64]](x)
|
tx = cast[StUint[64]](x)
|
||||||
ty = cast[MpUint[64]](y)
|
ty = cast[StUint[64]](y)
|
||||||
tz = tx or ty
|
tz = tx or ty
|
||||||
else:
|
else:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[32]](x)
|
tx = cast[StUint[32]](x)
|
||||||
ty = cast[MpUint[32]](y)
|
ty = cast[StUint[32]](y)
|
||||||
tz = tx or ty
|
tz = tx or ty
|
||||||
|
|
||||||
|
|
||||||
@ -41,13 +41,13 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
when sizeof(int) == 8:
|
when sizeof(int) == 8:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[64]](x)
|
tx = cast[StUint[64]](x)
|
||||||
ty = cast[MpUint[64]](y)
|
ty = cast[StUint[64]](y)
|
||||||
tz = tx and ty
|
tz = tx and ty
|
||||||
else:
|
else:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[32]](x)
|
tx = cast[StUint[32]](x)
|
||||||
ty = cast[MpUint[32]](y)
|
ty = cast[StUint[32]](y)
|
||||||
tz = tx and ty
|
tz = tx and ty
|
||||||
|
|
||||||
check(cast[uint](tz) == (x and y))
|
check(cast[uint](tz) == (x and y))
|
||||||
@ -56,13 +56,13 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
when sizeof(int) == 8:
|
when sizeof(int) == 8:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[64]](x)
|
tx = cast[StUint[64]](x)
|
||||||
ty = cast[MpUint[64]](y)
|
ty = cast[StUint[64]](y)
|
||||||
tz = tx xor ty
|
tz = tx xor ty
|
||||||
else:
|
else:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[32]](x)
|
tx = cast[StUint[32]](x)
|
||||||
ty = cast[MpUint[32]](y)
|
ty = cast[StUint[32]](y)
|
||||||
tz = tx xor ty
|
tz = tx xor ty
|
||||||
|
|
||||||
check(cast[uint](tz) == (x xor y))
|
check(cast[uint](tz) == (x xor y))
|
||||||
@ -71,11 +71,11 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
when sizeof(int) == 8:
|
when sizeof(int) == 8:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[64]](x)
|
tx = cast[StUint[64]](x)
|
||||||
tz = not tx
|
tz = not tx
|
||||||
else:
|
else:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[32]](x)
|
tx = cast[StUint[32]](x)
|
||||||
tz = not tx
|
tz = not tx
|
||||||
|
|
||||||
check(cast[uint](tz) == (not x))
|
check(cast[uint](tz) == (not x))
|
||||||
@ -84,13 +84,13 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
when sizeof(int) == 8:
|
when sizeof(int) == 8:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[64]](x)
|
tx = cast[StUint[64]](x)
|
||||||
ty = cast[MpUint[64]](y)
|
ty = cast[StUint[64]](y)
|
||||||
tz = tx < ty
|
tz = tx < ty
|
||||||
else:
|
else:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[32]](x)
|
tx = cast[StUint[32]](x)
|
||||||
ty = cast[MpUint[32]](y)
|
ty = cast[StUint[32]](y)
|
||||||
tz = tx < ty
|
tz = tx < ty
|
||||||
|
|
||||||
check(tz == (x < y))
|
check(tz == (x < y))
|
||||||
@ -100,13 +100,13 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
when sizeof(int) == 8:
|
when sizeof(int) == 8:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[64]](x)
|
tx = cast[StUint[64]](x)
|
||||||
ty = cast[MpUint[64]](y)
|
ty = cast[StUint[64]](y)
|
||||||
tz = tx <= ty
|
tz = tx <= ty
|
||||||
else:
|
else:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[32]](x)
|
tx = cast[StUint[32]](x)
|
||||||
ty = cast[MpUint[32]](y)
|
ty = cast[StUint[32]](y)
|
||||||
tz = tx <= ty
|
tz = tx <= ty
|
||||||
|
|
||||||
check(tz == (x <= y))
|
check(tz == (x <= y))
|
||||||
@ -115,13 +115,13 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
when sizeof(int) == 8:
|
when sizeof(int) == 8:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[64]](x)
|
tx = cast[StUint[64]](x)
|
||||||
ty = cast[MpUint[64]](y)
|
ty = cast[StUint[64]](y)
|
||||||
tz = tx + ty
|
tz = tx + ty
|
||||||
else:
|
else:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[32]](x)
|
tx = cast[StUint[32]](x)
|
||||||
ty = cast[MpUint[32]](y)
|
ty = cast[StUint[32]](y)
|
||||||
tz = tx + ty
|
tz = tx + ty
|
||||||
|
|
||||||
check(cast[uint](tz) == x+y)
|
check(cast[uint](tz) == x+y)
|
||||||
@ -131,13 +131,13 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
when sizeof(int) == 8:
|
when sizeof(int) == 8:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[64]](x)
|
tx = cast[StUint[64]](x)
|
||||||
ty = cast[MpUint[64]](y)
|
ty = cast[StUint[64]](y)
|
||||||
tz = tx - ty
|
tz = tx - ty
|
||||||
else:
|
else:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[32]](x)
|
tx = cast[StUint[32]](x)
|
||||||
ty = cast[MpUint[32]](y)
|
ty = cast[StUint[32]](y)
|
||||||
tz = tx - ty
|
tz = tx - ty
|
||||||
|
|
||||||
check(cast[uint](tz) == x-y)
|
check(cast[uint](tz) == x-y)
|
||||||
@ -146,13 +146,13 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
when sizeof(int) == 8:
|
when sizeof(int) == 8:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[64]](x)
|
tx = cast[StUint[64]](x)
|
||||||
ty = cast[MpUint[64]](y)
|
ty = cast[StUint[64]](y)
|
||||||
tz = tx * ty
|
tz = tx * ty
|
||||||
else:
|
else:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[32]](x)
|
tx = cast[StUint[32]](x)
|
||||||
ty = cast[MpUint[32]](y)
|
ty = cast[StUint[32]](y)
|
||||||
tz = tx * ty
|
tz = tx * ty
|
||||||
|
|
||||||
check(cast[uint](tz) == x*y)
|
check(cast[uint](tz) == x*y)
|
||||||
@ -161,11 +161,11 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
when sizeof(int) == 8:
|
when sizeof(int) == 8:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[64]](x)
|
tx = cast[StUint[64]](x)
|
||||||
tz = tx shl y
|
tz = tx shl y
|
||||||
else:
|
else:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[32]](x)
|
tx = cast[StUint[32]](x)
|
||||||
tz = tx shl y
|
tz = tx shl y
|
||||||
|
|
||||||
check(cast[uint](tz) == x shl y)
|
check(cast[uint](tz) == x shl y)
|
||||||
@ -174,11 +174,11 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
when sizeof(int) == 8:
|
when sizeof(int) == 8:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[64]](x)
|
tx = cast[StUint[64]](x)
|
||||||
tz = tx shr y
|
tz = tx shr y
|
||||||
else:
|
else:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[32]](x)
|
tx = cast[StUint[32]](x)
|
||||||
tz = tx shr y
|
tz = tx shr y
|
||||||
|
|
||||||
check(cast[uint](tz) == x shr y)
|
check(cast[uint](tz) == x shr y)
|
||||||
@ -187,13 +187,13 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
when sizeof(int) == 8:
|
when sizeof(int) == 8:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[64]](x)
|
tx = cast[StUint[64]](x)
|
||||||
ty = cast[MpUint[64]](y)
|
ty = cast[StUint[64]](y)
|
||||||
tz = tx mod ty
|
tz = tx mod ty
|
||||||
else:
|
else:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[32]](x)
|
tx = cast[StUint[32]](x)
|
||||||
ty = cast[MpUint[32]](y)
|
ty = cast[StUint[32]](y)
|
||||||
tz = tx mod ty
|
tz = tx mod ty
|
||||||
|
|
||||||
check(cast[uint](tz) == x mod y)
|
check(cast[uint](tz) == x mod y)
|
||||||
@ -202,13 +202,13 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
when sizeof(int) == 8:
|
when sizeof(int) == 8:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[64]](x)
|
tx = cast[StUint[64]](x)
|
||||||
ty = cast[MpUint[64]](y)
|
ty = cast[StUint[64]](y)
|
||||||
tz = tx div ty
|
tz = tx div ty
|
||||||
else:
|
else:
|
||||||
let
|
let
|
||||||
tx = cast[MpUint[32]](x)
|
tx = cast[StUint[32]](x)
|
||||||
ty = cast[MpUint[32]](y)
|
ty = cast[StUint[32]](y)
|
||||||
tz = tx div ty
|
tz = tx div ty
|
||||||
|
|
||||||
check(cast[uint](tz) == x div y)
|
check(cast[uint](tz) == x div y)
|
||||||
|
@ -35,8 +35,8 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
ttm_x = cast[ttmath.UInt256](x)
|
ttm_x = cast[ttmath.UInt256](x)
|
||||||
ttm_y = cast[ttmath.UInt256](y)
|
ttm_y = cast[ttmath.UInt256](y)
|
||||||
mp_x = cast[MpUint[256]](x)
|
mp_x = cast[StUint[256]](x)
|
||||||
mp_y = cast[MpUint[256]](y)
|
mp_y = cast[StUint[256]](y)
|
||||||
|
|
||||||
let
|
let
|
||||||
ttm_z = ttm_x or ttm_y
|
ttm_z = ttm_x or ttm_y
|
||||||
@ -60,8 +60,8 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
ttm_x = cast[ttmath.UInt256](x)
|
ttm_x = cast[ttmath.UInt256](x)
|
||||||
ttm_y = cast[ttmath.UInt256](y)
|
ttm_y = cast[ttmath.UInt256](y)
|
||||||
mp_x = cast[MpUint[256]](x)
|
mp_x = cast[StUint[256]](x)
|
||||||
mp_y = cast[MpUint[256]](y)
|
mp_y = cast[StUint[256]](y)
|
||||||
|
|
||||||
let
|
let
|
||||||
ttm_z = ttm_x and ttm_y
|
ttm_z = ttm_x and ttm_y
|
||||||
@ -84,8 +84,8 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
ttm_x = cast[ttmath.UInt256](x)
|
ttm_x = cast[ttmath.UInt256](x)
|
||||||
ttm_y = cast[ttmath.UInt256](y)
|
ttm_y = cast[ttmath.UInt256](y)
|
||||||
mp_x = cast[MpUint[256]](x)
|
mp_x = cast[StUint[256]](x)
|
||||||
mp_y = cast[MpUint[256]](y)
|
mp_y = cast[StUint[256]](y)
|
||||||
|
|
||||||
let
|
let
|
||||||
ttm_z = ttm_x xor ttm_y
|
ttm_z = ttm_x xor ttm_y
|
||||||
@ -104,7 +104,7 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
# y = [y0, y1, y2, y3]
|
# y = [y0, y1, y2, y3]
|
||||||
|
|
||||||
# ttm_x = cast[ttmath.UInt256](x)
|
# ttm_x = cast[ttmath.UInt256](x)
|
||||||
# mp_x = cast[MpUint[256]](x)
|
# mp_x = cast[StUint[256]](x)
|
||||||
|
|
||||||
# let
|
# let
|
||||||
# ttm_z = not ttm_x
|
# ttm_z = not ttm_x
|
||||||
@ -127,8 +127,8 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
ttm_x = cast[ttmath.UInt256](x)
|
ttm_x = cast[ttmath.UInt256](x)
|
||||||
ttm_y = cast[ttmath.UInt256](y)
|
ttm_y = cast[ttmath.UInt256](y)
|
||||||
mp_x = cast[MpUint[256]](x)
|
mp_x = cast[StUint[256]](x)
|
||||||
mp_y = cast[MpUint[256]](y)
|
mp_y = cast[StUint[256]](y)
|
||||||
|
|
||||||
let
|
let
|
||||||
ttm_z = ttm_x < ttm_y
|
ttm_z = ttm_x < ttm_y
|
||||||
@ -152,8 +152,8 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
ttm_x = cast[ttmath.UInt256](x)
|
ttm_x = cast[ttmath.UInt256](x)
|
||||||
ttm_y = cast[ttmath.UInt256](y)
|
ttm_y = cast[ttmath.UInt256](y)
|
||||||
mp_x = cast[MpUint[256]](x)
|
mp_x = cast[StUint[256]](x)
|
||||||
mp_y = cast[MpUint[256]](y)
|
mp_y = cast[StUint[256]](y)
|
||||||
|
|
||||||
let
|
let
|
||||||
ttm_z = ttm_x <= ttm_y
|
ttm_z = ttm_x <= ttm_y
|
||||||
@ -176,8 +176,8 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
ttm_x = cast[ttmath.UInt256](x)
|
ttm_x = cast[ttmath.UInt256](x)
|
||||||
ttm_y = cast[ttmath.UInt256](y)
|
ttm_y = cast[ttmath.UInt256](y)
|
||||||
mp_x = cast[MpUint[256]](x)
|
mp_x = cast[StUint[256]](x)
|
||||||
mp_y = cast[MpUint[256]](y)
|
mp_y = cast[StUint[256]](y)
|
||||||
|
|
||||||
let
|
let
|
||||||
ttm_z = ttm_x + ttm_y
|
ttm_z = ttm_x + ttm_y
|
||||||
@ -200,8 +200,8 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
ttm_x = cast[ttmath.UInt256](x)
|
ttm_x = cast[ttmath.UInt256](x)
|
||||||
ttm_y = cast[ttmath.UInt256](y)
|
ttm_y = cast[ttmath.UInt256](y)
|
||||||
mp_x = cast[MpUint[256]](x)
|
mp_x = cast[StUint[256]](x)
|
||||||
mp_y = cast[MpUint[256]](y)
|
mp_y = cast[StUint[256]](y)
|
||||||
|
|
||||||
let
|
let
|
||||||
ttm_z = ttm_x - ttm_y
|
ttm_z = ttm_x - ttm_y
|
||||||
@ -224,8 +224,8 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
ttm_x = cast[ttmath.UInt256](x)
|
ttm_x = cast[ttmath.UInt256](x)
|
||||||
ttm_y = cast[ttmath.UInt256](y)
|
ttm_y = cast[ttmath.UInt256](y)
|
||||||
mp_x = cast[MpUint[256]](x)
|
mp_x = cast[StUint[256]](x)
|
||||||
mp_y = cast[MpUint[256]](y)
|
mp_y = cast[StUint[256]](y)
|
||||||
|
|
||||||
let
|
let
|
||||||
ttm_z = ttm_x * ttm_y
|
ttm_z = ttm_x * ttm_y
|
||||||
@ -243,7 +243,7 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
x = [x0, x1, x2, x3]
|
x = [x0, x1, x2, x3]
|
||||||
|
|
||||||
ttm_x = cast[ttmath.UInt256](x)
|
ttm_x = cast[ttmath.UInt256](x)
|
||||||
mp_x = cast[MpUint[256]](x)
|
mp_x = cast[StUint[256]](x)
|
||||||
|
|
||||||
let
|
let
|
||||||
ttm_z = ttm_x shl y
|
ttm_z = ttm_x shl y
|
||||||
@ -261,7 +261,7 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
x = [x0, x1, x2, x3]
|
x = [x0, x1, x2, x3]
|
||||||
|
|
||||||
ttm_x = cast[ttmath.UInt256](x)
|
ttm_x = cast[ttmath.UInt256](x)
|
||||||
mp_x = cast[MpUint[256]](x)
|
mp_x = cast[StUint[256]](x)
|
||||||
|
|
||||||
let
|
let
|
||||||
ttm_z = ttm_x shr y
|
ttm_z = ttm_x shr y
|
||||||
@ -284,8 +284,8 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
ttm_x = cast[ttmath.UInt256](x)
|
ttm_x = cast[ttmath.UInt256](x)
|
||||||
ttm_y = cast[ttmath.UInt256](y)
|
ttm_y = cast[ttmath.UInt256](y)
|
||||||
mp_x = cast[MpUint[256]](x)
|
mp_x = cast[StUint[256]](x)
|
||||||
mp_y = cast[MpUint[256]](y)
|
mp_y = cast[StUint[256]](y)
|
||||||
|
|
||||||
let
|
let
|
||||||
ttm_z = ttm_x mod ttm_y
|
ttm_z = ttm_x mod ttm_y
|
||||||
@ -306,8 +306,8 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit /
|
|||||||
|
|
||||||
ttm_x = cast[ttmath.UInt256](x)
|
ttm_x = cast[ttmath.UInt256](x)
|
||||||
ttm_y = cast[ttmath.UInt256](y)
|
ttm_y = cast[ttmath.UInt256](y)
|
||||||
mp_x = cast[MpUint[256]](x)
|
mp_x = cast[StUint[256]](x)
|
||||||
mp_y = cast[MpUint[256]](y)
|
mp_y = cast[StUint[256]](y)
|
||||||
|
|
||||||
let
|
let
|
||||||
ttm_z = ttm_x div ttm_y
|
ttm_z = ttm_x div ttm_y
|
||||||
|
@ -12,8 +12,8 @@ import ../src/mpint, unittest
|
|||||||
suite "Testing addition implementation":
|
suite "Testing addition implementation":
|
||||||
test "In-place addition gives expected result":
|
test "In-place addition gives expected result":
|
||||||
|
|
||||||
var a = 20182018.initMpUint(64)
|
var a = 20182018.u(64)
|
||||||
let b = 20172017.initMpUint(64)
|
let b = 20172017.u(64)
|
||||||
|
|
||||||
a += b
|
a += b
|
||||||
|
|
||||||
@ -21,23 +21,23 @@ suite "Testing addition implementation":
|
|||||||
|
|
||||||
test "Addition gives expected result":
|
test "Addition gives expected result":
|
||||||
|
|
||||||
let a = 20182018.initMpUint(64)
|
let a = 20182018.u(64)
|
||||||
let b = 20172017.initMpUint(64)
|
let b = 20172017.u(64)
|
||||||
|
|
||||||
check: cast[uint64](a+b) == 20182018'u64 + 20172017'u64
|
check: cast[uint64](a+b) == 20182018'u64 + 20172017'u64
|
||||||
|
|
||||||
test "When the low half overflows, it is properly carried":
|
test "When the low half overflows, it is properly carried":
|
||||||
# uint8 (low half) overflow at 255
|
# uint8 (low half) overflow at 255
|
||||||
let a = 100'u16.initMpUint(16)
|
let a = 100'u16.u(16)
|
||||||
let b = 100'u16.initMpUint(16)
|
let b = 100'u16.u(16)
|
||||||
|
|
||||||
check: cast[uint16](a+b) == 200
|
check: cast[uint16](a+b) == 200
|
||||||
|
|
||||||
test "Full overflow is handled like native unsigned types":
|
test "Full overflow is handled like native unsigned types":
|
||||||
# uint16 overflows after 65535
|
# uint16 overflows after 65535
|
||||||
let a = 100'u16.initMpUint(16)
|
let a = 100'u16.u(16)
|
||||||
var z = 0'u16.initMpUint(16)
|
var z = 0'u16.u(16)
|
||||||
let o = 36'u16.initMpUint(16)
|
let o = 36'u16.u(16)
|
||||||
|
|
||||||
for _ in 0 ..< 655:
|
for _ in 0 ..< 655:
|
||||||
z += a
|
z += a
|
||||||
@ -54,8 +54,8 @@ suite "Testing addition implementation":
|
|||||||
suite "Testing substraction implementation":
|
suite "Testing substraction implementation":
|
||||||
test "In-place substraction gives expected result":
|
test "In-place substraction gives expected result":
|
||||||
|
|
||||||
var a = 20182018.initMpUint(64)
|
var a = 20182018.u(64)
|
||||||
let b = 20172017.initMpUint(64)
|
let b = 20172017.u(64)
|
||||||
|
|
||||||
a -= b
|
a -= b
|
||||||
|
|
||||||
@ -63,14 +63,14 @@ suite "Testing substraction implementation":
|
|||||||
|
|
||||||
test "Substraction gives expected result":
|
test "Substraction gives expected result":
|
||||||
|
|
||||||
let a = 20182018.initMpUint(64)
|
let a = 20182018.u(64)
|
||||||
let b = 20172017.initMpUint(64)
|
let b = 20172017.u(64)
|
||||||
|
|
||||||
check: cast[uint64](a-b) == 20182018'u64 - 20172017'u64
|
check: cast[uint64](a-b) == 20182018'u64 - 20172017'u64
|
||||||
|
|
||||||
test "Full overflow is handled like native unsigned types":
|
test "Full overflow is handled like native unsigned types":
|
||||||
# uint16 overflows after 65535
|
# uint16 overflows after 65535
|
||||||
let a = 100'u16.initMpUint(16)
|
let a = 100'u16.u(16)
|
||||||
let b = 101'u16.initMpUint(16)
|
let b = 101'u16.u(16)
|
||||||
|
|
||||||
check: cast[uint16](a-b) == high(uint16)
|
check: cast[uint16](a-b) == high(uint16)
|
||||||
|
@ -10,14 +10,14 @@
|
|||||||
import ../src/mpint, unittest
|
import ../src/mpint, unittest
|
||||||
|
|
||||||
suite "Testing bitwise operations":
|
suite "Testing bitwise operations":
|
||||||
let a = 100'i16.initMpUint(16)
|
let a = 100'i16.u(16)
|
||||||
|
|
||||||
let b = a * a
|
let b = a * a
|
||||||
let z = 10000'u16
|
let z = 10000'u16
|
||||||
assert cast[uint16](b) == z, "Test cannot proceed, something is wrong with the multiplication implementation"
|
assert cast[uint16](b) == z, "Test cannot proceed, something is wrong with the multiplication implementation"
|
||||||
|
|
||||||
|
|
||||||
let u = 10000.initMpUint(64)
|
let u = 10000.u(64)
|
||||||
let v = 10000'u64
|
let v = 10000'u64
|
||||||
let clz = 30
|
let clz = 30
|
||||||
|
|
||||||
@ -35,11 +35,11 @@ suite "Testing bitwise operations":
|
|||||||
check: cast[uint16](b) == z # Sanity check
|
check: cast[uint16](b) == z # Sanity check
|
||||||
check: cast[uint16](b shl 8) == z shl 8
|
check: cast[uint16](b shl 8) == z shl 8
|
||||||
|
|
||||||
block: # Testing shl for nested MpUintImpl
|
block: # Testing shl for nested UintImpl
|
||||||
let p2_64 = MpUintImpl[uint64](hi:1, lo:0)
|
let p2_64 = UintImpl[uint64](hi:1, lo:0)
|
||||||
let p = 1.initMpUint(128) shl 64
|
let p = 1.u(128) shl 64
|
||||||
|
|
||||||
check: p == cast[MpUint[128]](p2_64)
|
check: p == cast[StUint[128]](p2_64)
|
||||||
|
|
||||||
test "Shift right - by less than half the size of the integer":
|
test "Shift right - by less than half the size of the integer":
|
||||||
check: cast[uint16](b) == z # Sanity check
|
check: cast[uint16](b) == z # Sanity check
|
||||||
|
@ -11,19 +11,19 @@ import ../src/mpint, unittest
|
|||||||
|
|
||||||
suite "Testing comparison operators":
|
suite "Testing comparison operators":
|
||||||
let
|
let
|
||||||
a = 10'i16.initMpUint(16)
|
a = 10'i16.u(16)
|
||||||
b = 15'i16.initMpUint(16)
|
b = 15'i16.u(16)
|
||||||
c = 150'u16
|
c = 150'u16
|
||||||
d = 4.initMpUint(128) shl 64
|
d = 4.u(128) shl 64
|
||||||
e = 4.initMpUint(128)
|
e = 4.u(128)
|
||||||
f = 4.initMpUint(128) shl 65
|
f = 4.u(128) shl 65
|
||||||
|
|
||||||
test "< operator":
|
test "< operator":
|
||||||
check:
|
check:
|
||||||
a < b
|
a < b
|
||||||
not (a + b < b)
|
not (a + b < b)
|
||||||
not (a + a + a < b + b)
|
not (a + a + a < b + b)
|
||||||
not (a * b < cast[MpUint[16]](c))
|
not (a * b < cast[StUint[16]](c))
|
||||||
e < d
|
e < d
|
||||||
d < f
|
d < f
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ suite "Testing comparison operators":
|
|||||||
a <= b
|
a <= b
|
||||||
not (a + b <= b)
|
not (a + b <= b)
|
||||||
a + a + a <= b + b
|
a + a + a <= b + b
|
||||||
a * b <= cast[MpUint[16]](c)
|
a * b <= cast[StUint[16]](c)
|
||||||
e <= d
|
e <= d
|
||||||
d <= f
|
d <= f
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ suite "Testing comparison operators":
|
|||||||
b > a
|
b > a
|
||||||
not (b > a + b)
|
not (b > a + b)
|
||||||
not (b + b > a + a + a)
|
not (b + b > a + a + a)
|
||||||
not (cast[Mpuint[16]](c) > a * b)
|
not (cast[StUint[16]](c) > a * b)
|
||||||
d > e
|
d > e
|
||||||
f > d
|
f > d
|
||||||
|
|
||||||
@ -50,6 +50,6 @@ suite "Testing comparison operators":
|
|||||||
b >= a
|
b >= a
|
||||||
not (b >= a + b)
|
not (b >= a + b)
|
||||||
b + b >= a + a + a
|
b + b >= a + a + a
|
||||||
cast[MpUint[16]](c) >= a * b
|
cast[StUint[16]](c) >= a * b
|
||||||
d >= e
|
d >= e
|
||||||
f >= d
|
f >= d
|
||||||
|
@ -11,7 +11,7 @@ import ../src/mpint, unittest
|
|||||||
|
|
||||||
suite "Testing byte representation":
|
suite "Testing byte representation":
|
||||||
test "Byte representation conforms to the platform endianness":
|
test "Byte representation conforms to the platform endianness":
|
||||||
let a = 20182018.initMpUint(64)
|
let a = 20182018.u(64)
|
||||||
let b = 20182018'u64
|
let b = 20182018'u64
|
||||||
|
|
||||||
type AsBytes = array[8, byte]
|
type AsBytes = array[8, byte]
|
||||||
|
@ -12,23 +12,23 @@ import ../src/mpint, unittest
|
|||||||
suite "Testing multiplication implementation":
|
suite "Testing multiplication implementation":
|
||||||
test "Multiplication with result fitting in low half":
|
test "Multiplication with result fitting in low half":
|
||||||
|
|
||||||
let a = 10000.initMpUint(64)
|
let a = 10000.u(64)
|
||||||
let b = 10000.initMpUint(64)
|
let b = 10000.u(64)
|
||||||
|
|
||||||
check: cast[uint64](a*b) == 100_000_000'u64 # need 27-bits
|
check: cast[uint64](a*b) == 100_000_000'u64 # need 27-bits
|
||||||
|
|
||||||
test "Multiplication with result overflowing low half":
|
test "Multiplication with result overflowing low half":
|
||||||
|
|
||||||
let a = 1_000_000.initMpUint(64)
|
let a = 1_000_000.u(64)
|
||||||
let b = 1_000_000.initMpUint(64)
|
let b = 1_000_000.u(64)
|
||||||
|
|
||||||
check: cast[uint64](a*b) == 1_000_000_000_000'u64 # need 40 bits
|
check: cast[uint64](a*b) == 1_000_000_000_000'u64 # need 40 bits
|
||||||
|
|
||||||
test "Full overflow is handled like native unsigned types":
|
test "Full overflow is handled like native unsigned types":
|
||||||
|
|
||||||
let a = 1_000_000_000.initMpUint(64)
|
let a = 1_000_000_000.u(64)
|
||||||
let b = 1_000_000_000.initMpUint(64)
|
let b = 1_000_000_000.u(64)
|
||||||
let c = 1_000.initMpUint(64)
|
let c = 1_000.u(64)
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
@ -36,21 +36,21 @@ suite "Testing multiplication implementation":
|
|||||||
suite "Testing division and modulo implementation":
|
suite "Testing division and modulo implementation":
|
||||||
test "Divmod(100, 13) returns the correct result":
|
test "Divmod(100, 13) returns the correct result":
|
||||||
|
|
||||||
let a = 100.initMpUint(64)
|
let a = 100.u(64)
|
||||||
let b = 13.initMpUint(64)
|
let b = 13.u(64)
|
||||||
let qr = divmod(a, b)
|
let qr = divmod(a, b)
|
||||||
|
|
||||||
check: cast[uint64](qr.quot) == 7'u64
|
check: cast[uint64](qr.quot) == 7'u64
|
||||||
check: cast[uint64](qr.rem) == 9'u64
|
check: cast[uint64](qr.rem) == 9'u64
|
||||||
|
|
||||||
test "Divmod(2^64, 3) returns the correct result":
|
test "Divmod(2^64, 3) returns the correct result":
|
||||||
let a = 1.initMpUint(128) shl 64
|
let a = 1.u(128) shl 64
|
||||||
let b = 3.initMpUint(128)
|
let b = 3.u(128)
|
||||||
|
|
||||||
let qr = divmod(a, b)
|
let qr = divmod(a, b)
|
||||||
|
|
||||||
let q = cast[MpUintImpl[uint64]](qr.quot)
|
let q = cast[UintImpl[uint64]](qr.quot)
|
||||||
let r = cast[MpUintImpl[uint64]](qr.rem)
|
let r = cast[UintImpl[uint64]](qr.rem)
|
||||||
|
|
||||||
check: q.lo == 6148914691236517205'u64
|
check: q.lo == 6148914691236517205'u64
|
||||||
check: q.hi == 0'u64
|
check: q.hi == 0'u64
|
||||||
|
Loading…
x
Reference in New Issue
Block a user