fix #81 remove ashr from API and fix shr on Nim 0.20

This commit is contained in:
andri lim 2019-08-06 20:25:48 +07:00
parent d154bcf90a
commit 173699583b
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
3 changed files with 44 additions and 71 deletions

View File

@ -130,8 +130,6 @@ func `shr`*(x: SomeBigInteger, y: SomeInteger): SomeBigInteger {.inline.} =
result.data = x.data shr y result.data = x.data shr y
func `shl`*(x: SomeBigInteger, y: SomeInteger): SomeBigInteger {.inline.} = func `shl`*(x: SomeBigInteger, y: SomeInteger): SomeBigInteger {.inline.} =
result.data = x.data shl y result.data = x.data shl y
func ashr*(x: Stint, y: SomeInteger): Stint {.inline.} =
result.data = ashr(x.data, y)
import ./private/[int_highlow, uint_highlow] import ./private/[int_highlow, uint_highlow]

View File

@ -25,9 +25,6 @@ func `xor`*(x, y: IntImpl): IntImpl {.inline.}=
## `Bitwise xor` of numbers x and y ## `Bitwise xor` of numbers x and y
applyHiLo(x, y, `xor`) applyHiLo(x, y, `xor`)
func `shr`*(x: IntImpl, y: SomeInteger): IntImpl {.inline.}
# Forward declaration
func convertImpl[T: SomeInteger](x: SomeInteger): T {.compileTime.} = func convertImpl[T: SomeInteger](x: SomeInteger): T {.compileTime.} =
cast[T](x) cast[T](x)
@ -56,42 +53,46 @@ func `shl`*(x: IntImpl, y: SomeInteger): IntImpl {.inline.}=
elif y == halfSize: elif y == halfSize:
result.hi = convert[HiType](x.lo) result.hi = convert[HiType](x.lo)
elif y < halfSize: 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.hi = (x.hi shl y) or convert[HiType](x.lo shr (halfSize - y))
result.lo = x.lo shl y result.lo = x.lo shl y
else: else:
result.hi = convert[HiType](x.lo shl (y - halfSize)) result.hi = convert[HiType](x.lo shl (y - halfSize))
func `shr`*(x: IntImpl, y: SomeInteger): IntImpl {.inline.}= template createShr(name, operator: untyped) =
## Compute the `shift right` operation of x and y template name(x, y: SomeInteger): auto =
## Similar to C standard, result is undefined if y is bigger operator(x, y)
## than the number of bits in x.
const halfSize: type(y) = bitsof(x) div 2
type LoType = type(result.lo)
if y == 0: func name*(x: IntImpl, y: SomeInteger): IntImpl {.inline.}=
return x ## Compute the `arithmetic shift right` operation of x and y
elif y == halfSize: ## Similar to C standard, result is undefined if y is bigger
result.lo = convert[LoType](x.hi) ## than the number of bits in x.
elif y < halfSize: const halfSize: type(y) = bitsof(x) div 2
result.lo = (x.lo shr y) or convert[LoType](x.hi shl (halfSize - y)) type LoType = type(result.lo)
result.hi = x.hi shr y if y == 0:
else: return x
result.lo = convert[LoType](x.hi shr (y - halfSize)) 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)
func ashr*(x: IntImpl, y: SomeInteger): IntImpl {.inline.}= template nimVersionIs(comparator: untyped, major, minor, patch: int): bool =
## Compute the `arithmetic shift right` operation of x and y comparator(NimMajor * 100 + NimMinor * 10 + NimPatch, major * 100 + minor * 10 + patch)
## Similar to C standard, result is undefined if y is bigger
## than the number of bits in x. when nimVersionIs(`>=`, 0, 20, 0):
const halfSize: type(y) = bitsof(x) div 2 createShr(shrOfShr, `shr`)
type LoType = type(result.lo) elif nimVersionIs(`<`, 0, 20, 0) and defined(nimAshr):
if y == 0: createShr(shrOfAshr, ashr)
return x else:
elif y == halfSize: {.error: "arithmetic right shift is not defined for this Nim version".}
result.lo = convert[LoType](x.hi)
result.hi = ashr(x.hi, halfSize-1) template `shr`*(a, b: typed): untyped =
elif y < halfSize: when nimVersionIs(`>=`, 0, 20, 0):
result.lo = (x.lo shr y) or convert[LoType](x.hi shl (halfSize - y)) shrOfShr(a, b)
result.hi = ashr(x.hi, y) elif nimVersionIs(`<`, 0, 20, 0) and defined(nimAshr):
else: shrOfAShr(a, b)
result.lo = convert[LoType](ashr(x.hi, (y - halfSize)))
result.hi = ashr(x.hi, halfSize-1)

View File

@ -28,29 +28,21 @@ suite "Testing signed int bitwise operations":
y = y shl 1 y = y shl 1
check cast[stint.Uint256](x) == y check cast[stint.Uint256](x) == y
test "Shift Right": test "Shift Right on positive int":
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 const leftMost = 1.i256 shl 254
var y = 1.u256 shl 254 var y = 1.u256 shl 254
for i in 1..255: for i in 1..255:
let x = ashr(leftMost, i) let x = leftMost shr i
y = y shr 1 y = y shr 1
check x == cast[stint.Int256](y) check x == cast[stint.Int256](y)
test "ashr on negative int": test "Shift Right on negative int":
const const
leftMostU = 1.u256 shl 255 leftMostU = 1.u256 shl 255
leftMostI = 1.i256 shl 255 leftMostI = 1.i256 shl 255
var y = leftMostU var y = leftMostU
for i in 1..255: for i in 1..255:
let x = ashr(leftMostI, i) let x = leftMostI shr i
y = (y shr 1) or leftMostU y = (y shr 1) or leftMostU
check x == cast[stint.Int256](y) check x == cast[stint.Int256](y)
@ -65,11 +57,11 @@ suite "Testing signed int bitwise operations":
const const
a = (high(stint.Int256) shl 10) shr 10 a = (high(stint.Int256) shl 10) shr 10
b = (high(stint.Uint256) shl 10) shr 10 b = (high(stint.Uint256) shl 10) shr 10
c = ashr(high(stint.Int256) shl 10, 10) c = (high(stint.Int256) shl 10) shr 10
check a == cast[stint.Int256](b) check a != cast[stint.Int256](b)
check c != cast[stint.Int256](b) check c != cast[stint.Int256](b)
check c != a check c == a
when defined(cpp): when defined(cpp):
quicktest "signed int `shl` vs ttmath", itercount do(x0: int64(min=lo, max=hi), quicktest "signed int `shl` vs ttmath", itercount do(x0: int64(min=lo, max=hi),
@ -90,24 +82,6 @@ suite "Testing signed int bitwise operations":
check ttm_z.asSt == mp_z 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), quicktest "arithmetic shift right vs ttmath", itercount do(x0: int64(min=lo, max=hi),
x1: int64(min=0, max=hi), x1: int64(min=0, max=hi),
x2: int64(min=0, max=hi), x2: int64(min=0, max=hi),
@ -122,6 +96,6 @@ suite "Testing signed int bitwise operations":
let let
ttm_z = ttm_x shr y # C/CPP usually implement `shr` as `ashr` a.k.a. `sar` ttm_z = ttm_x shr y # C/CPP usually implement `shr` as `ashr` a.k.a. `sar`
mp_z = ashr(mp_x, y) mp_z = mp_x shr y
check ttm_z.asSt == mp_z check ttm_z.asSt == mp_z