Merge pull request #27 from status-im/signed-integers

Add Signed integers
This commit is contained in:
Mamy Ratsimbazafy 2018-04-26 13:06:51 +02:00 committed by GitHub
commit f520f7817b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 1006 additions and 160 deletions

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -11,25 +11,13 @@
import
strutils,
../private/[uint_type, getSize]
../private/datatypes
func tohexBE*[T: uint8 or uint16 or uint32 or uint64](x: T): string =
func tohexBE*(x: UintImpl or IntImpl or SomeInteger): string =
## Stringify an uint to hex, Most significant byte on the left
## i.e. a 1.uint64 will be 00000001
let bytes = cast[ptr array[T.sizeof, byte]](x.unsafeaddr)
result = ""
when system.cpuEndian == littleEndian:
for i in countdown(T.sizeof - 1, 0):
result.add toHex(bytes[i])
else:
for i in 0 ..< T.sizeof:
result.add toHex(bytes[i])
func tohexBE*(x: UintImpl): string =
## Stringify an uint to hex, Most significant byte on the left
## i.e. a (2.uint128)^64 + 1 will be 0000000100000001
## i.e.
## - 1.uint64 will be 00000001
## - (2.uint128)^64 + 1 will be 0000000100000001
const size = getSize(x) div 8
@ -42,3 +30,6 @@ func tohexBE*(x: UintImpl): string =
else:
for i in 0 ..< size:
result.add toHex(bytes[i])
func tohexBE*(x: Stint or StUint): string {.inline.}=
x.data.tohexBE

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -7,11 +7,10 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import typetraits
import ./private/uint_type
import typetraits
import
./private/datatypes,
./private/int_negabs,
typetraits
func stuint*[T: SomeInteger](n: T, bits: static[int]): StUint[bits] {.inline.}=
assert n >= 0.T
@ -33,3 +32,32 @@ func stuint*[T: SomeInteger](n: T, bits: static[int]): StUint[bits] {.inline.}=
r_ptr[r_ptr[].len - 1] = n
else:
result.data = (type result.data)(n)
func stint*[T: SomeInteger](n: T, bits: static[int]): StInt[bits] {.inline.}=
when result.data is IntImpl:
when getSize(n) > bits:
# To avoid a costly runtime check, we refuse storing into StUint types smaller
# than the input type.
raise newException(ValueError, "Input " & $n & " (" & $T &
") cannot be stored in a multi-precision " &
$bits & "-bit integer." &
"\nUse a smaller input type instead. This is a compile-time check" &
" to avoid a costly run-time bit_length check at each StUint initialization.")
else:
let r_ptr = cast[ptr array[bits div (sizeof(T) * 8), T]](result.addr)
when system.cpuEndian == littleEndian:
# "Least significant byte are at the beginning"
if n < 0:
r_ptr[0] = -n
result = -result
else:
r_ptr[0] = n
else:
if n < 0:
r_ptr[r_ptr[].len - 1] = -n
result = -result
else:
r_ptr[r_ptr[].len - 1] = n
else:
result.data = (type result.data)(n)

82
src/int_public.nim Normal file
View File

@ -0,0 +1,82 @@
# Stint
# 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.
import ./private/datatypes, macros
export StInt, IntImpl, intImpl # TODO remove the need to export intImpl and this macro
type
Int128* = Stint[128]
Int256* = Stint[256]
template make_conv(conv_name: untyped, size: int): untyped =
func `convname`*(n: SomeInteger): Stint[size] {.inline, noInit.}=
n.stint(size)
make_conv(i128, 128)
make_conv(i256, 256)
template make_unary(op, ResultTy): untyped =
func `op`*(x: Stint): ResultTy {.noInit, inline.} =
when ResultTy is Stint:
result.data = op(x.data)
else:
op(x.data)
export op
template make_binary(op, ResultTy): untyped =
func `op`*(x, y: Stint): ResultTy {.noInit, inline.} =
when ResultTy is Stint:
result.data = op(x.data, y.data)
else:
op(x.data, y.data)
export `op`
template make_binary_inplace(op): untyped =
func `op`*(x: var Stint, y: Stint) {.inline.} =
op(x.data, y.data)
export op
import ./private/int_addsub
make_binary(`+`, Stint)
make_binary_inplace(`+=`)
make_binary(`-`, Stint)
make_binary_inplace(`-=`)
import ./private/int_negabs
make_unary(`-`, Stint)
make_unary(abs, Stint)
import ./private/int_mul
make_binary(`*`, Stint)
import ./private/int_div
make_binary(`div`, Stint)
make_binary(`mod`, Stint)
func divmod*(x, y: Stint): tuple[quot, rem: Stint] {.noInit, inline.} =
(result.quot.data, result.rem.data) = divmod(x.data, y.data)
import ./private/int_comparison
make_binary(`<`, bool)
make_binary(`<=`, bool)
make_binary(`==`, bool)
func isZero*(x: Stint): bool {.inline.} = isZero x.data
import ./private/int_bitwise_ops
make_unary(`not`, Stint)
make_binary(`or`, Stint)
make_binary(`and`, Stint)
make_binary(`xor`, Stint)
# proc `shr`*(x: Stint, y: SomeInteger): Stint {.noInit, inline, noSideEffect.} =
# result.data = x.data shr y
# proc `shl`*(x: Stint, y: SomeInteger): Stint {.noInit, inline, noSideEffect.} =
# result.data = x.data shl y

View File

@ -0,0 +1,149 @@
# Stint
# 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.
import ./datatypes, macros, as_words
proc optimInt*(x: NimNode): NimNode =
let size = getSize(x)
if size > 64:
result = quote do:
# We represent as unsigned int. Signedness will be managed at a higher level.
array[`size` div 64, uint64]
elif size == 64:
result = quote do:
int64
elif size == 32:
result = quote do:
int32
elif size == 16:
result = quote do:
int16
elif size == 8:
result = quote do:
int8
else:
error "Unreachable path reached"
proc isInt*(x: NimNode): static[bool] =
if eqIdent(x, "int64"): true
elif eqIdent(x, "int32"): true
elif eqIdent(x, "int16"): true
elif eqIdent(x, "int8"): true
else: false
macro most_significant_word*(x: IntImpl): untyped =
let optim_type = optimInt(x)
if optim_type.isInt:
result = quote do:
cast[`optim_type`](`x`)
else:
when system.cpuEndian == littleEndian:
let size = getSize(x)
let msw_pos = size - 1
else:
let msw_pos = 0
result = quote do:
cast[int](cast[`optim_type`](`x`)[`msw_pos`])
macro most_significant_word_mut*(x: var IntImpl): untyped =
let optim_type = optimInt(x)
if optim_type.isInt:
result = quote do:
cast[var `optim_type`](`x`.addr)
else:
when system.cpuEndian == littleEndian:
let size = getSize(x)
let msw_pos = size - 1
else:
let msw_pos = 0
result = quote do:
(cast[ptr `optim_type`](`x`.unsafeAddr)[`msw_pos`])[]
macro asSignedWordsZip*[T](
x, y: IntImpl[T],
loopBody: untyped): untyped =
## Iterates over x and y, as an array of words.
## Input:
## - x, y: The multiprecision ints
## - loopBody: the operation you want to do.
## For the most significant word,
## the operation will be sign aware.
## for the next words it will ignore sign.
## Iteration is always done from most significant to least significant
let
optim_type = optimInt(x)
idx = ident("idx_asSignedWordsRawZip")
var
first_x, first_y: NimNode
next_x, next_y: NimNode
to_replace = nnkBracket.newTree
replacing = nnkBracket.newTree
to_replace.add x
to_replace.add y
# We directly cast the first x and y if the result fits in a word
# Otherwise we special case the most significant word
if optim_type.isInt:
first_x = quote do:
cast[`optim_type`](`x`)
first_y = quote do:
cast[`optim_type`](`y`)
else:
first_x = getAST(most_significant_word(x))
first_y = getAST(most_significant_word(y))
replacing.add first_x
replacing.add first_y
let firstReplacedAST = replaceNodes(loopBody, replacing, to_replace)
# Reset the replacement array
replacing = nnkBracket.newTree
# Setup the loop variables
next_x = ident("x_asSignedWordsRawZip")
next_y = ident("y_asSignedWordsRawZip")
# We replace the inner loop with the next_x[idx]
replacing.add quote do:
`next_x`[`idx`]
replacing.add quote do:
`next_y`[`idx`]
let nextReplacedAST = replaceNodes(loopBody, replacing, to_replace)
# Result:
result = newStmtList()
result.add firstReplacedAST
if not optim_type.isInt:
# if we have multiple iterations to do
if system.cpuEndian == bigEndian:
result = quote do:
{.pragma: restrict, codegenDecl: "$# __restrict__ $#".}
let
`next_x`{.restrict.} = cast[ptr `optim_type`](`x`.unsafeaddr)
`next_y`{.restrict.} = cast[ptr `optim_type`](`y`.unsafeaddr)
for `idx` in 1 ..< `next_x`[].len:
# We start from the second word
`nextReplacedAST`
else:
# Little-Endian, iteration in reverse
result = quote do:
{.pragma: restrict, codegenDecl: "$# __restrict__ $#".}
let
`next_x`{.restrict.} = cast[ptr `optim_type`](`x`.unsafeaddr)
`next_y`{.restrict.} = cast[ptr `optim_type`](`y`.unsafeaddr)
for `idx` in countdown(`next_x`[].len - 2, 0):
# We stop stop at the second to last word
`nextReplacedAST`

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -7,9 +7,9 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ./uint_type, macros
import ./datatypes, macros
proc optim(x: NimNode): NimNode =
proc optimUint(x: NimNode): NimNode =
let size = getSize(x)
if size > 64:
@ -30,7 +30,14 @@ proc optim(x: NimNode): NimNode =
else:
error "Unreachable path reached"
proc replaceNodes(ast: NimNode, replacing: NimNode, to_replace: NimNode): NimNode =
proc isUint(x: NimNode): static[bool] =
if eqIdent(x, "uint64"): true
elif eqIdent(x, "uint32"): true
elif eqIdent(x, "uint16"): true
elif eqIdent(x, "uint8"): true
else: false
proc replaceNodes*(ast: NimNode, replacing: NimNode, to_replace: NimNode): NimNode =
# Args:
# - The full syntax tree
# - an array of replacement value
@ -53,21 +60,16 @@ proc replaceNodes(ast: NimNode, replacing: NimNode, to_replace: NimNode): NimNod
return rTree
result = inspect(ast)
proc isUint(x: NimNode): static[bool] =
if eqIdent(x, "uint64"): true
elif eqIdent(x, "uint32"): true
elif eqIdent(x, "uint16"): true
elif eqIdent(x, "uint8"): true
else: false
macro asWords*[T](n: UintImpl[T], ignoreEndianness: static[bool], loopBody: untyped): untyped =
macro asWords*(n: UintImpl or IntImpl, ignoreEndianness: static[bool], loopBody: untyped): untyped =
## Iterates over n, as an array of words.
## Input:
## - n: The Multiprecision int
## - body: the operation you want to do on each word of n
## If iteration is needed, it is done from low to high, not taking endianness in account
## - If endianness should be taken into account for iteratio order.
## If yes, iteration is done from most significant word to least significant.
## Otherwise it is done in memory layout order.
## - loopBody: the operation you want to do on each word of n
let
optim_type = optim(n)
optim_type = optimUint(n)
var
inner_n: NimNode
to_replace = nnkBracket.newTree
@ -96,13 +98,16 @@ macro asWords*[T](n: UintImpl[T], ignoreEndianness: static[bool], loopBody: unty
else:
assert false, "Not implemented"
macro asWordsZip*[T](x, y: UintImpl[T], ignoreEndianness: static[bool], loopBody: untyped): untyped =
macro asWordsZip*(x, y: UintImpl or IntImpl, ignoreEndianness: static[bool], loopBody: untyped): untyped =
## Iterates over x and y, as an array of words.
## Input:
## - x, y: The multiprecision ints
## If iteration is needed, it is done from low to high, not taking endianness in account
## - If endianness should be taken into account for iteratio order.
## If yes, iteration is done from most significant word to least significant.
## Otherwise it is done in memory layout order.
## - loopBody: the operation you want to do on each word of n
let
optim_type = optim(x)
optim_type = optimUint(x)
idx = ident("idx_asWordsRawZip")
var
inner_x, inner_y: NimNode
@ -155,15 +160,19 @@ macro asWordsZip*[T](x, y: UintImpl[T], ignoreEndianness: static[bool], loopBody
for `idx` in countdown(`inner_x`[].len - 1, 0):
`replacedAST`
macro m_asWordsZip*[T](m: var UintImpl[T], x: UintImpl[T], ignoreEndianness: static[bool], loopBody: untyped): untyped =
macro m_asWordsZip*[T: UintImpl or IntImpl](m: var T, x: T,
ignoreEndianness: static[bool], loopBody: untyped): untyped =
## Iterates over a mutable int m and x as an array of words.
## returning a !! Pointer !! of the proper type to m.
## Input:
## - m: A mutable array
## - x: The multiprecision ints
## Iteration is done from low to high, not taking endianness in account
## - If endianness should be taken into account for iteratio order.
## If yes, iteration is done from most significant word to least significant.
## Otherwise it is done in memory layout order.
## - loopBody: the operation you want to do on each word of n
let
optim_type = optim(x)
optim_type = optimUint(x)
idx = ident("idx_asWordsRawZip")
var
inner_m, inner_x: NimNode
@ -217,15 +226,19 @@ macro m_asWordsZip*[T](m: var UintImpl[T], x: UintImpl[T], ignoreEndianness: sta
`replacedAST`
macro m_asWordsZip*[T](m: var UintImpl[T], x, y: UintImpl[T], ignoreEndianness: static[bool], loopBody: untyped): untyped =
macro m_asWordsZip*[T: UintImpl or IntImpl](m: var T, x, y: T,
ignoreEndianness: static[bool], loopBody: untyped): untyped =
## Iterates over a mutable int m and x as an array of words.
## returning a !! Pointer !! of the proper type to m.
## Input:
## - m: A mutable array
## - x: The multiprecision ints
## Iteration is done from low to high, not taking endianness in account
## - If endianness should be taken into account for iteratio order.
## If yes, iteration is done from most significant word to least significant.
## Otherwise it is done in memory layout order.
## - loopBody: the operation you want to do on each word of n
let
optim_type = optim(x)
optim_type = optimUint(x)
idx = ident("idx_asWordsRawZip")
var
inner_m, inner_x, inner_y: NimNode

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -7,7 +7,7 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ./uint_type, stdlib_bitops
import ./datatypes, stdlib_bitops, as_signed_words
export stdlib_bitops
# We reuse bitops from Nim standard lib, and expand it for multi-precision int.
@ -24,3 +24,25 @@ func countLeadingZeroBits*(n: UintImpl): int {.inline.} =
result = if hi_clz == maxHalfRepr:
n.lo.countLeadingZeroBits + maxHalfRepr
else: hi_clz
func msb*[T: SomeInteger](n: T): T {.inline.}=
## Returns the most significant bit of an integer.
when T is int64 or (T is int and sizeof(int) == 8):
type UInt = uint64
elif T is int32 or (T is int and sizeof(int) == 4):
type Uint = uint32
elif T is int16:
type Uint = uint16
elif T is int8:
type Uint = uint8
else:
type Uint = T
const msb_pos = sizeof(T) * 8 - 1
result = T(cast[Uint](n) shr msb_pos)
func msb*(n: IntImpl): auto {.inline.}=
## Returns the most significant bit of an arbitrary precision integer.
result = msb most_significant_word(n)

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -7,27 +7,7 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ./uint_type,
macros, typetraits
func initUintImpl*[InType, OutType](x: InType, _: typedesc[OutType]): OutType {.inline.} =
const
size_in = getSize(x)
size_out = getSize(result)
static:
assert size_out >= size_in, "The result type size (" & $size_out &
" for " & $OutType.name &
") should be equal or bigger than the input type size (" & $size_in &
" for " & $InType.name & ")."
when OutType is SomeUnsignedInt:
result = x.OutType
elif size_in == size_out:
result = cast[type result](x)
else:
result.lo = initUintImpl(x, type result.lo)
import ./datatypes
func toSubtype*[T: SomeInteger](b: bool, _: typedesc[T]): T {.inline.}=
b.T
@ -36,21 +16,8 @@ func toSubtype*[T: UintImpl](b: bool, _: typedesc[T]): T {.inline.}=
type SubTy = type result.lo
result.lo = toSubtype(b, SubTy)
func zero*[T: BaseUint](_: typedesc[T]): T {.inline.}=
discard
func one*[T: BaseUint](_: typedesc[T]): T {.inline.}=
when T is SomeUnsignedInt:
result = T(1)
else:
let r_ptr = cast[ptr array[getSize(result) div 8, byte]](result.addr)
when system.cpuEndian == bigEndian:
r_ptr[0] = 1
else:
r_ptr[r_ptr[].len - 1] = 1
func toUint*(n: UintImpl): auto {.inline.}=
## Casts a multiprecision integer to an uint of the same size
## Casts an unsigned integer to an uint of the same size
# TODO: uint128 support
when n.sizeof > 8:
@ -78,19 +45,3 @@ func asDoubleUint*(n: BaseUint): auto {.inline.} =
)
n.toUint.Double
func toUintImpl*(n: uint16|uint32|uint64): auto {.inline.} =
## Cast an integer to the corresponding size UintImpl
# Sometimes direct casting doesn't work and we must cast through a pointer
when n is uint64:
return (cast[ptr [UintImpl[uint32]]](unsafeAddr n))[]
elif n is uint32:
return (cast[ptr [UintImpl[uint16]]](unsafeAddr n))[]
elif n is uint16:
return (cast[ptr [UintImpl[uint8]]](unsafeAddr n))[]
func toUintImpl*(n: UintImpl): UintImpl {.inline.} =
## No op
n

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -12,16 +12,16 @@
import macros
# The macro getUintImpl must be exported
# The macro uintImpl must be exported
when defined(mpint_test):
macro getUintImpl*(bits: static[int]): untyped =
macro uintImpl*(bits: static[int]): untyped =
# 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 >= 16, "The number of bits in a should be greater or equal to 16"
if bits >= 128:
let inner = getAST(getUintImpl(bits div 2))
let inner = getAST(uintImpl(bits div 2))
result = newTree(nnkBracketExpr, ident("UintImpl"), inner)
elif bits == 64:
result = newTree(nnkBracketExpr, ident("UintImpl"), ident("uint32"))
@ -31,14 +31,34 @@ when defined(mpint_test):
result = newTree(nnkBracketExpr, ident("UintImpl"), ident("uint8"))
else:
error "Fatal: unreachable"
macro intImpl*(bits: static[int]): untyped =
# Test version, StInt[64] = 2 uint32. Test the logic of the library
# Note that ints are implemented in terms of unsigned ints
# Signed operatiosn will be built on top of that.
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"
if bits >= 128:
let inner = getAST(uintImpl(bits div 2)) # IntImpl is built on top of UintImpl
result = newTree(nnkBracketExpr, ident("IntImpl"), inner)
elif bits == 64:
result = newTree(nnkBracketExpr, ident("IntImpl"), ident("uint32"))
elif bits == 32:
result = newTree(nnkBracketExpr, ident("IntImpl"), ident("uint16"))
elif bits == 16:
result = newTree(nnkBracketExpr, ident("IntImpl"), ident("uint8"))
else:
error "Fatal: unreachable"
else:
macro getUintImpl*(bits: static[int]): untyped =
macro uintImpl*(bits: static[int]): untyped =
# Release version, StUint[64] = uint64.
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"
if bits >= 128:
let inner = getAST(getUintImpl(bits div 2))
let inner = getAST(uintImpl(bits div 2))
result = newTree(nnkBracketExpr, ident("UintImpl"), inner)
elif bits == 64:
result = ident("uint64")
@ -51,6 +71,25 @@ else:
else:
error "Fatal: unreachable"
macro intImpl*(bits: static[int]): untyped =
# Release version, StInt[64] = int64.
# Note that int of size 128+ are implemented in terms of unsigned ints
# Signed operations will be built on top of that.
if bits >= 128:
let inner = getAST(uintImpl(bits div 2))
result = newTree(nnkBracketExpr, ident("IntImpl"), inner)
elif bits == 64:
result = ident("int64")
elif bits == 32:
result = ident("int32")
elif bits == 16:
result = ident("int16")
elif bits == 8:
result = ident("int8")
else:
error "Fatal: unreachable"
proc getSize*(x: NimNode): static[int] =
# Size of doesn't always work at compile-time, pending PR https://github.com/nim-lang/Nim/pull/5664
@ -59,7 +98,8 @@ proc getSize*(x: NimNode): static[int] =
var node = x.getTypeInst
while node.kind == nnkBracketExpr:
assert eqIdent(node[0], "UintImpl")
assert eqIdent(node[0], "UintImpl") or eqIdent(node[0], "IntImpl"), (
"getSize only supports primitive integers, Stint and Stuint")
multiplier *= 2
node = node[1]
@ -84,8 +124,6 @@ macro getSize*(x: typed): untyped =
type
# ### Private ### #
# If this is not in the same type section
# the compiler has trouble
BaseUint* = UintImpl or SomeUnsignedInt
UintImpl*[Baseuint] = object
@ -93,8 +131,18 @@ type
lo*, hi*: BaseUint
else:
hi*, lo*: BaseUint
IntImpl*[Baseuint] = object
# Ints are implemented in terms of uints
when system.cpuEndian == littleEndian:
lo*, hi*: BaseUint
else:
hi*, lo*: BaseUint
# ### Private ### #
StUint*[bits: static[int]] = object
data*: getUintImpl(bits)
# wrapped in object to avoid recursive calls
data*: uintImpl(bits)
StInt*[bits: static[int]] = object
data*: intImpl(bits)

View File

@ -0,0 +1,42 @@
# Stint
# 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.
import ./datatypes, typetraits
func initUintImpl*[InType, OutType](x: InType, _: typedesc[OutType]): OutType {.inline.} =
const
size_in = getSize(x)
size_out = getSize(result)
static:
assert size_out >= size_in, "The result type size (" & $size_out &
" for " & $OutType.name &
") should be equal or bigger than the input type size (" & $size_in &
" for " & $InType.name & ")."
when OutType is SomeUnsignedInt:
result = x.OutType
elif size_in == size_out:
result = cast[type result](x)
else:
result.lo = initUintImpl(x, type result.lo)
func zero*[T: BaseUint](_: typedesc[T]): T {.inline.}=
discard
func one*[T: BaseUint or IntImpl](_: typedesc[T]): T {.inline.}=
when T is SomeInteger:
result = T(1)
else:
let r_ptr = cast[ptr array[getSize(result) div 8, byte]](result.addr)
when system.cpuEndian == littleEndian:
r_ptr[0] = 1
else:
r_ptr[r_ptr[].len - 1] = 1

View File

@ -0,0 +1,47 @@
# Stint
# 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.
import ./datatypes, ./conversion, ./as_signed_words
func `+`*(x, y: IntImpl): IntImpl {.noInit, inline.}=
# Addition for multi-precision signed int.
type SubTy = type x.lo
result.lo = x.lo + y.lo
result.hi = (x.lo < y.lo).toSubtype(SubTy) + x.hi + y.hi
when compileOption("boundChecks"):
if unlikely(
((result.most_significant_word xor x.most_significant_word) >= 0) or
((result.most_significant_word xor y.most_significant_word) >= 0)
):
return
raise newException(OverflowError, "Addition overflow")
func `+=`*(x: var IntImpl, y: IntImpl) {.inline.}=
## In-place addition for multi-precision signed int.
x = x + y
func `-`*(x, y: IntImpl): IntImpl {.noInit, inline.}=
# Substraction for multi-precision signed int.
type SubTy = type x.lo
result.lo = x.lo - y.lo
result.hi = x.hi - y.hi - (x.lo < y.lo).toSubtype(SubTy)
when compileOption("boundChecks"):
if unlikely(
((result.most_significant_word xor x.most_significant_word) >= 0) or
((result.most_significant_word xor (not y).most_significant_word) >= 0)
):
return
raise newException(OverflowError, "Substraction underflow")
func `-=`*(x: var IntImpl, y: IntImpl) {.inline.}=
## In-place substraction for multi-precision signed int.
x = x - y

View File

@ -0,0 +1,31 @@
# Stint
# 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.
import ./datatypes, ./as_words
func `not`*(x: IntImpl): IntImpl {.noInit, inline.}=
## Bitwise complement of unsigned integer x
m_asWordsZip(result, x, ignoreEndianness = true):
result = not x
func `or`*(x, y: IntImpl): IntImpl {.noInit, inline.}=
## `Bitwise or` of numbers x and y
m_asWordsZip(result, x, y, ignoreEndianness = true):
result = x or y
func `and`*(x, y: IntImpl): IntImpl {.noInit, inline.}=
## `Bitwise and` of numbers x and y
m_asWordsZip(result, x, y, ignoreEndianness = true):
result = x and y
func `xor`*(x, y: IntImpl): IntImpl {.noInit, inline.}=
## `Bitwise xor` of numbers x and y
m_asWordsZip(result, x, y, ignoreEndianness = true):
result = x xor y

View File

@ -0,0 +1,45 @@
# Stint
# 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.
import ./datatypes, ./bithacks, ./as_words, ./as_signed_words,
./bithacks
func isZero*(n: SomeSignedInt): bool {.inline.} =
n == 0
func isZero*(n: IntImpl): bool {.inline.} =
asWords(n, ignoreEndianness = true):
if n != 0:
return false
return true
func isNegative*(n: IntImpl): bool {.inline.} =
## Returns true if a number is negative:
n.msb.bool
func `<`*(x, y: IntImpl): bool {.inline.}=
# Lower comparison for multi-precision integers
asSignedWordsZip(x, y):
if x != y:
return x < y
return false # they're equal
func `==`*(x, y: IntImpl): bool {.inline.}=
# Equal comparison for multi-precision integers
asWordsZip(x, y, ignoreEndianness = true):
if x != y:
return false
return true # they're equal
func `<=`*(x, y: IntImpl): bool {.inline.}=
# Lower or equal comparison for multi-precision integers
asSignedWordsZip(x, y):
if x != y:
return x < y
return true # they're equal

59
src/private/int_div.nim Normal file
View File

@ -0,0 +1,59 @@
# Stint
# 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.
import ./datatypes, ./int_negabs, ./uint_div
# Here are the expected signs for division/modulo by opposite signs and both negative numbers
# in EVM
# Parity: https://github.com/paritytech/parity/blob/684322cd6f210684b890055c43d56bb1bc8cae15/ethcore/evm/src/interpreter/mod.rs#L729-L756
# - SDIV is sign(a) xor sign(b)
# - SMOD is sign(a)
# Go-Ethereum: https://github.com/ethereum/go-ethereum/blob/ba1030b6b84f810c04a82221a1b1c0a3dbf499a8/core/vm/instructions.go#L76-L104
# - SDIV is "if same sign, div(abs(a), abs(b)), else -div(abs(a), abs(b))
# - SMOD is "sign(a)"
#
# in Nim
# echo "10 div 3: " & $(10 div 3) # 3
# echo "10 mod 3: " & $(10 mod 3) # 1
# echo '\n'
# echo "10 div -3: " & $(10 div -3) # -3
# echo "10 mod -3: " & $(10 mod -3) # 1
# echo '\n'
# echo "-10 div 3: " & $(-10 div 3) # -3
# echo "-10 mod 3: " & $(-10 mod 3) # -1
# echo '\n'
# echo "-10 div -3: " & $(-10 div -3) # 3
# echo "-10 mod -3: " & $(-10 mod -3) # -1
# echo '\n'
func divmod*(x, y: SomeSignedInt): tuple[quot, rem: SomeSignedInt] {.noInit, inline.}=
# hopefully the compiler fuse that in a single op
(x div y, x mod y)
proc divmod*[T](x, y: IntImpl[T]): tuple[quot, rem: IntImpl[T]] {.noInit.}=
## Divmod operation for multi-precision signed integer
result = cast[type result](divmod(
cast[UintImpl[T]](x.abs),
cast[UintImpl[T]](y.abs)
))
if (x.isNegative xor y.isNegative):
# If opposite signs
result.quot = -result.quot
if x.isNegative:
result.rem = -result.rem
func `div`*(x, y: IntImpl): IntImpl {.inline.} =
## Division operation for multi-precision signed integer
divmod(x,y).quot
func `mod`*(x, y: IntImpl): IntImpl {.inline.} =
## Division operation for multi-precision signed integer
divmod(x,y).rem

View File

@ -0,0 +1,27 @@
# Stint
# 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.
import ./datatypes, ./as_signed_words
func low*(T: typedesc[IntImpl]): T {.inline.}=
# The lowest signed int has representation
# 0b1000_0000_0000_0000 ....
# so we only have to set the most significant bit.
type Msw = type result.most_significant_word
type U = Msw
most_significant_word_mut(result) = low(U)
func high*(T: typedesc[IntImpl]): T {.inline, noInit.}=
# The lowest signed int has representation
# 0b0111_1111_1111_1111 ....
# so we only have to unset the most significant bit.
not low(T)

17
src/private/int_mul.nim Normal file
View File

@ -0,0 +1,17 @@
# Stint
# 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.
import ./datatypes, ./uint_mul
func `*`*[T](x, y: IntImpl[T]): IntImpl[T] {.inline, noInit.}=
## Multiplication for multi-precision signed integers
# For 2-complement representation this is the exact same
# as unsigned multiplication. We don't need to deal with the sign
# TODO: overflow detection.
cast[type result](cast[UIntImpl[T]](x) * cast[UIntImpl[T]](y))

View File

@ -0,0 +1,29 @@
# Stint
# 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.
import
./datatypes,
./initialization, ./int_highlow,
./int_addsub
func `-`*[T: IntImpl](x: T): T {.noInit, inline.}=
# Negate a multi-precision signed int.
when compileOption("boundChecks"):
if unlikely(x == low(T)):
raise newException(OverflowError, "The lowest negative number cannot be negated")
result = not x
result += one(T)
func abs*[T: IntImpl](x: T): T {.noInit, inline.}=
## Returns the absolute value of a signed int.
result = if x.isNegative: -x
else: x

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -8,7 +8,7 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ./bithacks, ./conversion,
./uint_type,
./datatypes,
./uint_comparison,
./uint_bitwise_ops

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -7,7 +7,7 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ./uint_type, ./as_words
import ./datatypes, ./as_words
func `not`*(x: UintImpl): UintImpl {.noInit, inline.}=

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -7,7 +7,7 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ./uint_type, ./as_words
import ./datatypes, ./as_words
func isZero*(n: SomeUnsignedInt): bool {.inline.} =
n == 0

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -7,8 +7,8 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ./bithacks, ./conversion,
./uint_type,
import ./bithacks, ./conversion, ./initialization,
./datatypes,
./uint_comparison,
./uint_bitwise_ops,
./uint_addsub,
@ -48,7 +48,7 @@ func div2n1n[T: SomeunsignedInt](q, r: var T, n_hi, n_lo, d: T)
func div2n1n(q, r: var UintImpl, ah, al, b: UintImpl)
# Forward declaration
proc divmod*(x, y: SomeInteger): tuple[quot, rem: SomeInteger] {.noSideEffect, inline.}=
func divmod*(x, y: SomeUnsignedInt): tuple[quot, rem: SomeUnsignedInt] {.noInit, inline.}=
# hopefully the compiler fuse that in a single op
(x div y, x mod y)

View File

@ -0,0 +1,16 @@
# Stint
# 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.
import ./datatypes, ./initialization
func low*(T: typedesc[UintImpl]): T {.inline, noInit.}=
zero(T)
func high*(T: typedesc[UintImpl]): T {.inline, noInit.}=
not zero(T)

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -8,7 +8,8 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ./conversion,
./uint_type,
./initialization,
./datatypes,
./uint_comparison,
./uint_addsub
@ -114,7 +115,7 @@ func extPrecMul*[T](result: var UintImpl[UintImpl[T]], x, y: UintImpl[T]) =
if result.lo.hi < z1.lo:
result.hi += one(UintImpl[T])
func `*`*[T](x, y: UintImpl[T]): UintImpl[T] {.inline.}=
func `*`*[T](x, y: UintImpl[T]): UintImpl[T] {.inline, noInit.}=
## Multiplication for multi-precision unsigned uint
#
# For our representation, it is similar to school grade multiplication

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -7,5 +7,5 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ./uint_public, ./uint_init
export uint_public, uint_init
import ./uint_public, ./int_public, ./init
export uint_public, int_public, init

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -7,8 +7,8 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ./private/uint_type, macros
export StUint, UintImpl, getUintImpl # TODO remove the need to export UintImpl and this macro
import ./private/datatypes, macros
export StUint, UintImpl, uintImpl # TODO remove the need to export UintImpl and this macro
type
UInt128* = StUint[128]

View File

@ -8,7 +8,7 @@ srcDir = "src"
### Dependencies
# TODO remove test only requirements: https://github.com/nim-lang/nimble/issues/482
requires "nim >= 0.18", "https://github.com/alehander42/nim-quicktest >= 0.0.9"
requires "nim >= 0.18", "https://github.com/alehander42/nim-quicktest >= 0.0.12"
proc test(name: string, lang: string = "c") =
if not dirExists "build":

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -7,8 +7,12 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import test_endianness,
test_comparison,
test_bitwise,
test_addsub,
test_muldiv
import test_uint_endianness,
test_uint_comparison,
test_uint_bitwise,
test_uint_addsub,
test_uint_muldiv
import test_int_endianness,
test_int_comparison,
test_int_addsub

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -7,7 +7,7 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ../src/mpint, unittest, quicktest
import ../src/stint, unittest, quicktest
const itercount = 1000

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -10,7 +10,7 @@
# Requires "https://github.com/status-im/nim-ttmath#master"
# Note that currently importing both Stint and TTMath will crash the compiler for unknown reason
import ../src/mpint, unittest, quicktest, ttmath
import ../src/stint, unittest, quicktest, ttmath
const itercount = 1000

51
tests/test_int_addsub.nim Normal file
View File

@ -0,0 +1,51 @@
# Stint
# 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.
import ../src/stint, unittest
suite "Testing signed addition implementation":
test "In-place addition gives expected result":
var a = 20182018.stint(64)
let b = 20172017.stint(64)
a += b
check: cast[int64](a) == 20182018'i64 + 20172017'i64
test "Addition gives expected result":
let a = 20182018.stint(64)
let b = 20172017.stint(64)
check: cast[int64](a+b) == 20182018'i64 + 20172017'i64
test "When the low half overflows, it is properly carried":
# uint8 (low half) overflow at 255
let a = 100'i16.stint(16)
let b = 100'i16.stint(16)
check: cast[int16](a+b) == 200
suite "Testing signed substraction implementation":
test "In-place substraction gives expected result":
var a = 20182018.stint(64)
let b = 20172017.stint(64)
a -= b
check: cast[int64](a) == 20182018'i64 - 20172017'i64
test "Substraction gives expected result":
let a = 20182018.stint(64)
let b = 20172017.stint(64)
check: cast[int64](a-b) == 20182018'i64 - 20172017'i64

View File

View File

@ -0,0 +1,56 @@
# Stint
# 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.
import ../src/stint, unittest
suite "Signed int - Testing comparison operators":
let
a = 10'i16.stint(16)
b = 15'i16.stint(16)
c = 150'i16.stint(16)
test "< operator":
check:
a < b
not (a + b < b)
not (a + a + a < b + b)
-c < c
-c < a
-b < -a
not(-b < -b)
test "<= operator":
check:
a <= b
not (a + b <= b)
a + a + a <= b + b
-c <= c
-c <= a
-b <= -a
-b <= -b
test "> operator":
check:
b > a
not (b > a + b)
not (b + b > a + a + a)
c > -c
a > -c
b > -c
not(-b > -b)
test ">= operator":
check:
b >= a
not (b >= a + b)
b + b >= a + a + a
c >= -c
a >= -c
b >= -c
-b >= -b

View File

@ -0,0 +1,28 @@
# Stint
# 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.
import ../src/stint, unittest
suite "Testing signed int byte representation":
test "Byte representation conforms to the platform endianness":
block:
let a = 20182018.stint(64)
let b = 20182018'i64
type AsBytes = array[8, byte]
check cast[AsBytes](a) == cast[AsBytes](b)
block:
let a = (-20182018).stint(64)
let b = -20182018'i64
type AsBytes = array[8, byte]
check cast[AsBytes](a) == cast[AsBytes](b)

109
tests/test_int_muldiv.nim Normal file
View File

@ -0,0 +1,109 @@
# Stint
# 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.
import ../src/stint, unittest
suite "Testing signed int multiplication implementation":
test "Multiplication with result fitting in low half":
let a = 10000.stint(64)
let b = 10000.stint(64)
check: cast[int64](a*b) == 100_000_000'i64 # need 27-bits
test "Multiplication with result overflowing low half":
let a = 1_000_000.stint(64)
let b = 1_000_000.stint(64)
check: cast[int64](a*b) == 1_000_000_000_000'i64 # need 40 bits
test "Multiplication with result fitting in low half - opposite signs":
let a = -10000.stint(64)
let b = 10000.stint(64)
check:
cast[int64](a*b) == -100_000_000'i64 # need 27-bits
cast[int64](b*a) == -100_000_000'i64
test "Multiplication with result overflowing low half - opposite signs":
let a = -1_000_000.stint(64)
let b = 1_000_000.stint(64)
check:
cast[int64](a*b) == -1_000_000_000_000'i64 # need 40 bits
cast[int64](b*a) == -1_000_000_000_000'i64
test "Multiplication with result fitting in low half - both negative":
let a = -10000.stint(64)
let b = -10000.stint(64)
check: cast[int64](a*b) == 100_000_000'i64 # need 27-bits
test "Multiplication with result overflowing low half - both negative":
let a = -1_000_000.stint(64)
let b = -1_000_000.stint(64)
check: cast[int64](a*b) == 1_000_000_000_000'i64 # need 40 bits
suite "Testing signed int division and modulo implementation":
test "Divmod(100, 13) returns the correct result":
let a = 100.stint(64)
let b = 13.stint(64)
let qr = divmod(a, b)
check: cast[int64](qr.quot) == 7'i64
check: cast[int64](qr.rem) == 9'i64
test "Divmod(-100, 13) returns the correct result":
let a = -100.stint(64)
let b = 13.stint(64)
let qr = divmod(a, b)
check: cast[int64](qr.quot) == -100'i64 div 13
check: cast[int64](qr.rem) == -100'i64 mod 13
test "Divmod(100, -13) returns the correct result":
let a = 100.stint(64)
let b = -13.stint(64)
let qr = divmod(a, b)
check: cast[int64](qr.quot) == 100'i64 div -13
check: cast[int64](qr.rem) == 100'i64 mod -13
test "Divmod(-100, -13) returns the correct result":
let a = -100.stint(64)
let b = -13.stint(64)
let qr = divmod(a, b)
check: cast[int64](qr.quot) == -100'i64 div -13
check: cast[int64](qr.rem) == -100'i64 mod -13
# test "Divmod(2^64, 3) returns the correct result":
# let a = 1.stint(128) shl 64
# let b = 3.stint(128)
# let qr = divmod(a, b)
# 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

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -7,9 +7,9 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ../src/mpint, unittest
import ../src/stint, unittest
suite "Testing addition implementation":
suite "Testing unsigned int addition implementation":
test "In-place addition gives expected result":
var a = 20182018.stuint(64)
@ -51,7 +51,7 @@ suite "Testing addition implementation":
z += a
check: cast[uint16](z) == 164
suite "Testing substraction implementation":
suite "Testing unsigned int substraction implementation":
test "In-place substraction gives expected result":
var a = 20182018.stuint(64)

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -7,9 +7,9 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ../src/mpint, unittest
import ../src/stint, unittest
suite "Testing bitwise operations":
suite "Testing unsigned int bitwise operations":
let a = 100'i16.stuint(16)
let b = a * a

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -7,9 +7,9 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ../src/mpint, unittest
import ../src/stint, unittest
suite "Testing comparison operators":
suite "Testing unsigned int comparison operators":
let
a = 10'i16.stuint(16)
b = 15'i16.stuint(16)

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -7,9 +7,9 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ../src/mpint, unittest
import ../src/stint, unittest
suite "Testing byte representation":
suite "Testing unsigned int byte representation":
test "Byte representation conforms to the platform endianness":
let a = 20182018.stuint(64)
let b = 20182018'u64

View File

@ -1,4 +1,4 @@
# Mpint
# Stint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
@ -7,9 +7,9 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ../src/mpint, unittest
import ../src/stint, unittest
suite "Testing multiplication implementation":
suite "Testing unsigned int multiplication implementation":
test "Multiplication with result fitting in low half":
let a = 10000.stuint(64)
@ -33,7 +33,7 @@ suite "Testing multiplication implementation":
check: cast[uint64](a*b*c) == 1_000_000_000_000_000_000_000'u64 # need 70-bits
suite "Testing division and modulo implementation":
suite "Testing unsigned int division and modulo implementation":
test "Divmod(100, 13) returns the correct result":
let a = 100.stuint(64)