From 97fbe56353ac46d6812b459d42a154dcd6ebbe6b Mon Sep 17 00:00:00 2001 From: mratsim Date: Wed, 25 Apr 2018 15:41:59 +0200 Subject: [PATCH] Add most significant bit and isNegative proc --- src/private/as_words.nim | 29 ++++++++++++++++++++++------- src/private/bithacks.nim | 24 +++++++++++++++++++++++- src/private/int_comparison.nim | 30 +++++++----------------------- 3 files changed, 52 insertions(+), 31 deletions(-) diff --git a/src/private/as_words.nim b/src/private/as_words.nim index 09f16cc..599fc93 100644 --- a/src/private/as_words.nim +++ b/src/private/as_words.nim @@ -30,6 +30,28 @@ proc optim(x: NimNode): NimNode = else: error "Unreachable path reached" +proc isUint(x: NimNode): static[bool] = + if eqIdent(x, "uint64"): true + elif eqIdent(x, "uint32"): true + elif eqIdent(x, "uint16"): true + elif eqIdent(x, "uint8"): true + else: false + +macro most_significant_word*(x: IntImpl): untyped = + + let optim_type = optim(x) + if optim_type.isUint: + result = quote do: + cast[`optim_type`](`x`) + else: + when system.cpuEndian == littleEndian: + let size = getSize(x) + let msw_pos = size - 1 + else: + let msw_pos = 0 + result = quote do: + cast[`optim_type`](`x`)[`msw_pos`] + proc replaceNodes(ast: NimNode, replacing: NimNode, to_replace: NimNode): NimNode = # Args: # - The full syntax tree @@ -53,13 +75,6 @@ proc replaceNodes(ast: NimNode, replacing: NimNode, to_replace: NimNode): NimNod return rTree result = inspect(ast) -proc isUint(x: NimNode): static[bool] = - if eqIdent(x, "uint64"): true - elif eqIdent(x, "uint32"): true - elif eqIdent(x, "uint16"): true - elif eqIdent(x, "uint8"): true - else: false - macro asWords*[T](n: UintImpl[T], ignoreEndianness: static[bool], loopBody: untyped): untyped = ## Iterates over n, as an array of words. ## Input: diff --git a/src/private/bithacks.nim b/src/private/bithacks.nim index 0caaa67..ad33a92 100644 --- a/src/private/bithacks.nim +++ b/src/private/bithacks.nim @@ -7,7 +7,7 @@ # # at your option. This file may not be copied, modified, or distributed except according to those terms. -import ./datatypes, stdlib_bitops +import ./datatypes, stdlib_bitops, as_words export stdlib_bitops # We reuse bitops from Nim standard lib, and expand it for multi-precision int. @@ -24,3 +24,25 @@ func countLeadingZeroBits*(n: UintImpl): int {.inline.} = result = if hi_clz == maxHalfRepr: n.lo.countLeadingZeroBits + maxHalfRepr else: hi_clz + +func msb*[T: SomeInteger](n: T): T = + ## Returns the most significant bit of an integer. + + when T is int64 or (T is int and sizeof(int) == 8): + type UInt = uint64 + elif T is int32 or (T is int and sizeof(int) == 4): + type Uint = uint32 + elif T is int16: + type Uint = uint16 + elif T is int8: + type Uint = uint8 + else: + type Uint = T + + const msb_pos = sizeof(T) * 8 - 1 + result = T(cast[Uint](n) shr msb_pos) + +func msb*(n: IntImpl): auto = + ## Returns the most significant bit of an arbitrary precision integer. + + result = msb most_significant_word(n) diff --git a/src/private/int_comparison.nim b/src/private/int_comparison.nim index 8087682..d747a06 100644 --- a/src/private/int_comparison.nim +++ b/src/private/int_comparison.nim @@ -7,34 +7,18 @@ # # at your option. This file may not be copied, modified, or distributed except according to those terms. -import ./datatypes, ./as_words, ./uint_comparison +import ./datatypes, ./bithacks, ./as_words, + ./bithacks -func isZero*(n: SomeUnsignedInt): bool {.inline.} = +func isZero*(n: SomeSignedInt): bool {.inline.} = n == 0 -func isZero*(n: UintImpl): bool {.inline.} = +func isZero*(n: IntImpl): bool {.inline.} = asWords(n, ignoreEndianness = true): if n != 0: return false return true -func `<`*(x, y: UintImpl): bool {.inline.}= - # Lower comparison for multi-precision integers - asWordsZip(x, y, ignoreEndianness = false): - if x != y: - return x < y - return false # they're equal - -func `==`*(x, y: UintImpl): bool {.inline.}= - # Equal comparison for multi-precision integers - asWordsZip(x, y, ignoreEndianness = true): - if x != y: - return false - return true # they're equal - -func `<=`*(x, y: UintImpl): bool {.inline.}= - # Lower or equal comparison for multi-precision integers - asWordsZip(x, y, ignoreEndianness = false): - if x != y: - return x < y - return true # they're equal +func isNegative*(n: IntImpl): bool {.inline.} = + ## Returns true if a number is negative: + n.msb.bool