-
Notifications
You must be signed in to change notification settings - Fork 2
Examples
Here are some examples of what this library can do.
Calculate pi to 100 digits using continued fractions:
#include "bbi.h"
#include <array>
#include <iostream>
#include <string>
template <class Int>
Int
power(Int const& f, unsigned n)
{
if (n == 0)
return 1;
if (n == 1)
return f;
auto r = power(f, n / 2);
r *= r;
if (n % 2 != 0)
r *= f;
return r;
}
template <class Int>
Int
log10(Int const& f)
{
return Int{std::string{f}.size()};
}
int constexpr pi_a[] =
{
3, 7, 15, 1, 292, 1, 1, 1, 2, 1,
3, 1, 14, 2, 1, 1, 2, 2, 2, 2,
1, 84, 2, 1, 1, 15, 3, 13, 1, 4,
2, 6, 6, 99, 1, 2, 2, 6, 3, 5,
1, 1, 6, 8, 1, 7, 1, 2, 3, 7,
1, 2, 1, 1, 12, 1, 1, 1, 3, 1,
1, 8, 1, 1, 2, 1, 6, 1, 1, 5,
2, 2, 3, 1, 2, 4, 4, 16, 1, 161,
45, 1, 22, 1, 2, 2, 1, 4, 1, 2,
24, 1, 2, 1, 3, 1, 2, 1, 1, 10,
2, 5
};
constexpr unsigned Npi = sizeof(pi_a)/sizeof(pi_a[0]);
template <class Int>
constexpr
std::array<Int, Npi>
make_pi_d()
{
std::array<Int, Npi> pi_d{1, 7};
for (auto i = 2u; i < Npi; ++i)
pi_d[i] = pi_a[i] * pi_d[i-1] + pi_d[i-2];
return pi_d;
}
template <class Int>
Int
pi_d(int n)
{
static auto const den = make_pi_d<Int>();
return den[n];
}
template <class Int>
constexpr
std::array<Int, Npi>
make_pi_n()
{
std::array<Int, Npi> pi_n{3, 22};
for (auto i = 2u; i < Npi; ++i)
pi_n[i] = pi_a[i] * pi_n[i-1] + pi_n[i-2];
return pi_n;
}
template <class Int>
Int
pi_n(int n)
{
static auto const num = make_pi_n<Int>();
return num[n];
}
int
main()
{
using namespace bbi::term;
auto pi_num = pi_n<i256>(Npi-1);
auto pi_den = pi_d<i256>(Npi-1);
auto f = power(i1024{10}, unsigned{log10(pi_num)+log10(pi_den)-2});
auto d = pi_num * f / pi_den;
std::string s{d};
s.insert(s.begin()+1, '.');
std::cout << pi_num << " / " << pi_den << " = " << s << '\n';
}Output:
47851633293495758577879878030394929021214201883870831 / 15231647947361123271599045989184750211511930092111565 = 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214
I used i256 for the numerators and denominators computed from the continued fraction representation. And then to compute the fraction
I used a i1024. And I know no overflow occurred because if it had, std::terminate would have been called. I was able to experimentally determine that these were the smallest types I could use for each computation, as using even smaller types resulted in a call to std::terminate.
This example demonstrates the ease with which bbi types can use built-in integral types, and the ease with which different sizes of bbi types can interoperate. Because all implicit conversions are value-preserving, and because all overflows are caught with terminate (in namespace bbi::term), I have high confidence that this computation is free of run-time errors.