mirror of
https://github.com/status-im/nim-stint.git
synced 2025-02-16 17:07:23 +00:00
* implement arithmetic right shift * workaround Nim VM 'cast' limitation * fix high(stint) bug * fix compile time bit shift bug * add test for compile time shift and high(stint) * add tests against ttmath
128 lines
3.5 KiB
Nim
128 lines
3.5 KiB
Nim
# 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 ../stint, unittest
|
|
|
|
when defined(cpp):
|
|
import quicktest, ttmath_compat
|
|
|
|
func high(T: typedesc[SomeUnsignedInt]): T =
|
|
not T(0)
|
|
|
|
suite "Testing signed int bitwise operations":
|
|
const
|
|
hi = high(int64)
|
|
lo = low(int64)
|
|
itercount = 1000
|
|
|
|
test "Shift Left":
|
|
var y = 1.u256
|
|
for i in 1..255:
|
|
let x = 1.i256 shl i
|
|
y = y shl 1
|
|
check cast[stint.Uint256](x) == y
|
|
|
|
test "Shift Right":
|
|
const leftMost = 1.i256 shl 255
|
|
var y = 1.u256 shl 255
|
|
for i in 1..255:
|
|
let x = leftMost shr i
|
|
y = y shr 1
|
|
check cast[stint.Uint256](x) == y
|
|
|
|
test "ashr on positive int":
|
|
const leftMost = 1.i256 shl 254
|
|
var y = 1.u256 shl 254
|
|
for i in 1..255:
|
|
let x = ashr(leftMost, i)
|
|
y = y shr 1
|
|
check x == cast[stint.Int256](y)
|
|
|
|
test "ashr on negative int":
|
|
const
|
|
leftMostU = 1.u256 shl 255
|
|
leftMostI = 1.i256 shl 255
|
|
var y = leftMostU
|
|
for i in 1..255:
|
|
let x = ashr(leftMostI, i)
|
|
y = (y shr 1) or leftMostU
|
|
check x == cast[stint.Int256](y)
|
|
|
|
test "Compile time shift":
|
|
const
|
|
# set all bits
|
|
x = high(stint.Int256) or (1.i256 shl 255)
|
|
y = not 0.i256
|
|
|
|
check x == y
|
|
|
|
const
|
|
a = (high(stint.Int256) shl 10) shr 10
|
|
b = (high(stint.Uint256) shl 10) shr 10
|
|
c = ashr(high(stint.Int256) shl 10, 10)
|
|
|
|
check a == cast[stint.Int256](b)
|
|
check c != cast[stint.Int256](b)
|
|
check c != a
|
|
|
|
when defined(cpp):
|
|
quicktest "signed int `shl` vs ttmath", itercount do(x0: int64(min=lo, max=hi),
|
|
x1: int64(min=0, max=hi),
|
|
x2: int64(min=0, max=hi),
|
|
x3: int64(min=0, max=hi),
|
|
y: int(min=0, max=(255))):
|
|
|
|
let
|
|
x = [x0, x1, x2, x3]
|
|
|
|
ttm_x = x.asTT
|
|
mp_x = cast[stint.Int256](x)
|
|
|
|
let
|
|
ttm_z = ttm_x shl y
|
|
mp_z = mp_x shl y
|
|
|
|
check ttm_z.asSt == mp_z
|
|
|
|
quicktest "signed int `shr` vs ttmath", itercount do(x0: int64(min=lo, max=hi),
|
|
x1: int64(min=0, max=hi),
|
|
x2: int64(min=0, max=hi),
|
|
x3: int64(min=0, max=hi),
|
|
y: int(min=0, max=(255))):
|
|
|
|
let
|
|
x = [cast[uint64](x0), cast[uint64](x1), cast[uint64](x2), cast[uint64](x3)]
|
|
|
|
ttm_x = x.asTT
|
|
mp_x = cast[stint.Int256](x)
|
|
|
|
let
|
|
ttm_z = ttm_x shr y.uint
|
|
mp_z = mp_x shr y
|
|
|
|
check cast[stint.Int256](ttm_z.asSt) == mp_z
|
|
|
|
quicktest "arithmetic shift right vs ttmath", itercount do(x0: int64(min=lo, max=hi),
|
|
x1: int64(min=0, max=hi),
|
|
x2: int64(min=0, max=hi),
|
|
x3: int64(min=0, max=hi),
|
|
y: int(min=0, max=(255))):
|
|
|
|
let
|
|
x = [x0, x1, x2, x3]
|
|
|
|
ttm_x = x.asTT
|
|
mp_x = cast[stint.Int256](x)
|
|
|
|
let
|
|
ttm_z = ttm_x shr y # C/CPP usually implement `shr` as `ashr` a.k.a. `sar`
|
|
mp_z = ashr(mp_x, y)
|
|
|
|
check ttm_z.asSt == mp_z
|