diff --git a/src/mpint.nim b/src/mpint.nim index 66e75aa..b44d556 100644 --- a/src/mpint.nim +++ b/src/mpint.nim @@ -2,7 +2,9 @@ # Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT). import ./uint_type, - ./uint_init + ./uint_init, + ./uint_binary_ops export uint_type, - uint_init \ No newline at end of file + uint_init, + uint_binary_ops \ No newline at end of file diff --git a/src/uint_binary_ops.nim b/src/uint_binary_ops.nim new file mode 100644 index 0000000..d49866e --- /dev/null +++ b/src/uint_binary_ops.nim @@ -0,0 +1,19 @@ +# Copyright (c) 2018 Status Research & Development GmbH +# Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT). + +import uint_type + +proc `+=`*[T: MpUint](a: var T, b: T) {.noSideEffect.}= + + type Base = type a.lo + let tmp = a.lo + + a.lo += b.lo + a.hi += (a.lo < tmp).Base + b.hi + # Optimized assembly should contain adc instruction (add with carry) + # Clang on MacOS does with the -d:release switch. + +proc `+`*[T: MpUint](a: T, b: T): T {.noSideEffect, noInit.}= + + result = a + result += b \ No newline at end of file diff --git a/tests/all_tests.nim b/tests/all_tests.nim index 07c0632..88567f7 100644 --- a/tests/all_tests.nim +++ b/tests/all_tests.nim @@ -1,4 +1,5 @@ # Copyright (c) 2018 Status Research & Development GmbH # Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT).$ -import test_endianness \ No newline at end of file +import test_endianness, + test_addition \ No newline at end of file diff --git a/tests/test_addition.nim b/tests/test_addition.nim new file mode 100644 index 0000000..a053962 --- /dev/null +++ b/tests/test_addition.nim @@ -0,0 +1,46 @@ +# Copyright (c) 2018 Status Research & Development GmbH +# Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT). + +import ../src/mpint, unittest + +suite "Testing addition implementation": + test "In-place addition gives expected result": + + var a = initMpUint(20182018, uint32) + let b = initMpUint(20172017, uint32) + + a += b + + check: cast[uint64](a) == 20182018'u64 + 20172017'u64 + + test "Addition gives expected result": + + let a = initMpUint(20182018, uint32) + let b = initMpUint(20172017, uint32) + + check: cast[uint64](a+b) == 20182018'u64 + 20172017'u64 + + test "When the low half overflows, it is properly carried": + # uint8 (low half) overflow at 255 + let a = initMpUint(100, uint8) + let b = initMpUint(100, uint8) + + check: cast[uint16](a+b) == 200 + + test "Full overflow is handled like native unsigned types": + # uint16 overflows after 65535 + let a = initMpUint(100, uint8) + var z = initMpUint(0, uint8) + let o = initMpUint(36, uint8) + + for _ in 0 ..< 655: + z += a + + check: cast[uint16](z) == 65500 + check: cast[uint16](z + o) == 0 + + z += a + check: cast[uint16](z) == 64 + + z += a + check: cast[uint16](z) == 164 \ No newline at end of file