diff --git a/stint/private/datatypes.nim b/stint/private/datatypes.nim index 46da4be..2dd4e67 100644 --- a/stint/private/datatypes.nim +++ b/stint/private/datatypes.nim @@ -16,7 +16,7 @@ when sizeof(int) == 8 and not defined(Stint32): else: type Word* = uint32 -type Word* = uint32 +const WordBitWidth = sizeof(Word) * 8 func wordsRequired*(bits: int): int {.compileTime.} = ## Compute the number of limbs required @@ -24,7 +24,7 @@ func wordsRequired*(bits: int): int {.compileTime.} = (bits + WordBitWidth - 1) div WordBitWidth type - Limbs*[N: static int] = array[N, BaseUint] + Limbs*[N: static int] = array[N, Word] StUint*[bits: static[int]] = object ## Stack-based integer @@ -60,3 +60,39 @@ func mostSignificantWord*(limbs: Limbs): auto {.inline.} = limbs[^1] else: limbs[0] + +iterator leastToMostSig*(limbs: Limbs): Word = + ## Iterate from least to most significant word + when cpuEndian == littleEndian: + for i in 0 ..< limbs.len: + yield limbs[i] + else: + for i in countdown(limbs.len-1, 0): + yield limbs[i] + +iterator leastToMostSig*(limbs: var Limbs): var Word = + ## Iterate from least to most significant word + when cpuEndian == littleEndian: + for i in 0 ..< limbs.len: + yield limbs[i] + else: + for i in countdown(limbs.len-1, 0): + yield limbs[i] + +iterator leastToMostSig*(aLimbs, bLimbs: Limbs): (Word, Word) = + ## Iterate from least to most significant word + when cpuEndian == littleEndian: + for i in 0 ..< limbs.len: + yield (aLimbs[i], bLimbs[i]) + else: + for i in countdown(limbs.len-1, 0): + yield (aLimbs[i], bLimbs[i]) + +iterator leastToMostSig*(aLimbs: var Limbs, bLimbs: Limbs): (var Word, Word) = + ## Iterate from least to most significant word + when cpuEndian == littleEndian: + for i in 0 ..< limbs.len: + yield (aLimbs[i], bLimbs[i]) + else: + for i in countdown(limbs.len-1, 0): + yield (aLimbs[i], bLimbs[i]) diff --git a/stint/private/uint_comparison.nim b/stint/private/uint_comparison.nim index 2364e5c..eafa9b0 100644 --- a/stint/private/uint_comparison.nim +++ b/stint/private/uint_comparison.nim @@ -7,36 +7,46 @@ # # at your option. This file may not be copied, modified, or distributed except according to those terms. -import ./datatypes +import + ./datatypes, + ./primitives/addcarry_subborrow func isZero*(n: SomeUnsignedInt): bool {.inline.} = n == 0 -func isZero*(n: UintImpl): bool {.inline.} = - n.hi.isZero and n.lo.isZero +func isZero*(limbs: Limbs): bool {.inline.} = + for word in limbs: + if not word.isZero(): + return false + return true -func `<`*(x, y: UintImpl): bool {.inline.}= +func `<`*(x, y: Limbs): bool {.inline.}= # Lower comparison for multi-precision integers - x.hi < y.hi or - (x.hi == y.hi and x.lo < y.lo) + var diff: Word + var borrow: Borrow + for wx, wy in leastToMostSig(x, y): + subB(borrow, diff, wx, wy, borrow) + return bool(borrow) -func `==`*(x, y: UintImpl): bool {.inline.}= +func `==`*(x, y: Limbs): bool {.inline.}= # Equal comparison for multi-precision integers - x.hi == y.hi and x.lo == y.lo + for wx, wy in leastToMostSig(x, y): + if wx != wy: + return false + return true -func `<=`*(x, y: UintImpl): bool {.inline.}= +func `<=`*(x, y: Limbs): bool {.inline.}= # Lower or equal comparison for multi-precision integers - x.hi < y.hi or - (x.hi == y.hi and x.lo <= y.lo) + not(y < x) func isEven*(x: SomeUnsignedInt): bool {.inline.} = (x and 1) == 0 -func isEven*(x: UintImpl): bool {.inline.}= - x.lo.isEven +func isEven*(x: Limbs): bool {.inline.}= + x.leastSignificantWord.isEven func isOdd*(x: SomeUnsignedInt): bool {.inline.} = not x.isEven -func isOdd*(x: UintImpl): bool {.inline.}= +func isOdd*(x: Limbs): bool {.inline.}= not x.isEven