From 0296b5eca925e8026dafdf01df99e282b882663b Mon Sep 17 00:00:00 2001 From: mratsim Date: Wed, 25 Apr 2018 19:51:14 +0200 Subject: [PATCH] Add sub, proper negate bound checking, high and low, most significant word mutation --- src/private/as_signed_words.nim | 4 +-- src/private/int_addsubneg.nim | 45 +++++++++++++++++++++++++-------- src/private/int_highlow.nim | 30 ++++++++++++++++++++++ src/private/uint_highlow.nim | 16 ++++++++++++ 4 files changed, 82 insertions(+), 13 deletions(-) create mode 100644 src/private/int_highlow.nim create mode 100644 src/private/uint_highlow.nim diff --git a/src/private/as_signed_words.nim b/src/private/as_signed_words.nim index fd8e973..846ce42 100644 --- a/src/private/as_signed_words.nim +++ b/src/private/as_signed_words.nim @@ -43,7 +43,7 @@ macro most_significant_word*(x: IntImpl): untyped = let optim_type = optimInt(x) if optim_type.isInt: result = quote do: - cast[`optim_type`](`x`) + (cast[ptr `optim_type`](`x`.unsafeAddr))[] else: when system.cpuEndian == littleEndian: let size = getSize(x) @@ -51,7 +51,7 @@ macro most_significant_word*(x: IntImpl): untyped = else: let msw_pos = 0 result = quote do: - cast[`optim_type`](`x`)[`msw_pos`] + (cast[ptr `optim_type`](`x`)[`msw_pos`.unsafeAddr])[] macro asSignedWordsZip*[T]( x, y: IntImpl[T], diff --git a/src/private/int_addsubneg.nim b/src/private/int_addsubneg.nim index 6a68b5a..9b987dd 100644 --- a/src/private/int_addsubneg.nim +++ b/src/private/int_addsubneg.nim @@ -7,20 +7,43 @@ # # at your option. This file may not be copied, modified, or distributed except according to those terms. -import ./datatypes, ./int_bitwise_ops, ./initialization +import ./datatypes, ./int_bitwise_ops, + ./initialization, ./as_signed_words, ./int_highlow -func `+=`*(x: var IntImpl, y: IntImpl) {.inline.}= - ## In-place addition for multi-precision signed int - - type SubTy = type x.lo - x.lo += y.lo - x.hi += (x.lo < y.lo).toSubtype(SubTy) + y.hi - -func `+`*(x, y: UintImpl): UintImpl {.noInit, inline.}= +func `+`*(x, y: IntImpl): IntImpl {.noInit, inline.}= # Addition for multi-precision signed int - result = x - result += y + type SubTy = type x.lo + result.lo = x.lo + y.lo + result.hi = (x.lo < y.lo).toSubtype(SubTy) + x.hi + y.hi + + when compileOption("boundChecks"): + if unlikely( + (result.most_significant_word xor a.most_significant_word >= 0) or + (result.most_significant_word xor b.most_significant_word >= 0) + ): + raise newException(OverflowError, "Addition overflow") func `-`*[T: IntImpl](x: T): T {.noInit, inline.}= result = not x result += one(T) + when compileOption("boundChecks"): + if unlikely(x == low(T)): + raise newException(OverflowError, "The lowest negative number cannot be negated") + +func `-`*(x, y: IntImpl): IntImpl {.noInit, inline.}= + # Substraction for multi-precision signed int + + type SubTy = type x.lo + result.lo = x.lo - y.lo + result.hi = x.hi - y.hi - (x.lo < y.lo).toSubtype(SubTy) + + when compileOption("boundChecks"): + if unlikely( + (result.most_significant_word xor a.most_significant_word >= 0) or + (result.most_significant_word xor (not b).most_significant_word >= 0) + ): + raise newException(OverflowError, "Substraction underflow") + +func `-=`*(x: var IntImpl, y: IntImpl) {.inline.}= + ## In-place substraction for multi-precision signed int + x = x - y diff --git a/src/private/int_highlow.nim b/src/private/int_highlow.nim new file mode 100644 index 0000000..8f08e0c --- /dev/null +++ b/src/private/int_highlow.nim @@ -0,0 +1,30 @@ +# Mpint +# 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 ./datatypes, ./as_signed_words + +func low*(T: typedesc[UintImpl]): T {.inline.}= + + # The lowest signed int has representation + # 0b1000_0000_0000_0000 .... + # so we only have to set the most significant bit. + type Msw = type result.most_significant_word + when Msw is uint64: + type U = int64 + else: + type U = Msw + + result.most_significant_word = low(U) + +func high*(T: typedesc[UintImpl]): T {.inline, noInit.}= + + # The lowest signed int has representation + # 0b0111_1111_1111_1111 .... + # so we only have to unset the most significant bit. + not low(T) diff --git a/src/private/uint_highlow.nim b/src/private/uint_highlow.nim new file mode 100644 index 0000000..c9354e6 --- /dev/null +++ b/src/private/uint_highlow.nim @@ -0,0 +1,16 @@ +# Mpint +# 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 ./datatypes, ./initialization + +func low*(T: typedesc[UintImpl]): T {.inline, noInit.}= + zero(T) + +func high*(T: typedesc[UintImpl]): T {.inline, noInit.}= + not zero(T)