From c65ab165124c2633ebdefb8269f9abb914d37750 Mon Sep 17 00:00:00 2001 From: mratsim Date: Mon, 26 Mar 2018 12:45:10 +0200 Subject: [PATCH] Conversion fixes for tmp) + y.hi + x.hi -= (x.lo > tmp).toSubtype(SubTy) + y.hi proc `-`*(x, y: MpUintImpl): MpUintImpl {.noSideEffect, noInit, inline.}= # Substraction for multi-precision unsigned int result = x result -= y -template naiveMulImpl[T: MpUintImpl](x, y: T): MpUintImpl[T] = + +proc naiveMulImpl[T: MpUintImpl](x, y: T): MpUintImpl[T] {.noSideEffect, noInit, inline.} + # Forward declaration + +proc naiveMul[T: BaseUint](x, y: T): MpUintImpl[T] {.noSideEffect, noInit, inline.}= + ## Naive multiplication algorithm with extended precision + + when T.sizeof in {1, 2, 4}: + # Use types twice bigger to do the multiplication + cast[type result](x.asDoubleUint * y.asDoubleUint) + + elif T.sizeof == 8: # uint64 or MpUint[uint32] + # We cannot double uint64 to uint128 + naiveMulImpl(x.toMpUintImpl, y.toMpUintImpl) + else: + # Case: at least uint128 * uint128 --> uint256 + naiveMulImpl(x, y) + + +proc naiveMulImpl[T: MpUintImpl](x, y: T): MpUintImpl[T] {.noSideEffect, noInit, inline.}= # See details at # https://en.wikipedia.org/wiki/Karatsuba_algorithm # https://locklessinc.com/articles/256bit_arithmetic/ @@ -66,27 +85,12 @@ template naiveMulImpl[T: MpUintImpl](x, y: T): MpUintImpl[T] = var z1 = tmp z1 += naiveMul(x.hi, y.lo) - let z2 = (z1 < tmp).T + naiveMul(x.hi, y.hi) + let z2 = (z1 < tmp).toSubtype(T) + naiveMul(x.hi, y.hi) let tmp2 = z1.lo shl halfSize result.lo = tmp2 result.lo += z0 - result.hi = (result.lo < tmp2).T + z2 + z1.hi - -proc naiveMul[T: BaseUint](x, y: T): MpUintImpl[T] {.noSideEffect, noInit, inline.}= - ## Naive multiplication algorithm with extended precision - - when T.sizeof in {1, 2, 4}: - # Use types twice bigger to do the multiplication - cast[type result](x.asDoubleUint * y.asDoubleUint) - - elif T.sizeof == 8: # uint64 or MpUint[uint32] - # We cannot double uint64 to uint128 - naiveMulImpl(x.toMpUint, y.toMpUint) - else: - # Case: at least uint128 * uint128 --> uint256 - naiveMulImpl(x, y) - + result.hi = (result.lo < tmp2).toSubtype(T) + z2 + z1.hi proc `*`*(x, y: MpUintImpl): MpUintImpl {.noSideEffect, noInit.}= ## Multiplication for multi-precision unsigned uint diff --git a/src/private/uint_comparison.nim b/src/private/uint_comparison.nim index 36ae35e..919a62b 100644 --- a/src/private/uint_comparison.nim +++ b/src/private/uint_comparison.nim @@ -17,8 +17,8 @@ proc `<=`*(x, y: MpUintImpl): bool {.noSideEffect, noInit, inline.}= result = if x == y: true else: x < y -proc isZero[T: SomeUnsignedInt](n: T): bool {.noSideEffect,inline.} = - n == 0.T +proc isZero*(n: SomeUnsignedInt): bool {.noSideEffect,inline.} = + n == 0 proc isZero*(n: MpUintImpl): bool {.noSideEffect,inline.} = n.lo.isZero and n.hi.isZero diff --git a/src/uint_init.nim b/src/uint_init.nim index b8861cb..9aa8986 100644 --- a/src/uint_init.nim +++ b/src/uint_init.nim @@ -14,15 +14,15 @@ import ./private/bithacks, ./private/conversion, import typetraits -proc initMpUint*(n: SomeUnsignedInt, bits: static[int]): MpUint[bits] {.noSideEffect.} = - +proc initMpUint*(n: SomeInteger, bits: static[int]): MpUint[bits] {.noSideEffect.} = + assert n >= 0 when result.data is MpuintImpl: type SubTy = type result.data.lo let len = n.bit_length if len > bits: - # Todo print n - raise newException(ValueError, "Input cannot be stored in a multi-precision " & $bits & "-bit integer." & + raise newException(ValueError, "Input " & $n & " cannot be stored in a multi-precision " & + $bits & "-bit integer." & "\nIt requires at least " & $len & " bits of precision") elif len < bits div 2: result.data.lo = SubTy(n) @@ -35,12 +35,6 @@ proc initMpUint*(n: SomeUnsignedInt, bits: static[int]): MpUint[bits] {.noSideEf elif bits == 64: result.data = toMpUintImpl n.uint64 else: - {.fatal, "unreachable".} + raise newException(ValueError, "Fatal") else: result.data = (type result.data)(n) - -proc u128*(n: SomeUnsignedInt): MpUint[128] {.noSideEffect, inline, noInit.}= - initMpUint[128](n) - -proc u256*(n: SomeUnsignedInt): MpUint[256] {.noSideEffect, inline, noInit.}= - initMpUint[256](n) diff --git a/src/uint_public.nim b/src/uint_public.nim index 51e18e5..83adac5 100644 --- a/src/uint_public.nim +++ b/src/uint_public.nim @@ -14,6 +14,13 @@ type UInt128* = MpUint[128] UInt256* = MpUint[256] +template make_conv(conv_name: untyped, size: int): untyped = + proc `convname`*(n: SomeInteger): MpUint[size] {.noSideEffect, inline, noInit.}= + n.initMpUint(size) + +make_conv(u128, 128) +make_conv(u256, 256) + template make_unary(op, ResultTy): untyped = proc `op`*(x: MpUint): ResultTy {.noInit, inline, noSideEffect.} = when resultTy is MpUint: