Skip to content

Commit

Permalink
Merge pull request #130 from chfast/adc
Browse files Browse the repository at this point in the history
Add/sub refactor
  • Loading branch information
chfast authored Mar 7, 2020
2 parents 25a73b2 + 73a7263 commit 4e7e2b8
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 46 deletions.
68 changes: 44 additions & 24 deletions include/intx/int128.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,57 +69,77 @@ struct uint<128>
using uint128 = uint<128>;


template <unsigned N>
struct uint_with_carry
/// Contains result of add/sub/etc with a carry flag.
template <typename T>
struct result_with_carry
{
uint<N> value;
T value;
bool carry;

/// Conversion to tuple of referecences, to allow usage with std::tie().
operator std::tuple<T&, bool&>() 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<uint64_t> 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 <unsigned N>
constexpr result_with_carry<uint<N>> add_with_carry(
const uint<N>& a, const uint<N>& 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<uint64_t> 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 <unsigned N>
constexpr inline result_with_carry<uint<N>> sub_with_carry(
const uint<N>& a, const uint<N>& 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.
Expand Down
23 changes: 1 addition & 22 deletions include/intx/intx.hpp
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -410,27 +410,6 @@ inline uint<N> shl_loop(const uint<N>& x, unsigned shift)
return r;
}


template <unsigned N>
constexpr uint_with_carry<N> add_with_carry(const uint<N>& a, const uint<N>& 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<N>::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 <unsigned N>
constexpr uint_with_carry<N> sub_with_carry(const uint<N>& a, const uint<N>& 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<N>::half_type{lo.carry});
return {{hi.value, lo.value}, tt.carry || hi.carry};
}

template <unsigned N>
inline uint<N> add_loop(const uint<N>& a, const uint<N>& b) noexcept
{
Expand Down

0 comments on commit 4e7e2b8

Please sign in to comment.