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.
|
||||
|
||||
import ./private/[datatypes]
|
||||
import
|
||||
./private/datatypes,
|
||||
./private/uint_bitwise,
|
||||
./private/uint_shift,
|
||||
./private/uint_addsub,
|
||||
./uintops
|
||||
|
||||
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
|
||||
discard
|
||||
|
||||
#[
|
||||
func one*[bits: static[int]](T: typedesc[StUint[bits]]): T {.inline.} =
|
||||
result.setZero
|
||||
|
||||
func one*[bits: static[int]](T: typedesc[StInt[bits]]): T =
|
||||
## 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.} =
|
||||
## Integer addition
|
||||
result.data = x.data + y.data
|
||||
func `+=`*(x: var SomeBigInteger, y: SomeBigInteger) {.inline.} =
|
||||
## Integer addition
|
||||
x.data += y.data
|
||||
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
|
||||
func low*[bits](_: typedesc[StInt[bits]]): StInt[bits] =
|
||||
# The lowest signed int has representation
|
||||
# 0b1000_0000_0000_0000 ....
|
||||
# so we only have to set the most significant bit.
|
||||
result.setZero
|
||||
result.setSign
|
||||
|
||||
import ./private/int_negabs
|
||||
{.pop.}
|
||||
|
||||
func `-`*(x: StInt): StInt {.inline.} =
|
||||
## Returns true if input is zero
|
||||
## false otherwise
|
||||
result.data = -x.data
|
||||
# Comparisons
|
||||
# --------------------------------------------------------
|
||||
{.push raises: [], inline, noinit, gcsafe.}
|
||||
|
||||
func abs*(x: StInt): StInt {.inline.} =
|
||||
## Returns true if input is zero
|
||||
## false otherwise
|
||||
result.data = abs(x.data)
|
||||
func isZero*(a: StInt): bool =
|
||||
a.imp.isZero
|
||||
|
||||
import ./private/[int_mul, uint_mul]
|
||||
|
||||
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.} =
|
||||
func `==`*(a, b: StInt): bool =
|
||||
## Unsigned `equal` comparison
|
||||
x.data == y.data
|
||||
export `<`, `<=`, `==` # Address Generic Instantiation too nested: https://github.com/status-im/nim-stint/pull/66#issuecomment-427557655
|
||||
a.imp == b.imp
|
||||
|
||||
# TODO these exports are needed for the SomeInteger versions - move to stew?
|
||||
export isZero, isOdd, isEven, isNegative
|
||||
func `<`*(a, b: StInt): bool =
|
||||
## 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
|
||||
## false otherwise
|
||||
x.data.isZero
|
||||
not a.isOdd()
|
||||
|
||||
func isNegative*(x: StInt): bool {.inline.} =
|
||||
## Returns true if input is negative (< 0)
|
||||
## false otherwise
|
||||
x.data.isNegative
|
||||
{.pop.}
|
||||
|
||||
func isOdd*(x: SomeBigInteger): bool {.inline.} =
|
||||
## Returns true if input is zero
|
||||
## false otherwise
|
||||
x.data.isOdd
|
||||
# Bitwise operations
|
||||
# --------------------------------------------------------
|
||||
{.push raises: [], inline, noinit, gcsafe.}
|
||||
|
||||
func isEven*(x: SomeBigInteger): bool {.inline.} =
|
||||
## Returns true if input is zero
|
||||
## false otherwise
|
||||
x.data.isEven
|
||||
func `not`*(a: StInt): StInt =
|
||||
## Bitwise complement of unsigned integer a
|
||||
## i.e. flips all bits of the input
|
||||
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.}=
|
||||
## Bitwise `not` i.e. flips all bits of the input
|
||||
result.data = x.data.not
|
||||
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 `xor`*(a, b: StInt): StInt =
|
||||
## `Bitwise xor` of numbers x and y
|
||||
result.imp.bitxor(a.imp, b.imp)
|
||||
|
||||
func `shr`*(x: SomeBigInteger, y: SomeInteger): SomeBigInteger {.inline.} =
|
||||
result.data = x.data shr y
|
||||
{.pop.} # End noInit
|
||||
|
||||
func `shl`*(x: SomeBigInteger, y: SomeInteger): SomeBigInteger {.inline.} =
|
||||
result.data = x.data shl y
|
||||
{.push raises: [], inline, gcsafe.}
|
||||
|
||||
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.} =
|
||||
result.data = high(type result.data)
|
||||
func high*[bits](_: typedesc[StUint[bits]]): StUint[bits] {.inline.} =
|
||||
result.data = high(type result.data)
|
||||
func `shl`*(a: StInt, k: SomeInteger): StInt =
|
||||
## Shift left by k bits
|
||||
result.imp.shiftLeft(a.imp, k)
|
||||
|
||||
func low*[bits](_: typedesc[StInt[bits]]): StInt[bits] {.inline.} =
|
||||
result.data = low(type result.data)
|
||||
func low*[bits](_: typedesc[StUint[bits]]): StUint[bits] {.inline.} =
|
||||
result.data = low(type result.data)
|
||||
{.pop.}
|
||||
|
||||
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
|
||||
when x.data is UintImpl:
|
||||
result.data = x.data.pow(y)
|
||||
else:
|
||||
result.data = x.data ^ y
|
||||
#[
|
||||
func `+`*(a, b: StInt): StInt =
|
||||
## Addition for multi-precision unsigned int
|
||||
result.sum(a, b)
|
||||
|
||||
func pow*(x: StUint, y: StUint): StUint {.inline.} =
|
||||
## Returns x raised at the power of y
|
||||
when x.data is UintImpl:
|
||||
result.data = x.data.pow(y.data)
|
||||
else:
|
||||
result.data = x.data ^ y.data
|
||||
]#
|
||||
func `+=`*(a: var StInt, b: StInt) =
|
||||
## In-place addition for multi-precision unsigned int
|
||||
a.sum(a, b)
|
||||
|
||||
func `-`*(a, b: StInt): StInt =
|
||||
## 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.}=
|
||||
## Converts an integer to an arbitrary precision integer.
|
||||
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)
|
||||
else:
|
||||
result.limbs[0] = Word(n)
|
||||
result.limbs[0] = Word(n)
|
||||
|
||||
# func stint*[T: SomeInteger](n: T, bits: static[int]): StInt[bits] {.inline.}=
|
||||
# ## Converts an integer to an arbitrary precision signed integer.
|
||||
#
|
||||
# when result.data is IntImpl:
|
||||
# static_check_size(T, bits)
|
||||
# when T is SomeSignedInt:
|
||||
# if n < 0:
|
||||
# # TODO: when bits >= 128, cannot create from
|
||||
# # low(int8-64)
|
||||
# # see: status-im/nim-stint/issues/92
|
||||
# assignLo(result.data, -n)
|
||||
# result = -result
|
||||
# else:
|
||||
# assignLo(result.data, n)
|
||||
# else:
|
||||
# assignLo(result.data, n)
|
||||
# else:
|
||||
# result.data = (type result.data)(n)
|
||||
func stint*[T: SomeInteger](n: T, bits: static[int]): StInt[bits] {.inline.}=
|
||||
## Converts an integer to an arbitrary precision signed integer.
|
||||
when T is SomeUnsignedInt:
|
||||
result.imp = stuint(n, bits)
|
||||
else:
|
||||
if n < 0:
|
||||
result.imp = stuint(-n, bits)
|
||||
result.negate
|
||||
else:
|
||||
result.imp = stuint(n, bits)
|
||||
|
||||
# func to*(a: SomeInteger, T: typedesc[Stint]): T =
|
||||
# stint(a, result.bits)
|
||||
func to*(a: SomeInteger, T: typedesc[Stint]): T =
|
||||
stint(a, result.bits)
|
||||
|
||||
func to*(a: SomeUnsignedInt, T: typedesc[StUint]): T =
|
||||
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.
|
||||
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.} =
|
||||
## unsigned int to unsigned int conversion
|
||||
## 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)
|
||||
|
||||
# func toString*[bits: static[int]](num: Stint[bits], radix: static[int8] = 10): string =
|
||||
# ## Convert a Stint or StUint to string.
|
||||
# ## In case of negative numbers:
|
||||
# ## - they are prefixed with "-" for base 10.
|
||||
# ## - if not base 10, they are returned raw in two-complement form.
|
||||
func toString*[bits: static[int]](num: StInt[bits], radix: static[int8] = 10): string =
|
||||
## Convert a Stint or StUint to string.
|
||||
## In case of negative numbers:
|
||||
## - they are prefixed with "-" for base 10.
|
||||
## - 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"
|
||||
# # TODO: use static[range[2 .. 16]], not supported at the moment (2018-04-26)
|
||||
|
||||
# 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 `$`*(num: StInt or StUint): string {.inline.}=
|
||||
toString(num, 10)
|
||||
|
||||
func toHex*[bits: static[int]](num: StInt[bits] or StUint[bits]): string {.inline.}=
|
||||
## Convert to a hex string.
|
||||
|
|
|
@ -40,7 +40,7 @@ type
|
|||
StInt*[bits: static[int]] = object
|
||||
## Stack-based integer
|
||||
## Signed
|
||||
limbs*: array[bits.wordsRequired, Word]
|
||||
imp*: StUint[bits]
|
||||
|
||||
# {.borrow: `.`.} only works with nim-devel
|
||||
# StInt*[bits: static[int]] {.borrow: `.`.} = distinct StUint[bits]
|
||||
|
@ -94,6 +94,10 @@ func usedBitsAndWords*(a: openArray[Word]): tuple[bits, words: int] =
|
|||
# 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 =
|
||||
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
|
||||
|
||||
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 a uses less bits than b,
|
||||
|
|
|
@ -5,5 +5,6 @@ template ctCheck*(cond: untyped) =
|
|||
doAssert(cond)
|
||||
|
||||
template ctTest*(name: string, body: untyped) =
|
||||
body
|
||||
echo "[OK] compile time ", name
|
||||
block:
|
||||
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