// // This file is part of // // CTBignum // // C++ Library for Compile-Time and Run-Time Multi-Precision and Modular Arithmetic // // // This file is distributed under the Apache License, Version 2.0. See the LICENSE // file for details. #ifndef CT_ADDITION_HPP #define CT_ADDITION_HPP #include #include #include #include #include #include namespace cbn { template CBN_ALWAYS_INLINE constexpr auto add(big_int a, big_int b) { constexpr auto L = std::max(M, N); return add_same(detail::pad(a), detail::pad(b)); } template CBN_ALWAYS_INLINE constexpr auto subtract(big_int a, big_int b) { constexpr auto L = std::max(M, N); return subtract_same(detail::pad(a), detail::pad(b)); } template CBN_ALWAYS_INLINE constexpr auto add_same(big_int a, big_int b) { T carry{}; big_int r{}; for (auto i = 0; i < N; ++i) { auto aa = a[i]; auto sum = aa + b[i]; auto res = sum + carry; carry = (sum < aa) | (res < sum); r[i] = res; } r[N] = carry; return r; } template CBN_ALWAYS_INLINE constexpr auto subtract_same(big_int a, big_int b) { T carry{}; big_int r{}; for (auto i = 0; i < N; ++i) { auto aa = a[i]; auto diff = aa - b[i]; auto res = diff - carry; carry = (diff > aa) | (res > diff); r[i] = res; } r[N] = carry * static_cast(-1); // sign extension return r; } template CBN_ALWAYS_INLINE constexpr auto add_ignore_carry(big_int a, big_int b) { T carry{}; big_int r{}; for (auto i = 0; i < N; ++i) { T aa = a[i]; T sum = aa + b[i]; T res = sum + carry; carry = (sum < aa) | (res < sum); r[i] = res; } return r; } template constexpr auto subtract_ignore_carry(big_int a, big_int b) { T carry{}; big_int r{}; for (auto i = 0; i < N; ++i) { auto aa = a[i]; auto diff = aa - b[i]; auto res = diff - carry; carry = (diff > aa) | (res > diff); r[i] = res; } return r; } template constexpr auto mod_add(big_int a, big_int b, big_int modulus) { T carry{}; big_int r{}; for (auto i = 0; i < N; ++i) { auto aa = a[i]; auto sum = aa + b[i]; auto res = sum + carry; carry = (sum < aa) | (res < sum); r[i] = res; } auto reduced = subtract_ignore_carry(r, modulus); big_int res = (carry + (r >= modulus) != 0) ? reduced : r; return res; } template constexpr auto mod_sub(big_int a, big_int b, big_int modulus) { T carry{}; big_int r{}; for (auto i = 0; i < N; ++i) { auto aa = a[i]; auto diff = aa - b[i]; auto res = diff - carry; carry = (diff > aa) | (res > diff); r[i] = res; } auto adjusted_r = add_ignore_carry(r, modulus); big_int res = carry ? adjusted_r : r; return res; } template constexpr auto mod_add(big_int a, big_int b, std::integer_sequence) { big_int modulus{{Modulus...}}; return mod_add(a, b, modulus); } template constexpr auto operator+(big_int a, big_int b) { return add(a, b); } template constexpr auto operator-(big_int a, big_int b) { return subtract(a, b); } template constexpr auto mod_sub(big_int a, big_int b, std::integer_sequence) { big_int modulus{{Modulus...}}; return mod_sub(a, b, modulus); } } // end namespace cbn #endif