From 6ce29f52ee585e8de8c001eb9aeda8f780a619b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 7 Mar 2020 22:57:41 +0100 Subject: [PATCH 1/5] Change uint_with_carry struct to result_with_carry --- include/intx/int128.hpp | 16 ++++++++++------ include/intx/intx.hpp | 8 ++++---- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/include/intx/int128.hpp b/include/intx/int128.hpp index 5721f1a7..8abbcc1d 100644 --- a/include/intx/int128.hpp +++ b/include/intx/int128.hpp @@ -69,18 +69,22 @@ 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(uint128 a, uint128 b) noexcept { const auto lo = a.lo + b.lo; const auto lo_carry = lo < a.lo; @@ -101,9 +105,9 @@ constexpr uint128 operator+(uint128 x) noexcept return x; } -/// Performs subtraction of two unsinged numbers and returns the difference +/// 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 +constexpr inline result_with_carry sub_with_carry(uint128 a, uint128 b) noexcept { const auto lo = a.lo - b.lo; const auto lo_borrow = lo > a.lo; diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp index 16cf695e..87ca209b 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 @@ -412,7 +412,7 @@ inline uint shl_loop(const uint& x, unsigned shift) template -constexpr uint_with_carry add_with_carry(const uint& a, const uint& b) noexcept +constexpr result_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); @@ -420,10 +420,10 @@ constexpr uint_with_carry add_with_carry(const uint& a, const uint& b) return {{hi.value, lo.value}, tt.carry || hi.carry}; } -/// Performs subtraction of two unsinged numbers and returns the difference +/// Performs subtraction of two unsigned 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 +constexpr result_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); From 12ef0f249eb4a9f9a5efa4746b80be928704779a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 7 Mar 2020 23:18:27 +0100 Subject: [PATCH 2/5] Add add_with_carry() for uint64_t --- include/intx/int128.hpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/include/intx/int128.hpp b/include/intx/int128.hpp index 8abbcc1d..54c94706 100644 --- a/include/intx/int128.hpp +++ b/include/intx/int128.hpp @@ -84,23 +84,29 @@ struct result_with_carry /// Linear arithmetic operators. /// @{ +constexpr inline result_with_carry add_with_carry( + uint64_t x, uint64_t y, bool carry = false) noexcept +{ + 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 inline result_with_carry add_with_carry(uint128 a, uint128 b) 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 lo = add_with_carry(a.lo, b.lo); + const auto hi = add_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 add_with_carry(x, y).value; } -constexpr uint128 operator+(uint128 x) noexcept +constexpr inline uint128 operator+(uint128 x) noexcept { return x; } From a4fb8f895aa8b0550ad7733b6f925c786c1de544 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 7 Mar 2020 23:33:05 +0100 Subject: [PATCH 3/5] Make add_with_carry() more generic and simplify addition --- include/intx/int128.hpp | 6 ++++-- include/intx/intx.hpp | 10 ---------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/include/intx/int128.hpp b/include/intx/int128.hpp index 54c94706..334ea97b 100644 --- a/include/intx/int128.hpp +++ b/include/intx/int128.hpp @@ -94,9 +94,11 @@ constexpr inline result_with_carry add_with_carry( return {t, carry1 || carry2}; } -constexpr inline result_with_carry add_with_carry(uint128 a, uint128 b) 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); + 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}; } diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp index 87ca209b..0b9ea8c6 100644 --- a/include/intx/intx.hpp +++ b/include/intx/intx.hpp @@ -410,16 +410,6 @@ inline uint shl_loop(const uint& x, unsigned shift) return r; } - -template -constexpr result_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 unsigned numbers and returns the difference /// and the carry bit (aka borrow, overflow). template From cd8d183276410b132b0afc3f23272fc1771162b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 7 Mar 2020 23:42:03 +0100 Subject: [PATCH 4/5] Add sub_with_carry() for uint64_t --- include/intx/int128.hpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/include/intx/int128.hpp b/include/intx/int128.hpp index 334ea97b..f89f3531 100644 --- a/include/intx/int128.hpp +++ b/include/intx/int128.hpp @@ -113,25 +113,31 @@ constexpr inline uint128 operator+(uint128 x) noexcept return x; } +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 inline result_with_carry sub_with_carry(uint128 a, uint128 b) 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); + 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. From 73a7263ea37ac6392cda2adef68465d1fcd7bf36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 7 Mar 2020 23:47:31 +0100 Subject: [PATCH 5/5] Make sub_with_carry() more generic and simplify subtraction --- include/intx/int128.hpp | 6 ++++-- include/intx/intx.hpp | 11 ----------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/include/intx/int128.hpp b/include/intx/int128.hpp index f89f3531..d514e5c6 100644 --- a/include/intx/int128.hpp +++ b/include/intx/int128.hpp @@ -125,9 +125,11 @@ constexpr inline result_with_carry sub_with_carry( /// Performs subtraction of two unsigned numbers and returns the difference /// and the carry bit (aka borrow, overflow). -constexpr inline result_with_carry 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 = sub_with_carry(a.lo, b.lo); + 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}; } diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp index 0b9ea8c6..bd3b8455 100644 --- a/include/intx/intx.hpp +++ b/include/intx/intx.hpp @@ -410,17 +410,6 @@ inline uint shl_loop(const uint& x, unsigned shift) return r; } -/// Performs subtraction of two unsigned numbers and returns the difference -/// and the carry bit (aka borrow, overflow). -template -constexpr result_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 {