The big_int
class
The big_int
class is a thin wrapper class around C++'s fixed-size array type (std::array
).
Defined in header decimal_literals.hpp
The user-defined literal _Z
returns a std::integer_sequence
, which can then be converted to a big_int
using the to_big_int
conversion function.
template <char... Chars> constexpr auto operator"" _Z()
auto i_am_an_integer_sequence = 1457094817350874187634298576109387589746_Z;
template <size_t ExplicitLength = 0, typename T, T... Limbs>
constexpr auto to_big_int(std::integer_sequence<T, Limbs...>);
constexpr auto i_am_a_big_int = to_big_int(7656523141023855493084520646_Z);
big_int
"feels" like a std::array
, so things like indexing (operator[]
), begin()
, end()
and range-for work as you would expect.
big_int<3, uint64_t> x { 1, 2, 3};
for(uint64_t limb: x){
// do something with limb
}
To start, some examples (also to show the overloaded operators)
#include <ctbignum/ctbignum.hpp>
using namespace cbn;
constexpr auto x = to_big_int(29519863647905179352825_Z);
constexpr auto y = to_big_int(1180591620717411303424_Z);
static_assert(x + y == to_big_int(30700455268622590656249_Z)); // invokes add
static_assert(x - y == to_big_int(28339272027187768049401_Z)); // invokes subtract
static_assert(x * y == to_big_int(34850903667437369155084628453170676026572800_Z)); // invokes mul
static_assert(x / y == to_big_int(25_Z)); // invokes div, selects the quotient
static_assert(x % y == to_big_int(5073129969896767225_Z)); // invokes div, selects the remainder
Defined in header addition.hpp
The following operation acts on big-ints of arbitrary sizes
template <typename T, size_t M, size_t N>
constexpr auto add(big_int<M, T> a, big_int<N, T> b);
template <typename T, size_t M, size_t N>
constexpr auto subtract(big_int<M, T> a, big_int<N, T> b);
The following operations act on big-ints of the same size:
template <typename T, size_t N>
constexpr auto add_ignore_carry(big_int<N, T> a, big_int<N, T> b);
template <typename T, size_t N>
constexpr auto subtract_ignore_carry(big_int<N, T> a, big_int<N, T> b);
template <typename T, size_t N>
constexpr auto mod_add(big_int<N, T> a, big_int<N, T> b, big_int<N, T> modulus);
template <typename T, size_t N, T... Modulus>
constexpr auto mod_add(big_int<N, T> a, big_int<N, T> b, std::integer_sequence<T, Modulus...>);
Defined in header mult.hpp
Multiplication (for inputs of arbitrary lengths)
template <size_t padding_limbs = 0, size_t M, size_t N, typename T>
constexpr big_int<M + N, T> mul(big_int<M, T> u, big_int<N, T> v);
Partial multiplication (computation of most significant limbs beyond ResultLength
is skipped)
template <size_t ResultLength, size_t M, size_t N, typename T>
constexpr big_int<ResultLength, T> partial_mul(big_int<M, T> u, big_int<N, T> v);
Short multiplication (second operand is a single limb)
template <typename T, std::size_t N>
constexpr auto short_mul(big_int<N, T> a, T b);
Defined in header division.hpp
The division functions return a DivisionResult
struct:
template <typename Q, typename R>
struct DivisionResult {
Q quotient;
R remainder;
};
Division.
template <size_t M, size_t N, typename T>
constexpr DivisionResult<big_int<M, T>, big_int<N, T>>
div(big_int<M, T> u, big_int<N, T> v);
Short division (second operand, the divisor, is a single limb). The function returns the pair (quotient, remainder).
template <size_t M, typename T>
constexpr DivisionResult<big_int<M, T>,big_int<1, T>>
short_div(big_int<M, T> u, T v);
Defined in header invariant_div.hpp
Division via multiplication and bitshifts (see paper by Granlund and Montgomery, "Division by Invariant Integers using Multiplication", 1994)
template <typename T, size_t N, T... Divisor>
constexpr auto div(big_int<N, T> n, std::integer_sequence<T, Divisor...>);
Remainder (modulo) operation
template <typename T, size_t N, T... Modulus>
constexpr auto mod(big_int<N, T> n, std::integer_sequence<T, Modulus...>);
Defined in header mod_inv.hpp
template <typename T, size_t N>
constexpr auto
mod_inv(big_int<N, T> a, big_int<N, T> modulus) -> big_int<N, T>
Defined in header pow.hpp
Raise a big_int
to a power that fits in a single limb
template <std::size_t N1, typename T>
constexpr auto pow(big_int<N1, T> base, T exp) {
Defined in header mod_exp.hpp
Raise a big_int
to a big_int
power modulo a compile-time modulus
template <std::size_t N1, std::size_t N2, typename T, T... Modulus>
constexpr auto mod_exp(big_int<N1, T> a, big_int<N2, T> exp, std::integer_sequence<T, Modulus...> modulus);
Defined in header barrett.hpp
Barrett reduction with a compile-time modulus
template <typename T, std::size_t N1, T... Modulus>
constexpr auto barrett_reduction(big_int<N1, T> x, std::integer_sequence<T, Modulus...>);
Defined in header montgomery.hpp
Montgomery reduction with a compile-time modulus
template <typename T, std::size_t N1, T... Modulus, std::size_t N2 = sizeof...(Modulus)>
constexpr auto montgomery_reduction(big_int<N1, T> A, std::integer_sequence<T, Modulus...>);
Montgomery multiplication with compile-time modulus
template <typename T, std::size_t N, T... Modulus>
constexpr auto montgomery_mul(big_int<N, T> x, big_int<N, T> y, std::integer_sequence<T, Modulus...>);
Defined in header relational_ops.hpp
The following operation acts on big-ints of arbitrary sizes
template <typename T, size_t N1, size_t N2>
constexpr bool operator==(big_int<N1, T> a, big_int<N2, T> b);
template <typename T, size_t N1, size_t N2>
constexpr bool operator!=(big_int<N1, T> a, big_int<N2, T> b);
template <typename T, size_t N1, size_t N2>
constexpr bool operator< (big_int<N1, T> a, big_int<N2, T> b);
template <typename T, size_t N1, size_t N2>
constexpr bool operator> (big_int<N1, T> a, big_int<N2, T> b);
template <typename T, size_t N1, size_t N2>
constexpr bool operator<=(big_int<N1, T> a, big_int<N2, T> b);
template <typename T, size_t N1, size_t N2>
constexpr bool operator>=(big_int<N1, T> a, big_int<N2, T> b);
Defined in header io.hpp
Writes a base-10 (decimal-digit) representation of the big_int
to an output stream
template <std::size_t N, typename T>
std::ostream &operator<<(std::ostream &strm, cbn::big_int<N, T> obj)
#include <ctbignum/decimal_literals.hpp>
#include <ctbignum/io.hpp>
#include <iostream>
using namespace cbn;
std::cout << to_big_int(123456789012345678901234567890_Z) << '\n';
We can create a big_int reference of existing limbs in memory via a reinterpret_cast
:
std::vector<uint64_t> some_limbs_on_the_heap = {1,2,3,4,5,6,7};
// let's create a big_int<3, uint64_t> reference that is
// a view on the second to fourth entry in the vector
auto bigint_ptr = reinterpret_cast<big_int<3, uint64_t>*>(some_limbs_on_the_heap.begin() + 1);
auto& big_int_ref = *bigint_ptr;
Of course, you can also just memcpy
the limbs into a freshly constructed big_int.