Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add/sub refactor #130

Merged
merged 5 commits into from
Mar 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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