Add signed initialization, bitwise ops, addition, negation
This commit is contained in:
parent
e2ab2dbf59
commit
b34019c0b5
|
@ -33,3 +33,36 @@ 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 UintImpl:
|
||||
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:
|
||||
if n < 0:
|
||||
result.data = (type result.data)(-n)
|
||||
result = -result
|
||||
else:
|
||||
result.data = (type result.data)(n)
|
|
@ -0,0 +1,79 @@
|
|||
# Mpint
|
||||
# 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_addsubneg
|
||||
|
||||
make_binary(`+`, Stint)
|
||||
make_binary_inplace(`+=`)
|
||||
make_unary(`-`, Stint)
|
||||
# make_binary(`-`, Stint)
|
||||
# make_binary_inplace(`-=`)
|
||||
|
||||
# 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
|
|
@ -25,7 +25,7 @@ func countLeadingZeroBits*(n: UintImpl): int {.inline.} =
|
|||
n.lo.countLeadingZeroBits + maxHalfRepr
|
||||
else: hi_clz
|
||||
|
||||
func msb*[T: SomeInteger](n: T): T =
|
||||
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):
|
||||
|
@ -42,7 +42,7 @@ func msb*[T: SomeInteger](n: T): T =
|
|||
const msb_pos = sizeof(T) * 8 - 1
|
||||
result = T(cast[Uint](n) shr msb_pos)
|
||||
|
||||
func msb*(n: IntImpl): auto =
|
||||
func msb*(n: IntImpl): auto {.inline.}=
|
||||
## Returns the most significant bit of an arbitrary precision integer.
|
||||
|
||||
result = msb most_significant_word(n)
|
||||
|
|
|
@ -109,8 +109,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
|
||||
|
@ -120,6 +118,7 @@ type
|
|||
hi*, lo*: BaseUint
|
||||
|
||||
IntImpl*[Baseuint] = object
|
||||
# Ints are implemented in terms of uints
|
||||
when system.cpuEndian == littleEndian:
|
||||
lo*, hi*: BaseUint
|
||||
else:
|
||||
|
|
|
@ -40,3 +40,13 @@ func one*[T: BaseUint](_: typedesc[T]): T {.inline.}=
|
|||
r_ptr[0] = 1
|
||||
else:
|
||||
r_ptr[r_ptr[].len - 1] = 1
|
||||
|
||||
func one*[T: 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 == bigEndian:
|
||||
r_ptr[0] = 1
|
||||
else:
|
||||
r_ptr[r_ptr[].len - 1] = 1
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# Mpint
|
||||
# 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_bitwise_ops, ./initialization
|
||||
|
||||
func `+=`*(x: var IntImpl, y: IntImpl) {.inline.}=
|
||||
## In-place addition for multi-precision signed int
|
||||
|
||||
type SubTy = type x.lo
|
||||
x.lo += y.lo
|
||||
x.hi += (x.lo < y.lo).toSubtype(SubTy) + y.hi
|
||||
|
||||
func `+`*(x, y: UintImpl): UintImpl {.noInit, inline.}=
|
||||
# Addition for multi-precision signed int
|
||||
result = x
|
||||
result += y
|
||||
|
||||
func `-`*[T: IntImpl](x: T): T {.noInit, inline.}=
|
||||
result = not x
|
||||
result += one(T)
|
|
@ -0,0 +1,31 @@
|
|||
# Mpint
|
||||
# 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
|
|
@ -115,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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
# Mpint
|
||||
# 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'u16
|
||||
|
||||
test "< operator":
|
||||
check:
|
||||
a < b
|
||||
not (a + b < b)
|
||||
not (a + a + a < b + b)
|
||||
|
||||
test "<= operator":
|
||||
check:
|
||||
a <= b
|
||||
not (a + b <= b)
|
||||
a + a + a <= b + b
|
||||
|
||||
test "> operator":
|
||||
check:
|
||||
b > a
|
||||
not (b > a + b)
|
||||
not (b + b > a + a + a)
|
||||
|
||||
test ">= operator":
|
||||
check:
|
||||
b >= a
|
||||
not (b >= a + b)
|
||||
b + b >= a + a + a
|
||||
|
|
@ -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
|
||||
import ../src/stint, unittest
|
||||
|
||||
suite "Testing addition implementation":
|
||||
test "In-place addition gives expected result":
|
||||
|
|
|
@ -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
|
||||
import ../src/stint, unittest
|
||||
|
||||
suite "Testing bitwise operations":
|
||||
let a = 100'i16.stuint(16)
|
||||
|
|
|
@ -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
|
||||
import ../src/stint, unittest
|
||||
|
||||
suite "Testing comparison operators":
|
||||
let
|
||||
|
|
|
@ -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
|
||||
import ../src/stint, unittest
|
||||
|
||||
suite "Testing byte representation":
|
||||
test "Byte representation conforms to the platform endianness":
|
||||
|
|
|
@ -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
|
||||
import ../src/stint, unittest
|
||||
|
||||
suite "Testing multiplication implementation":
|
||||
test "Multiplication with result fitting in low half":
|
||||
|
|
Loading…
Reference in New Issue