signed int signedness
This commit is contained in:
parent
8c5a96463c
commit
76b2baad6f
291
stint/intops.nim
291
stint/intops.nim
|
@ -7,155 +7,204 @@
|
||||||
#
|
#
|
||||||
# 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/[datatypes]
|
import
|
||||||
|
./private/datatypes,
|
||||||
|
./private/uint_bitwise,
|
||||||
|
./private/uint_shift,
|
||||||
|
./private/uint_addsub,
|
||||||
|
./uintops
|
||||||
|
|
||||||
export StInt
|
export StInt
|
||||||
#export IntImpl, intImpl, UintImpl, uintImpl, bitsof # TODO: remove the need to export those
|
|
||||||
|
|
||||||
#import ./private/initialization
|
const
|
||||||
|
signMask = 1.Word shl WordBitWidth
|
||||||
|
clearSignMask = not signMask
|
||||||
|
|
||||||
func zero*[bits: static[int]](T: typedesc[StInt[bits]]): T {.inline.} =
|
# Signedness
|
||||||
|
# --------------------------------------------------------
|
||||||
|
{.push raises: [], inline, noinit, gcsafe.}
|
||||||
|
|
||||||
|
func sign*(a: StInt): int =
|
||||||
|
if a.imp.isZero: return 0
|
||||||
|
if a.limbs[^1] < signMask: 1
|
||||||
|
else: -1
|
||||||
|
|
||||||
|
func isNegative*(a: StInt): bool =
|
||||||
|
a.sign < 0
|
||||||
|
|
||||||
|
func clearSign(a: var StInt) =
|
||||||
|
a.limbs[^1] = a.limbs[^1] and clearSignMask
|
||||||
|
|
||||||
|
func setSign(a: var StInt) =
|
||||||
|
a.limbs[^1] = a.limbs[^1] or signMask
|
||||||
|
|
||||||
|
func negate*(a: var StInt) =
|
||||||
|
a.imp.bitnot(a.imp)
|
||||||
|
a.imp.inc
|
||||||
|
|
||||||
|
func neg*(a: StInt): StInt =
|
||||||
|
result.imp.bitnot(a.imp)
|
||||||
|
result.imp.inc
|
||||||
|
|
||||||
|
func abs*(a: StInt): StInt =
|
||||||
|
if a.isNegative:
|
||||||
|
a.neg
|
||||||
|
else:
|
||||||
|
a
|
||||||
|
|
||||||
|
func `-`*(a: StInt): StInt =
|
||||||
|
a.neg
|
||||||
|
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
|
# Initialization
|
||||||
|
# --------------------------------------------------------
|
||||||
|
{.push raises: [], inline, noinit, gcsafe.}
|
||||||
|
|
||||||
|
func setZero*(a: var StInt) =
|
||||||
|
## Set ``a`` to 0
|
||||||
|
a.imp.setZero
|
||||||
|
|
||||||
|
func setOne*(a: var StInt) =
|
||||||
|
a.imp.setOne
|
||||||
|
|
||||||
|
func zero*[bits: static[int]](T: typedesc[StInt[bits]]): T =
|
||||||
## Returns the zero of the input type
|
## Returns the zero of the input type
|
||||||
discard
|
result.setZero
|
||||||
|
|
||||||
#[
|
func one*[bits: static[int]](T: typedesc[StInt[bits]]): T =
|
||||||
func one*[bits: static[int]](T: typedesc[StUint[bits]]): T {.inline.} =
|
|
||||||
## Returns the one of the input type
|
## Returns the one of the input type
|
||||||
result.data = one(type result.data)
|
result.setOne
|
||||||
|
|
||||||
import ./private/[int_addsub, uint_addsub]
|
func high*[bits](_: typedesc[StInt[bits]]): StInt[bits] =
|
||||||
|
# The highest signed int has representation
|
||||||
|
# 0b0111_1111_1111_1111 ....
|
||||||
|
# so we only have to unset the most significant bit.
|
||||||
|
for i in 0 ..< result.limbs.len:
|
||||||
|
result[i] = high(Word)
|
||||||
|
result.clearSign
|
||||||
|
|
||||||
func `+`*(x, y: SomeBigInteger): SomeBigInteger {.inline.} =
|
func low*[bits](_: typedesc[StInt[bits]]): StInt[bits] =
|
||||||
## Integer addition
|
# The lowest signed int has representation
|
||||||
result.data = x.data + y.data
|
# 0b1000_0000_0000_0000 ....
|
||||||
func `+=`*(x: var SomeBigInteger, y: SomeBigInteger) {.inline.} =
|
# so we only have to set the most significant bit.
|
||||||
## Integer addition
|
result.setZero
|
||||||
x.data += y.data
|
result.setSign
|
||||||
func `-`*(x, y: SomeBigInteger): SomeBigInteger {.inline.} =
|
|
||||||
## Integer substraction
|
|
||||||
result.data = x.data - y.data
|
|
||||||
func `-=`*(x: var SomeBigInteger, y: SomeBigInteger) {.inline.} =
|
|
||||||
## Integer substraction
|
|
||||||
x.data -= y.data
|
|
||||||
|
|
||||||
import ./private/int_negabs
|
{.pop.}
|
||||||
|
|
||||||
func `-`*(x: StInt): StInt {.inline.} =
|
# Comparisons
|
||||||
## Returns true if input is zero
|
# --------------------------------------------------------
|
||||||
## false otherwise
|
{.push raises: [], inline, noinit, gcsafe.}
|
||||||
result.data = -x.data
|
|
||||||
|
|
||||||
func abs*(x: StInt): StInt {.inline.} =
|
func isZero*(a: StInt): bool =
|
||||||
## Returns true if input is zero
|
a.imp.isZero
|
||||||
## false otherwise
|
|
||||||
result.data = abs(x.data)
|
|
||||||
|
|
||||||
import ./private/[int_mul, uint_mul]
|
func `==`*(a, b: StInt): bool =
|
||||||
|
|
||||||
func `*`*(x, y: SomeBigInteger): SomeBigInteger {.inline.} =
|
|
||||||
## Integer multiplication
|
|
||||||
result.data = x.data * y.data
|
|
||||||
|
|
||||||
import ./private/[int_div, uint_div]
|
|
||||||
|
|
||||||
func `div`*(x, y: SomeBigInteger): SomeBigInteger {.inline.} =
|
|
||||||
## Integer division
|
|
||||||
result.data = x.data div y.data
|
|
||||||
func `mod`*(x, y: SomeBigInteger): SomeBigInteger {.inline.} =
|
|
||||||
## Integer modulo
|
|
||||||
## This returns the remainder of x / y.
|
|
||||||
## i.e. x = y * quotient + remainder
|
|
||||||
result.data = x.data mod y.data
|
|
||||||
func divmod*(x, y: SomeBigInteger): tuple[quot, rem: SomeBigInteger] {.inline.} =
|
|
||||||
## Fused integer division and modulo
|
|
||||||
## Return both the quotient and remainder
|
|
||||||
## of x / y
|
|
||||||
(result.quot.data, result.rem.data) = divmod(x.data, y.data)
|
|
||||||
|
|
||||||
import ./private/[int_comparison, uint_comparison]
|
|
||||||
|
|
||||||
func `<`*(x, y: SomeBigInteger): bool {.inline.} =
|
|
||||||
## Unsigned `less than` comparison
|
|
||||||
x.data < y.data
|
|
||||||
func `<=`*(x, y: SomeBigInteger): bool {.inline.} =
|
|
||||||
## Unsigned `less or equal` comparison
|
|
||||||
x.data <= y.data
|
|
||||||
func `==`*(x, y: SomeBigInteger): bool {.inline.} =
|
|
||||||
## Unsigned `equal` comparison
|
## Unsigned `equal` comparison
|
||||||
x.data == y.data
|
a.imp == b.imp
|
||||||
export `<`, `<=`, `==` # Address Generic Instantiation too nested: https://github.com/status-im/nim-stint/pull/66#issuecomment-427557655
|
|
||||||
|
|
||||||
# TODO these exports are needed for the SomeInteger versions - move to stew?
|
func `<`*(a, b: StInt): bool =
|
||||||
export isZero, isOdd, isEven, isNegative
|
## Unsigned `less than` comparison
|
||||||
|
let
|
||||||
|
aSign = a.Sign
|
||||||
|
bSign = b.Sign
|
||||||
|
|
||||||
func isZero*(x: SomeBigInteger): bool {.inline.} =
|
if aSign >= 0:
|
||||||
|
if bSign < 0:
|
||||||
|
return false
|
||||||
|
elif bSign >= 0:
|
||||||
|
return true
|
||||||
|
|
||||||
|
a.imp < b.imp
|
||||||
|
|
||||||
|
func `<=`*(a, b: StInt): bool =
|
||||||
|
## Unsigned `less or equal` comparison
|
||||||
|
not(b < a)
|
||||||
|
|
||||||
|
func isOdd*(a: StInt): bool =
|
||||||
|
## Returns true if input is off
|
||||||
|
## false otherwise
|
||||||
|
bool(a[0] and 1)
|
||||||
|
|
||||||
|
func isEven*(a: StInt): bool =
|
||||||
## Returns true if input is zero
|
## Returns true if input is zero
|
||||||
## false otherwise
|
## false otherwise
|
||||||
x.data.isZero
|
not a.isOdd()
|
||||||
|
|
||||||
func isNegative*(x: StInt): bool {.inline.} =
|
{.pop.}
|
||||||
## Returns true if input is negative (< 0)
|
|
||||||
## false otherwise
|
|
||||||
x.data.isNegative
|
|
||||||
|
|
||||||
func isOdd*(x: SomeBigInteger): bool {.inline.} =
|
# Bitwise operations
|
||||||
## Returns true if input is zero
|
# --------------------------------------------------------
|
||||||
## false otherwise
|
{.push raises: [], inline, noinit, gcsafe.}
|
||||||
x.data.isOdd
|
|
||||||
|
|
||||||
func isEven*(x: SomeBigInteger): bool {.inline.} =
|
func `not`*(a: StInt): StInt =
|
||||||
## Returns true if input is zero
|
## Bitwise complement of unsigned integer a
|
||||||
## false otherwise
|
## i.e. flips all bits of the input
|
||||||
x.data.isEven
|
result.imp.bitnot(a.imp)
|
||||||
|
|
||||||
export isEven, isOdd
|
func `or`*(a, b: StInt): StInt =
|
||||||
|
## `Bitwise or` of numbers a and b
|
||||||
|
result.imp.bitor(a.imp, b.imp)
|
||||||
|
|
||||||
import ./private/[int_bitwise_ops, uint_bitwise_ops]
|
func `and`*(a, b: StInt): StInt =
|
||||||
|
## `Bitwise and` of numbers a and b
|
||||||
|
result.imp.bitand(a.imp, b.imp)
|
||||||
|
|
||||||
func `not`*(x: SomeBigInteger): SomeBigInteger {.inline.}=
|
func `xor`*(a, b: StInt): StInt =
|
||||||
## Bitwise `not` i.e. flips all bits of the input
|
## `Bitwise xor` of numbers x and y
|
||||||
result.data = x.data.not
|
result.imp.bitxor(a.imp, b.imp)
|
||||||
func `or`*(x, y: SomeBigInteger): SomeBigInteger {.inline.}=
|
|
||||||
## Bitwise `or`
|
|
||||||
result.data = x.data or y.data
|
|
||||||
func `and`*(x, y: SomeBigInteger): SomeBigInteger {.inline.}=
|
|
||||||
## Bitwise `and`
|
|
||||||
result.data = x.data and y.data
|
|
||||||
func `xor`*(x, y: SomeBigInteger): SomeBigInteger {.inline.}=
|
|
||||||
## Bitwise `xor`
|
|
||||||
result.data = x.data xor y.data
|
|
||||||
|
|
||||||
func `shr`*(x: SomeBigInteger, y: SomeInteger): SomeBigInteger {.inline.} =
|
{.pop.} # End noInit
|
||||||
result.data = x.data shr y
|
|
||||||
|
|
||||||
func `shl`*(x: SomeBigInteger, y: SomeInteger): SomeBigInteger {.inline.} =
|
{.push raises: [], inline, gcsafe.}
|
||||||
result.data = x.data shl y
|
|
||||||
|
|
||||||
import ./private/[int_highlow, uint_highlow]
|
func `shr`*(a: StInt, k: SomeInteger): StInt =
|
||||||
|
## Shift right by k bits, arithmetically
|
||||||
|
## ~(~a >> k)
|
||||||
|
var tmp: type a
|
||||||
|
result.imp.bitnot(a.imp)
|
||||||
|
tmp.imp.shiftRight(result.imp, k)
|
||||||
|
result.imp.bitnot(tmp.imp)
|
||||||
|
|
||||||
func high*[bits](_: typedesc[StInt[bits]]): StInt[bits] {.inline.} =
|
func `shl`*(a: StInt, k: SomeInteger): StInt =
|
||||||
result.data = high(type result.data)
|
## Shift left by k bits
|
||||||
func high*[bits](_: typedesc[StUint[bits]]): StUint[bits] {.inline.} =
|
result.imp.shiftLeft(a.imp, k)
|
||||||
result.data = high(type result.data)
|
|
||||||
|
|
||||||
func low*[bits](_: typedesc[StInt[bits]]): StInt[bits] {.inline.} =
|
{.pop.}
|
||||||
result.data = low(type result.data)
|
|
||||||
func low*[bits](_: typedesc[StUint[bits]]): StUint[bits] {.inline.} =
|
|
||||||
result.data = low(type result.data)
|
|
||||||
|
|
||||||
import ./private/uint_exp, math
|
# Addsub
|
||||||
|
# --------------------------------------------------------
|
||||||
|
{.push raises: [], inline, noinit, gcsafe.}
|
||||||
|
|
||||||
func pow*(x: StUint, y: Natural): StUint {.inline.} =
|
#[
|
||||||
## Returns x raised at the power of y
|
func `+`*(a, b: StInt): StInt =
|
||||||
when x.data is UintImpl:
|
## Addition for multi-precision unsigned int
|
||||||
result.data = x.data.pow(y)
|
result.sum(a, b)
|
||||||
else:
|
|
||||||
result.data = x.data ^ y
|
|
||||||
|
|
||||||
func pow*(x: StUint, y: StUint): StUint {.inline.} =
|
func `+=`*(a: var StInt, b: StInt) =
|
||||||
## Returns x raised at the power of y
|
## In-place addition for multi-precision unsigned int
|
||||||
when x.data is UintImpl:
|
a.sum(a, b)
|
||||||
result.data = x.data.pow(y.data)
|
|
||||||
else:
|
func `-`*(a, b: StInt): StInt =
|
||||||
result.data = x.data ^ y.data
|
## Substraction for multi-precision unsigned int
|
||||||
]#
|
result.diff(a, b)
|
||||||
|
|
||||||
|
func `-=`*(a: var StInt, b: StInt) =
|
||||||
|
## In-place substraction for multi-precision unsigned int
|
||||||
|
a.diff(a, b)
|
||||||
|
|
||||||
|
func inc*(a: var StInt, w: Word = 1) =
|
||||||
|
|
||||||
|
func `+`*(a: StInt, b: SomeUnsignedInt): StInt =
|
||||||
|
## Addition for multi-precision unsigned int
|
||||||
|
## with an unsigned integer
|
||||||
|
result.sum(a, Word(b))
|
||||||
|
|
||||||
|
func `+=`*(a: var StInt, b: SomeUnsignedInt) =
|
||||||
|
## In-place addition for multi-precision unsigned int
|
||||||
|
## with an unsigned integer
|
||||||
|
a.inc(Word(b))
|
||||||
|
]#
|
||||||
|
|
||||||
|
{.pop.}
|
90
stint/io.nim
90
stint/io.nim
|
@ -46,32 +46,24 @@ template static_check_size(T: typedesc[SomeInteger], bits: static[int]) =
|
||||||
func stuint*[T: SomeInteger](n: T, bits: static[int]): StUint[bits] {.inline.}=
|
func stuint*[T: SomeInteger](n: T, bits: static[int]): StUint[bits] {.inline.}=
|
||||||
## Converts an integer to an arbitrary precision integer.
|
## Converts an integer to an arbitrary precision integer.
|
||||||
when sizeof(n) > sizeof(Word):
|
when sizeof(n) > sizeof(Word):
|
||||||
result.limbs[0] = Word(n and Word.high)
|
result.limbs[0] = Word(n and Word.high)
|
||||||
result.limbs[1] = Word(n shr WordBitWidth)
|
result.limbs[1] = Word(n shr WordBitWidth)
|
||||||
else:
|
else:
|
||||||
result.limbs[0] = Word(n)
|
result.limbs[0] = Word(n)
|
||||||
|
|
||||||
# func stint*[T: SomeInteger](n: T, bits: static[int]): StInt[bits] {.inline.}=
|
func stint*[T: SomeInteger](n: T, bits: static[int]): StInt[bits] {.inline.}=
|
||||||
# ## Converts an integer to an arbitrary precision signed integer.
|
## Converts an integer to an arbitrary precision signed integer.
|
||||||
#
|
when T is SomeUnsignedInt:
|
||||||
# when result.data is IntImpl:
|
result.imp = stuint(n, bits)
|
||||||
# static_check_size(T, bits)
|
else:
|
||||||
# when T is SomeSignedInt:
|
if n < 0:
|
||||||
# if n < 0:
|
result.imp = stuint(-n, bits)
|
||||||
# # TODO: when bits >= 128, cannot create from
|
result.negate
|
||||||
# # low(int8-64)
|
else:
|
||||||
# # see: status-im/nim-stint/issues/92
|
result.imp = stuint(n, bits)
|
||||||
# assignLo(result.data, -n)
|
|
||||||
# result = -result
|
|
||||||
# else:
|
|
||||||
# assignLo(result.data, n)
|
|
||||||
# else:
|
|
||||||
# assignLo(result.data, n)
|
|
||||||
# else:
|
|
||||||
# result.data = (type result.data)(n)
|
|
||||||
|
|
||||||
# func to*(a: SomeInteger, T: typedesc[Stint]): T =
|
func to*(a: SomeInteger, T: typedesc[Stint]): T =
|
||||||
# stint(a, result.bits)
|
stint(a, result.bits)
|
||||||
|
|
||||||
func to*(a: SomeUnsignedInt, T: typedesc[StUint]): T =
|
func to*(a: SomeUnsignedInt, T: typedesc[StUint]): T =
|
||||||
stuint(a, result.bits)
|
stuint(a, result.bits)
|
||||||
|
@ -83,9 +75,6 @@ func truncate*(num: StInt or StUint, T: typedesc[SomeInteger]): T {.inline.}=
|
||||||
## For signed result type, result is undefined if input does not fit in the target type.
|
## For signed result type, result is undefined if input does not fit in the target type.
|
||||||
result = T(num.leastSignificantWord())
|
result = T(num.leastSignificantWord())
|
||||||
|
|
||||||
func toInt*(num: StInt or StUint): int {.inline, deprecated:"Use num.truncate(int) instead".}=
|
|
||||||
num.truncate(int)
|
|
||||||
|
|
||||||
func stuint*(a: StUint, bits: static[int]): StUint[bits] {.inline.} =
|
func stuint*(a: StUint, bits: static[int]): StUint[bits] {.inline.} =
|
||||||
## unsigned int to unsigned int conversion
|
## unsigned int to unsigned int conversion
|
||||||
## smaller to bigger bits conversion will have the same value
|
## smaller to bigger bits conversion will have the same value
|
||||||
|
@ -307,46 +296,19 @@ func toString*[bits: static[int]](num: StUint[bits], radix: static[uint8] = 10):
|
||||||
|
|
||||||
reverse(result)
|
reverse(result)
|
||||||
|
|
||||||
# func toString*[bits: static[int]](num: Stint[bits], radix: static[int8] = 10): string =
|
func toString*[bits: static[int]](num: StInt[bits], radix: static[int8] = 10): string =
|
||||||
# ## Convert a Stint or StUint to string.
|
## Convert a Stint or StUint to string.
|
||||||
# ## In case of negative numbers:
|
## In case of negative numbers:
|
||||||
# ## - they are prefixed with "-" for base 10.
|
## - they are prefixed with "-" for base 10.
|
||||||
# ## - if not base 10, they are returned raw in two-complement form.
|
## - if not base 10, they are returned raw in two-complement form.
|
||||||
|
let isNeg = num.isNegative
|
||||||
|
if radix == 10 and isNeg:
|
||||||
|
"-" & toString(num.neg.imp, radix)
|
||||||
|
else:
|
||||||
|
toString(num.imp, radix)
|
||||||
|
|
||||||
# static: doAssert (radix >= 2) and radix <= 16, "Only base from 2..16 are supported"
|
func `$`*(num: StInt or StUint): string {.inline.}=
|
||||||
# # TODO: use static[range[2 .. 16]], not supported at the moment (2018-04-26)
|
toString(num, 10)
|
||||||
|
|
||||||
# const hexChars = "0123456789abcdef"
|
|
||||||
# const base = radix.int8.StUint(bits)
|
|
||||||
|
|
||||||
# result = ""
|
|
||||||
|
|
||||||
# type T = StUint[bits]
|
|
||||||
# let isNeg = num.isNegative
|
|
||||||
# let num = convert[T](if radix == 10 and isNeg: -num
|
|
||||||
# else: num)
|
|
||||||
|
|
||||||
# var (q, r) = divmod(num, base)
|
|
||||||
|
|
||||||
# while true:
|
|
||||||
# when bitsof(r.data) <= 64:
|
|
||||||
# result.add hexChars[r.data.int]
|
|
||||||
# else:
|
|
||||||
# result.add hexChars[r.truncate(int)]
|
|
||||||
# if q.isZero:
|
|
||||||
# break
|
|
||||||
# (q, r) = divmod(q, base)
|
|
||||||
|
|
||||||
# if isNeg and radix == 10:
|
|
||||||
# result.add '-'
|
|
||||||
|
|
||||||
# reverse(result)
|
|
||||||
|
|
||||||
# func `$`*(num: Stint or StUint): string {.inline.}=
|
|
||||||
# when num.data is SomeInteger:
|
|
||||||
# $num.data
|
|
||||||
# else:
|
|
||||||
# toString(num, 10)
|
|
||||||
|
|
||||||
func toHex*[bits: static[int]](num: StInt[bits] or StUint[bits]): string {.inline.}=
|
func toHex*[bits: static[int]](num: StInt[bits] or StUint[bits]): string {.inline.}=
|
||||||
## Convert to a hex string.
|
## Convert to a hex string.
|
||||||
|
|
|
@ -40,7 +40,7 @@ type
|
||||||
StInt*[bits: static[int]] = object
|
StInt*[bits: static[int]] = object
|
||||||
## Stack-based integer
|
## Stack-based integer
|
||||||
## Signed
|
## Signed
|
||||||
limbs*: array[bits.wordsRequired, Word]
|
imp*: StUint[bits]
|
||||||
|
|
||||||
# {.borrow: `.`.} only works with nim-devel
|
# {.borrow: `.`.} only works with nim-devel
|
||||||
# StInt*[bits: static[int]] {.borrow: `.`.} = distinct StUint[bits]
|
# StInt*[bits: static[int]] {.borrow: `.`.} = distinct StUint[bits]
|
||||||
|
@ -94,6 +94,10 @@ func usedBitsAndWords*(a: openArray[Word]): tuple[bits, words: int] =
|
||||||
# Accessors
|
# Accessors
|
||||||
# --------------------------------------------------------
|
# --------------------------------------------------------
|
||||||
|
|
||||||
|
template limbs*(a: StInt): untyped =
|
||||||
|
# TODO: remove this when we switch to borrow `.`
|
||||||
|
a.imp.limbs
|
||||||
|
|
||||||
template `[]`*(a: SomeBigInteger, i: SomeInteger or BackwardsIndex): Word =
|
template `[]`*(a: SomeBigInteger, i: SomeInteger or BackwardsIndex): Word =
|
||||||
a.limbs[i]
|
a.limbs[i]
|
||||||
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
# Stint
|
|
||||||
# Copyright 2018-2023 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, ./int_comparison,
|
|
||||||
./uint_addsub, ./uint_comparison
|
|
||||||
|
|
||||||
func `+`*(x, y: IntImpl): IntImpl {.inline.}=
|
|
||||||
# Addition for multi-precision signed int.
|
|
||||||
type SubTy = type x.hi
|
|
||||||
result.lo = x.lo + y.lo
|
|
||||||
result.hi = (result.lo < y.lo).toSubtype(SubTy) + x.hi + y.hi
|
|
||||||
|
|
||||||
when compileOption("boundChecks"):
|
|
||||||
if unlikely(
|
|
||||||
not(result.isNegative xor x.isNegative) or
|
|
||||||
not(result.isNegative xor y.isNegative)
|
|
||||||
):
|
|
||||||
return
|
|
||||||
raise newException(OverflowDefect, "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 {.inline.}=
|
|
||||||
# Substraction for multi-precision signed int.
|
|
||||||
|
|
||||||
type SubTy = type x.hi
|
|
||||||
result.lo = x.lo - y.lo
|
|
||||||
result.hi = x.hi - y.hi - (x.lo < y.lo).toSubtype(SubTy)
|
|
||||||
|
|
||||||
when compileOption("boundChecks"):
|
|
||||||
if unlikely(
|
|
||||||
not(result.isNegative xor x.isNegative) or
|
|
||||||
not(result.isNegative xor y.isNegative.not)
|
|
||||||
):
|
|
||||||
return
|
|
||||||
raise newException(OverflowDefect, "Substraction underflow")
|
|
||||||
|
|
||||||
func `-=`*(x: var IntImpl, y: IntImpl) {.inline.}=
|
|
||||||
## In-place substraction for multi-precision signed int.
|
|
||||||
x = x - y
|
|
|
@ -1,72 +0,0 @@
|
||||||
# Stint
|
|
||||||
# Copyright 2018-2023 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, ./bitops2_priv, ./uint_bitwise_ops, ./compiletime_cast
|
|
||||||
|
|
||||||
func `not`*(x: IntImpl): IntImpl {.inline.}=
|
|
||||||
## Bitwise complement of unsigned integer x
|
|
||||||
applyHiLo(x, `not`)
|
|
||||||
|
|
||||||
func `or`*(x, y: IntImpl): IntImpl {.inline.}=
|
|
||||||
## `Bitwise or` of numbers x and y
|
|
||||||
applyHiLo(x, y, `or`)
|
|
||||||
|
|
||||||
func `and`*(x, y: IntImpl): IntImpl {.inline.}=
|
|
||||||
## `Bitwise and` of numbers x and y
|
|
||||||
applyHiLo(x, y, `and`)
|
|
||||||
|
|
||||||
func `xor`*(x, y: IntImpl): IntImpl {.inline.}=
|
|
||||||
## `Bitwise xor` of numbers x and y
|
|
||||||
applyHiLo(x, y, `xor`)
|
|
||||||
|
|
||||||
func `shl`*(x: IntImpl, y: SomeInteger): IntImpl {.inline.}=
|
|
||||||
## Compute the `shift left` operation of x and y
|
|
||||||
# Note: inlining this poses codegen/aliasing issue when doing `x = x shl 1`
|
|
||||||
|
|
||||||
# TODO: would it be better to reimplement this with words iteration?
|
|
||||||
const halfSize: type(y) = bitsof(x) div 2
|
|
||||||
type HiType = type(result.hi)
|
|
||||||
|
|
||||||
if y == 0:
|
|
||||||
return x
|
|
||||||
elif y == halfSize:
|
|
||||||
result.hi = convert[HiType](x.lo)
|
|
||||||
elif y < halfSize:
|
|
||||||
# `shr` in this equation uses uint version
|
|
||||||
result.hi = (x.hi shl y) or convert[HiType](x.lo shr (halfSize - y))
|
|
||||||
result.lo = x.lo shl y
|
|
||||||
else:
|
|
||||||
result.hi = convert[HiType](x.lo shl (y - halfSize))
|
|
||||||
|
|
||||||
template createShr(name, operator: untyped) =
|
|
||||||
template name(x, y: SomeInteger): auto =
|
|
||||||
operator(x, y)
|
|
||||||
|
|
||||||
func name*(x: IntImpl, y: SomeInteger): IntImpl {.inline.}=
|
|
||||||
## Compute the `arithmetic shift right` operation of x and y
|
|
||||||
## Similar to C standard, result is undefined if y is bigger
|
|
||||||
## than the number of bits in x.
|
|
||||||
const halfSize: type(y) = bitsof(x) div 2
|
|
||||||
type LoType = type(result.lo)
|
|
||||||
if y == 0:
|
|
||||||
return x
|
|
||||||
elif y == halfSize:
|
|
||||||
result.lo = convert[LoType](x.hi)
|
|
||||||
result.hi = name(x.hi, halfSize-1)
|
|
||||||
elif y < halfSize:
|
|
||||||
result.lo = (x.lo shr y) or convert[LoType](x.hi shl (halfSize - y))
|
|
||||||
result.hi = name(x.hi, y)
|
|
||||||
else:
|
|
||||||
result.lo = convert[LoType](name(x.hi, (y - halfSize)))
|
|
||||||
result.hi = name(x.hi, halfSize-1)
|
|
||||||
|
|
||||||
createShr(shrOfShr, `shr`)
|
|
||||||
|
|
||||||
template `shr`*(a, b: typed): untyped =
|
|
||||||
shrOfShr(a, b)
|
|
|
@ -1,49 +0,0 @@
|
||||||
# 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_comparison
|
|
||||||
|
|
||||||
func isZero*(n: SomeSignedInt): bool {.inline.} =
|
|
||||||
n == 0
|
|
||||||
|
|
||||||
func isZero*(n: IntImpl): bool {.inline.} =
|
|
||||||
n.hi.isZero and n.lo.isZero
|
|
||||||
|
|
||||||
func isNegative*(n: SomeSignedInt): bool {.inline.} =
|
|
||||||
n < 0
|
|
||||||
|
|
||||||
func isNegative*(n: IntImpl): bool {.inline.} =
|
|
||||||
## Returns true if a number is negative:
|
|
||||||
n.hi.isNegative
|
|
||||||
|
|
||||||
func `<`*(x, y: IntImpl): bool {.inline.}=
|
|
||||||
# Lower comparison for multi-precision integers
|
|
||||||
x.hi < y.hi or
|
|
||||||
(x.hi == y.hi and x.lo < y.lo)
|
|
||||||
|
|
||||||
func `==`*(x, y: IntImpl): bool {.inline.}=
|
|
||||||
# Equal comparison for multi-precision integers
|
|
||||||
x.hi == y.hi and x.lo == y.lo
|
|
||||||
|
|
||||||
func `<=`*(x, y: IntImpl): bool {.inline.}=
|
|
||||||
# Lower or equal comparison for multi-precision integers
|
|
||||||
x.hi < y.hi or
|
|
||||||
(x.hi == y.hi and x.lo <= y.lo)
|
|
||||||
|
|
||||||
func isOdd*(x: SomeSignedInt): bool {.inline.}=
|
|
||||||
bool(x and 1)
|
|
||||||
|
|
||||||
func isEven*(x: SomeSignedInt): bool {.inline.}=
|
|
||||||
not x.isOdd
|
|
||||||
|
|
||||||
func isEven*(x: IntImpl): bool {.inline.}=
|
|
||||||
x.lo.isEven
|
|
||||||
|
|
||||||
func isOdd*(x: IntImpl): bool {.inline.}=
|
|
||||||
not x.isEven
|
|
|
@ -1,27 +0,0 @@
|
||||||
# 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_bitwise_ops, ./initialization, ./uint_highlow, typetraits
|
|
||||||
|
|
||||||
# XXX There's some Araq reason why this isn't part of the std lib..
|
|
||||||
func high(T: typedesc[SomeUnsignedInt]): T =
|
|
||||||
not T(0)
|
|
||||||
|
|
||||||
func high*[T, T2](_: typedesc[IntImpl[T, T2]]): IntImpl[T, T2] {.inline.}=
|
|
||||||
# The highest signed int has representation
|
|
||||||
# 0b0111_1111_1111_1111 ....
|
|
||||||
# so we only have to unset the most significant bit.
|
|
||||||
result.hi = high(type result.hi)
|
|
||||||
result.lo = high(type result.lo)
|
|
||||||
|
|
||||||
func low*[T, T2](_: typedesc[IntImpl[T, T2]]): IntImpl[T, T2] {.inline.}=
|
|
||||||
# The lowest signed int has representation
|
|
||||||
# 0b1000_0000_0000_0000 ....
|
|
||||||
# so we only have to set the most significant bit.
|
|
||||||
not high(IntImpl[T, T2])
|
|
|
@ -1,29 +0,0 @@
|
||||||
# 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, ./int_comparison, ./int_bitwise_ops
|
|
||||||
|
|
||||||
func `-`*(x: IntImpl): IntImpl {.inline.}=
|
|
||||||
# Negate a multi-precision signed int.
|
|
||||||
|
|
||||||
when compileOption("boundChecks"):
|
|
||||||
if unlikely(x == low(type x)):
|
|
||||||
raise newException(OverflowError, "The lowest negative number cannot be negated")
|
|
||||||
|
|
||||||
result = not x
|
|
||||||
result += one(type x)
|
|
||||||
|
|
||||||
func abs*[T: IntImpl](x: T): T {.inline.}=
|
|
||||||
## Returns the absolute value of a signed int.
|
|
||||||
|
|
||||||
result = if x.isNegative: -x
|
|
||||||
else: x
|
|
|
@ -164,7 +164,7 @@ func divRem*(
|
||||||
let rLen = bLen
|
let rLen = bLen
|
||||||
|
|
||||||
if unlikely(bBits == 0):
|
if unlikely(bBits == 0):
|
||||||
raise newException(DivByZeroError, "You attempted to divide by zero")
|
raise newException(DivByZeroDefect, "You attempted to divide by zero")
|
||||||
|
|
||||||
if aBits < bBits:
|
if aBits < bBits:
|
||||||
# if a uses less bits than b,
|
# if a uses less bits than b,
|
||||||
|
|
|
@ -5,5 +5,6 @@ template ctCheck*(cond: untyped) =
|
||||||
doAssert(cond)
|
doAssert(cond)
|
||||||
|
|
||||||
template ctTest*(name: string, body: untyped) =
|
template ctTest*(name: string, body: untyped) =
|
||||||
body
|
block:
|
||||||
echo "[OK] compile time ", name
|
body
|
||||||
|
echo "[OK] compile time ", name
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
# Stint
|
||||||
|
# Copyright 2018-2023 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 ../stint, unittest, test_helpers
|
||||||
|
|
||||||
|
#[
|
||||||
|
template chkAddition(chk, a, b, c, bits: untyped) =
|
||||||
|
block:
|
||||||
|
let x = stuint(a, bits)
|
||||||
|
let y = stuint(b, bits)
|
||||||
|
chk x + y == stuint(c, bits)
|
||||||
|
]#
|
||||||
|
|
||||||
|
template testSignedness(chk, tst: untyped) =
|
||||||
|
tst "positive sign":
|
||||||
|
let a = stint(1, 128)
|
||||||
|
chk a.sign > 0
|
||||||
|
chk a.isNegative == false
|
||||||
|
|
||||||
|
let b = stint(uint32.high, 128)
|
||||||
|
chk b.sign > 0
|
||||||
|
chk b.isNegative == false
|
||||||
|
|
||||||
|
let c = stint(uint64.high, 128)
|
||||||
|
chk c.sign > 0
|
||||||
|
chk c.isNegative == false
|
||||||
|
|
||||||
|
let aa = stint(1, 256)
|
||||||
|
chk aa.sign > 0
|
||||||
|
chk aa.isNegative == false
|
||||||
|
|
||||||
|
let bb = stint(uint32.high, 256)
|
||||||
|
chk bb.sign > 0
|
||||||
|
chk bb.isNegative == false
|
||||||
|
|
||||||
|
let cc = stint(uint64.high, 256)
|
||||||
|
chk cc.sign > 0
|
||||||
|
chk cc.isNegative == false
|
||||||
|
|
||||||
|
var zz: StInt[128]
|
||||||
|
zz.setOne
|
||||||
|
chk zz.sign > 0
|
||||||
|
chk zz.isNegative == false
|
||||||
|
|
||||||
|
let yy = StInt[128].one
|
||||||
|
chk yy.sign > 0
|
||||||
|
chk yy.isNegative == false
|
||||||
|
|
||||||
|
tst "zero sign":
|
||||||
|
let a = stint(0, 128)
|
||||||
|
chk a.sign == 0
|
||||||
|
chk a.isNegative == false
|
||||||
|
|
||||||
|
let aa = stint(0, 256)
|
||||||
|
chk aa.sign == 0
|
||||||
|
chk aa.isNegative == false
|
||||||
|
|
||||||
|
var zz: StInt[128]
|
||||||
|
zz.setZero
|
||||||
|
chk zz.sign == 0
|
||||||
|
chk zz.isNegative == false
|
||||||
|
|
||||||
|
let yy = StInt[128].zero
|
||||||
|
chk yy.sign == 0
|
||||||
|
chk yy.isNegative == false
|
||||||
|
|
||||||
|
tst "negative sign":
|
||||||
|
let a = stint(-1, 128)
|
||||||
|
chk a.sign < 0
|
||||||
|
chk a.isNegative == true
|
||||||
|
|
||||||
|
let aa = stint(-1, 256)
|
||||||
|
chk aa.sign < 0
|
||||||
|
chk aa.isNegative == true
|
||||||
|
|
||||||
|
let zz = -1.i128
|
||||||
|
chk zz.sign < 0
|
||||||
|
chk zz.isNegative == true
|
||||||
|
|
||||||
|
let yy = -1.i256
|
||||||
|
chk yy.sign < 0
|
||||||
|
chk yy.isNegative == true
|
||||||
|
|
||||||
|
tst "abs":
|
||||||
|
let a = -1.i128
|
||||||
|
let aa = a.abs
|
||||||
|
chk aa == 1.i128
|
||||||
|
|
||||||
|
let b = -1.i256
|
||||||
|
let bb = b.abs
|
||||||
|
chk bb == 1.i256
|
||||||
|
|
||||||
|
tst "negate":
|
||||||
|
var a = -1.i128
|
||||||
|
a.negate
|
||||||
|
chk a == 1.i128
|
||||||
|
|
||||||
|
var b = -1.i256
|
||||||
|
b.negate
|
||||||
|
chk b == 1.i256
|
||||||
|
|
||||||
|
let c = -1.i256
|
||||||
|
let d = -c
|
||||||
|
chk d == 1.i256
|
||||||
|
|
||||||
|
static:
|
||||||
|
testSignedness(ctCheck, ctTest)
|
||||||
|
|
||||||
|
suite "Signed integer signedness":
|
||||||
|
testSignedness(check, test)
|
Loading…
Reference in New Issue