nim-stint/stint/intops.nim

210 lines
4.8 KiB
Nim
Raw Normal View History

# Stint
2023-06-05 11:42:36 +00:00
# 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.
2023-06-13 12:03:43 +00:00
import
./private/datatypes,
./private/uint_bitwise,
./private/uint_shift,
./private/uint_addsub,
./uintops
export StInt
2023-06-13 12:03:43 +00:00
const
signMask = 1.Word shl WordBitWidth
clearSignMask = not signMask
2023-06-13 12:03:43 +00:00
# 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
2023-06-13 12:51:49 +00:00
func clearMSB(a: var StInt) =
a.limbs[0] = a.limbs[0] and clearSignMask
2023-06-13 12:03:43 +00:00
2023-06-13 12:51:49 +00:00
func setMSB(a: var StInt) =
a.limbs[0] = a.limbs[0] or signMask
2023-06-13 12:03:43 +00:00
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
2023-06-13 12:03:43 +00:00
result.setZero
func one*[bits: static[int]](T: typedesc[StInt[bits]]): T =
## Returns the one of the input type
2023-06-13 12:03:43 +00:00
result.setOne
2023-06-13 12:03:43 +00:00
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)
2023-06-13 12:51:49 +00:00
result.clearMSB
2023-06-13 12:03:43 +00:00
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
2023-06-13 12:51:49 +00:00
result.setMSB
2023-06-13 12:03:43 +00:00
{.pop.}
2023-06-13 12:03:43 +00:00
# Comparisons
# --------------------------------------------------------
{.push raises: [], inline, noinit, gcsafe.}
2023-06-13 12:03:43 +00:00
func isZero*(a: StInt): bool =
a.imp.isZero
2023-06-13 12:03:43 +00:00
func `==`*(a, b: StInt): bool =
## Unsigned `equal` comparison
a.imp == b.imp
2023-06-13 12:03:43 +00:00
func `<`*(a, b: StInt): bool =
## Unsigned `less than` comparison
2023-06-13 12:03:43 +00:00
let
aSign = a.Sign
bSign = b.Sign
2023-06-13 12:03:43 +00:00
if aSign >= 0:
if bSign < 0:
return false
elif bSign >= 0:
return true
2019-07-22 08:13:19 +00:00
2023-06-13 12:03:43 +00:00
a.imp < b.imp
2023-06-13 12:03:43 +00:00
func `<=`*(a, b: StInt): bool =
## Unsigned `less or equal` comparison
not(b < a)
2023-06-13 12:03:43 +00:00
func isOdd*(a: StInt): bool =
## Returns true if input is off
## false otherwise
2023-06-13 12:03:43 +00:00
bool(a[0] and 1)
2023-06-13 12:03:43 +00:00
func isEven*(a: StInt): bool =
## Returns true if input is zero
## false otherwise
2023-06-13 12:03:43 +00:00
not a.isOdd()
2023-06-13 12:03:43 +00:00
{.pop.}
2023-06-13 12:03:43 +00:00
# Bitwise operations
# --------------------------------------------------------
{.push raises: [], inline, noinit, gcsafe.}
2023-06-13 12:03:43 +00:00
func `not`*(a: StInt): StInt =
## Bitwise complement of unsigned integer a
## i.e. flips all bits of the input
result.imp.bitnot(a.imp)
2023-06-13 12:03:43 +00:00
func `or`*(a, b: StInt): StInt =
## `Bitwise or` of numbers a and b
result.imp.bitor(a.imp, b.imp)
2019-10-22 15:23:08 +00:00
2023-06-13 12:03:43 +00:00
func `and`*(a, b: StInt): StInt =
## `Bitwise and` of numbers a and b
result.imp.bitand(a.imp, b.imp)
2023-06-13 12:03:43 +00:00
func `xor`*(a, b: StInt): StInt =
## `Bitwise xor` of numbers x and y
result.imp.bitxor(a.imp, b.imp)
2023-06-13 12:03:43 +00:00
{.pop.} # End noInit
2023-06-13 12:03:43 +00:00
{.push raises: [], inline, gcsafe.}
2023-06-13 12:03:43 +00:00
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)
2023-06-13 12:03:43 +00:00
func `shl`*(a: StInt, k: SomeInteger): StInt =
## Shift left by k bits
result.imp.shiftLeft(a.imp, k)
2023-06-13 12:03:43 +00:00
{.pop.}
# Addsub
# --------------------------------------------------------
{.push raises: [], inline, noinit, gcsafe.}
#[
func `+`*(a, b: StInt): StInt =
## Addition for multi-precision unsigned int
result.sum(a, b)
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.}