diff --git a/include/intx/int128.hpp b/include/intx/int128.hpp index 5721f1a7..d514e5c6 100644 --- a/include/intx/int128.hpp +++ b/include/intx/int128.hpp @@ -69,57 +69,77 @@ struct uint<128> using uint128 = uint<128>; -template -struct uint_with_carry +/// Contains result of add/sub/etc with a carry flag. +template +struct result_with_carry { - uint value; + T value; bool carry; + + /// Conversion to tuple of referecences, to allow usage with std::tie(). + operator std::tuple() noexcept { return {value, carry}; } }; /// Linear arithmetic operators. /// @{ -constexpr uint_with_carry<128> add_with_carry(uint128 a, uint128 b) noexcept +constexpr inline result_with_carry add_with_carry( + uint64_t x, uint64_t y, bool carry = false) noexcept { - const auto lo = a.lo + b.lo; - const auto lo_carry = lo < a.lo; - const auto t = a.hi + b.hi; - const auto carry1 = t < a.hi; - const auto hi = t + lo_carry; - const auto carry2 = hi < t; - return {{hi, lo}, carry1 || carry2}; + const auto s = x + y; + const auto carry1 = s < x; + const auto t = s + carry; + const auto carry2 = t < s; + return {t, carry1 || carry2}; } -constexpr uint128 operator+(uint128 x, uint128 y) noexcept +template +constexpr result_with_carry> add_with_carry( + const uint& a, const uint& b, bool carry = false) noexcept +{ + const auto lo = add_with_carry(a.lo, b.lo, carry); + const auto hi = add_with_carry(a.hi, b.hi, lo.carry); + return {{hi.value, lo.value}, hi.carry}; +} + +constexpr inline uint128 operator+(uint128 x, uint128 y) noexcept { return add_with_carry(x, y).value; } -constexpr uint128 operator+(uint128 x) noexcept +constexpr inline uint128 operator+(uint128 x) noexcept { return x; } -/// Performs subtraction of two unsinged numbers and returns the difference +constexpr inline result_with_carry sub_with_carry( + uint64_t x, uint64_t y, bool carry = false) noexcept +{ + const auto d = x - y; + const auto carry1 = d > x; + const auto e = d - carry; + const auto carry2 = e > d; + return {e, carry1 || carry2}; +} + +/// Performs subtraction of two unsigned numbers and returns the difference /// and the carry bit (aka borrow, overflow). -constexpr uint_with_carry<128> sub_with_carry(uint128 a, uint128 b) noexcept +template +constexpr inline result_with_carry> sub_with_carry( + const uint& a, const uint& b, bool carry = false) noexcept { - const auto lo = a.lo - b.lo; - const auto lo_borrow = lo > a.lo; - const auto t = a.hi - b.hi; - const auto borrow1 = t > a.hi; - const auto hi = t - lo_borrow; - const auto borrow2 = hi > t; - return {{hi, lo}, borrow1 || borrow2}; + const auto lo = sub_with_carry(a.lo, b.lo, carry); + const auto hi = sub_with_carry(a.hi, b.hi, lo.carry); + return {{hi.value, lo.value}, hi.carry}; } -constexpr uint128 operator-(uint128 x, uint128 y) noexcept +constexpr inline uint128 operator-(uint128 x, uint128 y) noexcept { return sub_with_carry(x, y).value; } -constexpr uint128 operator-(uint128 x) noexcept +constexpr inline uint128 operator-(uint128 x) noexcept { // Implementing as subtraction is better than ~x + 1. // Clang9: Perfect. diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp index 16cf695e..bd3b8455 100644 --- a/include/intx/intx.hpp +++ b/include/intx/intx.hpp @@ -1,5 +1,5 @@ // intx: extended precision integer library. -// Copyright 2019 Pawel Bylica. +// Copyright 2019-2020 Pawel Bylica. // Licensed under the Apache License, Version 2.0. #pragma once @@ -410,27 +410,6 @@ inline uint shl_loop(const uint& x, unsigned shift) return r; } - -template -constexpr uint_with_carry add_with_carry(const uint& a, const uint& b) noexcept -{ - const auto lo = add_with_carry(a.lo, b.lo); - const auto tt = add_with_carry(a.hi, b.hi); - const auto hi = add_with_carry(tt.value, typename uint::half_type{lo.carry}); - return {{hi.value, lo.value}, tt.carry || hi.carry}; -} - -/// Performs subtraction of two unsinged numbers and returns the difference -/// and the carry bit (aka borrow, overflow). -template -constexpr uint_with_carry sub_with_carry(const uint& a, const uint& b) noexcept -{ - const auto lo = sub_with_carry(a.lo, b.lo); - const auto tt = sub_with_carry(a.hi, b.hi); - const auto hi = sub_with_carry(tt.value, typename uint::half_type{lo.carry}); - return {{hi.value, lo.value}, tt.carry || hi.carry}; -} - template inline uint add_loop(const uint& a, const uint& b) noexcept {