Generating prime numbers at compile time - c++

I am interested in how you can generate an array of prime numbers at compile time (I believe that the only way is using metaprogramming (in C++, not sure how this works in other languages)).
Quick note, I don't want to just say int primes[x] = {2, 3, 5, 7, 11, ...};, since I want to use this method in competitive programming, where source files cannot be larger than 10KB. So this rules out any pregenerated arrays of more than a few thousand elements.
I know that you can generate the fibonacci sequence at compile time for example, but that is rather easy, since you just add the 2 last elements. For prime numbers, I don't really know how to do this without loops (I believe it is possible, but I don't know how, using recursion I guess), and I don't know how loops could be evaluated at compile-time.
So I'm looking for an idea (at least) on how to approach this problem, maybe even a short example

We can do a compile time pre calculation of some prime numbers and put them in a compile time generated array. And then use a simple look up mechanism to get the value. This will work only to a small count of prime numbers. But it should show you the basic mechanism.
We will first define some default approach for the calculation a prime number as a constexpr function:
constexpr bool isPrime(size_t n) noexcept {
if (n <= 1) return false;
for (size_t i = 2; i*i < n; i++) if (n % i == 0) return false;
return true;
}
constexpr unsigned int primeAtIndex(size_t i) noexcept {
size_t k{3};
for (size_t counter{}; counter < i; ++k)
if (isPrime(k)) ++counter;
return k-1;
}
With that, prime numbers can easily be calculated at compile time. Then, we fill a std::array with all prime numbers. We use also a constexpr function and make it a template with a variadic parameter pack.
We use std::index_sequence to create a prime number for indices 0,1,2,3,4,5, ....
That is straigtforward and not complicated:
// Some helper to create a constexpr std::array initilized by a generator function
template <typename Generator, size_t ... Indices>
constexpr auto generateArrayHelper(Generator generator, std::index_sequence<Indices...>) {
return std::array<decltype(std::declval<Generator>()(size_t{})), sizeof...(Indices) > { generator(Indices)... };
}
This function will be fed with an index sequence 0,1,2,3,4,... and a generator function and return a std::array<return type of generator function, ...> with the corresponding numbers, calculated by the generator.
We make a next function, that will call the above with the index sequence 1,2,3,4,...Max, like so:
template <size_t Size, typename Generator>
constexpr auto generateArray(Generator generator) {
return generateArrayHelper(generator, std::make_index_sequence<Size>());
}
And now, finally,
constexpr auto Primes = generateArray<100>(primeAtIndex);
will give us a compile-time std::array<unsigned int, 100> with the name Primes containing all 100 prime numbers. And if we need the i'th prime number, then we can simply write Primes [i]. There will be no calculation at runtime.
I do not think that there is a faster way to calculate the n'th prime number.
Please see the complete program below:
#include <iostream>
#include <utility>
#include <array>
// All done during compile time -------------------------------------------------------------------
constexpr bool isPrime(size_t n) noexcept {
if (n <= 1) return false;
for (size_t i = 2; i*i < n; i++) if (n % i == 0) return false;
return true;
}
constexpr unsigned int primeAtIndex(size_t i) noexcept {
size_t k{3};
for (size_t counter{}; counter < i; ++k)
if (isPrime(k)) ++counter;
return k-1;
}
// Some helper to create a constexpr std::array initilized by a generator function
template <typename Generator, size_t ... Indices>
constexpr auto generateArrayHelper(Generator generator, std::index_sequence<Indices...>) {
return std::array<decltype(std::declval<Generator>()(size_t{})), sizeof...(Indices) > { generator(Indices)... };
}
template <size_t Size, typename Generator>
constexpr auto generateArray(Generator generator) {
return generateArrayHelper(generator, std::make_index_sequence<Size>());
}
// This is the definition of a std::array<unsigned int, 100> with prime numbers in it
constexpr auto Primes = generateArray<100>(primeAtIndex);
// End of: All done during compile time -----------------------------------------------------------
// Some debug test driver code
int main() {
for (const auto p : Primes) std::cout << p << ' '; std::cout << '\n';
return 0;
}
By the way. The generateArray fucntionality will of course also work with other generator functions.
If you need for example triangle numbers, then you could use:
constexpr size_t getTriangleNumber(size_t row) noexcept {
size_t sum{};
for (size_t i{ 1u }; i <= row; i++) sum += i;
return sum;
}
and
constexpr auto TriangleNumber = generateArray<100>(getTriangleNumber);
would give you a compile time calculated constexpr std::array<size_t, 100> with triangle numbers.
For fibonacci numbers your could use
constexpr unsigned long long getFibonacciNumber(size_t index) noexcept {
unsigned long long f1{ 0ull }, f2{ 1ull }, f3{};
while (index--) { f3 = f2 + f1; f1 = f2; f2 = f3; }
return f2;
}
and
constexpr auto FibonacciNumber = generateArray<93>(getFibonacciNumber);
to get ALL Fibonacci numbers that fit in a 64 bit value.
So, a rather flexible helper.
Caveat
Big array sizes will create a compiler out of heap error.
Developed and tested with Microsoft Visual Studio Community 2019, Version 16.8.2.
Additionally compiled and tested with clang11.0 and gcc10.2
Language: C++17

The following is just to give you something to start with. It heavily relies on recursively instantiating types, which isn't quite efficient and I would not want to see in the next iteration of the implementation.
div is a divisor of x iff x%div == false:
template <int div,int x>
struct is_divisor_of : std::conditional< x%div, std::false_type, std::true_type>::type {};
A number x is not prime, if there is a p < x that is a divisor of x:
template <int x,int p=x-2>
struct has_divisor : std::conditional< is_divisor_of<p,x>::value, std::true_type, has_divisor<x,p-1>>::type {};
If no 1 < p < x divides x then x has no divisor (and thus is prime):
template <int x>
struct has_divisor<x,1> : std::false_type {};
A main to test it:
int main()
{
std::cout << is_divisor_of<3,12>::value;
std::cout << is_divisor_of<5,12>::value;
std::cout << has_divisor<12>::value;
std::cout << has_divisor<13>::value;
}
Output:
1010
Live Demo.
PS: You probably better take the constexpr function route, as suggested in a comment. The above is just as useful as recursive templates to calculate the fibonacci numbers (ie not really useful other than for demonstration ;).

With "simple" constexpr, you might do:
template <std::size_t N>
constexpr void fill_next_primes(std::array<std::size_t, N>& a, std::size_t n)
{
std::size_t i = (a[n - 1] & ~0x1) + 1;
while (!std::all_of(a.begin(), a.begin() + n, [&i](int e){ return i % e != 0; })) {
i += 2;
}
a[n] = i;
}
template <std::size_t N>
constexpr std::array<std::size_t, N> make_primes_array()
{
// use constexpr result
// to ensure to compute at compile time,
// even if `make_primes_array` is not called in constexpr context
constexpr auto res = [](){
std::array<std::size_t, N> res{2};
for (std::size_t i = 1; i != N; ++i) {
fill_next_primes(res, i);
}
return res;
}();
return res;
}
Demo

Related

How to optimize Fibonacci using memoization in C++?

I'm struggling with getting the correct implementation of finding the nth number in the Fibonacci sequence. More accurately, how to optimize it with DP.
I was able to correctly write it in the bottom-up approach:
int fib(int n) {
int dp[n + 2];
dp[0] = 0;
dp[1] = 1;
for (int i = 2; i <= n; i++)
dp[i] = dp[i - 1] + dp[i - 2];
return dp[n];
}
But the top-down (memoized) approach is harder for me to grasp. This is what I put originally:
int fib(int n) {
std::vector<int> dp(n + 1, -1);
// Lambda Function
auto recurse = [&](int n) {
if (dp[n] != -1)
return dp[n];
if (n == 0) {
dp[n] = 0;
return 0;
}
if (n == 1){
dp[n] = 1;
return 1;
}
dp[n] = fib(n - 2) + fib(n - 1);
return dp[n];
};
recurse(n);
return dp.back();
}
...This was my first time using a C++ lambda function, though, so I also tried:
int recurse(int n, std::vector<int>& dp) {
if (dp[n] != -1)
return dp[n];
if (n == 0) {
dp[n] = 0;
return 0;
}
if (n == 1){
dp[n] = 1;
return 1;
}
dp[n] = fib(n - 2) + fib(n - 1);
return dp[n];
}
int fib(int n) {
std::vector<int> dp(n + 1, -1);
recurse(n, dp);
return dp.back();
}
...just to make sure. Both of these gave time limit exceeded errors on leetcode. This, obviously, seemed off, since DP/Memoization are optimization techniques. Is my top-down approach wrong? How do I fix it?
You set up the memoization storage in fib, and then create the recursive part of your solution in the lambda recurse. That means that here: dp[n] = fib(n - 2) + fib(n - 1); you really should call recurse not fib. But in order to do that with a lambda, you need to give the lambda to the lambda so to speak.
Example:
#include <iostream>
#include <vector>
int fib(int n)
{
std::vector<int> dp(n + 1, -1);
// Lambda Function
auto recurse = [&dp](int n, auto &rec)
{
if (dp[n] != -1)
return dp[n];
if (n == 0)
{
dp[n] = 0;
return 0;
}
if (n == 1)
{
dp[n] = 1;
return 1;
}
dp[n] = rec(n - 2, rec) + rec(n - 1, rec);
return dp[n];
};
recurse(n, recurse);
return dp.back();
}
int main()
{
std::cout << fib(12) << '\n';
}
Whenever you call fib(n), you create new vector dp with all element -1, then in fact, you don't memorize any previous result.
int fib(int n) {
std::vector<int> dp(n + 1, -1);
To solve this issue, you can declare dp vector outside the function as fib as shared data. Note that you said this is leetcode problem, then you can declare a vector with fixed size. For example,
std::vector<int> dp = std::vector<int>(31, -1);
You can test yourself. I just give the code which is runable in leetcode.
int fib(int n) {
// Lambda Function
auto recurse = [&](int n) {
if (n == 0) {
dp[n] = 0;
return 0;
}
if (n == 1){
dp[n] = 1;
return 1;
}
if (dp[n] != -1)
return dp[n];
dp[n] = fib(n - 2) + fib(n - 1);
return dp[n];
};
recurse(n);
return dp[n];
}
Very interesting. I will show you the fastest possible solution with an additional low memory footprint.
For this we will use compile time memoization.
One important property of the Fibonacci series is that the values grow strongly exponential. So, all existing build in integer data types will overflow rather quick.
With Binet's formula you can calculate that the 93rd Fibonacci number is the last that will fit in a 64bit unsigned value.
And calculating 93 values during compilation is a really simple and fast task.
So, how to do?
We will first define the default approach for calculation a Fibonacci number as a constexpr function. Iterative and non recursive.
// Constexpr function to calculate the nth Fibonacci number
constexpr unsigned long long getFibonacciNumber(size_t index) noexcept {
// Initialize first two even numbers
unsigned long long f1{ 0 }, f2{ 1 };
// calculating Fibonacci value
while (index--) {
// get next value of Fibonacci sequence
unsigned long long f3 = f2 + f1;
// Move to next number
f1 = f2;
f2 = f3;
}
return f2;
}
With that, Fibonacci numbers can easily be calculated at compile time. Then, we fill a std::array with all Fibonacci numbers. We use also a constexpr and make it a template with a variadic parameter pack.
We use std::integer_sequence to create a Fibonacci number for indices 0,1,2,3,4,5, ....
That is straigtforward and not complicated:
template <size_t... ManyIndices>
constexpr auto generateArrayHelper(std::integer_sequence<size_t, ManyIndices...>) noexcept {
return std::array<unsigned long long, sizeof...(ManyIndices)>{ { getFibonacciNumber(ManyIndices)... } };
};
This function will be fed with an integer sequence 0,1,2,3,4,... and return a std::array<unsigned long long, ...> with the corresponding Fibonacci numbers.
We know that we can store maximum 93 values. And therefore we make a next function, that will call the above with the integer sequence 1,2,3,4,...,92,93, like so:
constexpr auto generateArray() noexcept {
return generateArrayHelper(std::make_integer_sequence<size_t, MaxIndexFor64BitValue>());
}
And now, finally,
constexpr auto FIB = generateArray();
will give us a compile-time std::array<unsigned long long, 93> with the name FIB containing all Fibonacci numbers. And if we need the i'th Fibonacci number, then we can simply write FIB[i]. There will be no calculation at runtime.
I do not think that there is a faster or easier way to calculate the n'th Fibonacci number.
Please see the complete program below:
#include <iostream>
#include <array>
#include <utility>
// ----------------------------------------------------------------------
// All the following will be done during compile time
// Constexpr function to calculate the nth Fibonacci number
constexpr unsigned long long getFibonacciNumber(size_t index) {
// Initialize first two even numbers
unsigned long long f1{ 0 }, f2{ 1 };
// calculating Fibonacci value
while (index--) {
// get next value of Fibonacci sequence
unsigned long long f3 = f2 + f1;
// Move to next number
f1 = f2;
f2 = f3;
}
return f2;
}
// We will automatically build an array of Fibonacci numberscompile time
// Generate a std::array with n elements
template <size_t... ManyIndices>
constexpr auto generateArrayHelper(std::integer_sequence<size_t, ManyIndices...>) noexcept {
return std::array<unsigned long long, sizeof...(ManyIndices)>{ { getFibonacciNumber(ManyIndices)... } };
};
// Max index for Fibonaccis that for in an 64bit unsigned value (Binets formula)
constexpr size_t MaxIndexFor64BitValue = 93;
// Generate the required number of elements
constexpr auto generateArray()noexcept {
return generateArrayHelper(std::make_integer_sequence<size_t, MaxIndexFor64BitValue>());
}
// This is an constexpr array of all Fibonacci numbers
constexpr auto FIB = generateArray();
// ----------------------------------------------------------------------
// Test
int main() {
// Print all possible Fibonacci numbers
for (size_t i{}; i < MaxIndexFor64BitValue; ++i)
std::cout << i << "\t--> " << FIB[i] << '\n';
return 0;
}
Developed and tested with Microsoft Visual Studio Community 2019, Version 16.8.2.
Additionally compiled and tested with clang11.0 and gcc10.2
Language: C++17

What is wrong with my code C++ Fibo series

#include <iostream>
using namespace std;
int main()
{
int num1 = 0;
int num2 = 1;
int num_temp;
int num_next = 1;
int n;
cin >> n;
for (int i = 0; i < n; i++){
cout << num_next << " ";
num_next = num1 + num2;
num1 = num2;
num_temp = num2;
num2 = num_next - num1;
num1 = num_temp;
}
return 0;
}
EXPECTED: For n=9
0, 1, 1, 2, 3, 5, 8, 13, 21
Actual:
1 1 1 1 1 1 1 1 1
I have to output the first "n" Fibonacci numbers however I think there is some problem in logic.. I can't find out what am I doing wrong. The first 3 or 4 elements are correct but then a problem occurs...
You have to think about what the Fibonacci sequence is.
f(0) == 0
f(1) == 1
f(n>1) = f(n-2) + f(n-1)
A lot of people write this recursively, but of course, that means you end up re-calculating a lot. So then you get into optimizing it. And yes, you can do it in a single loop.
I would keep:
int fibuMinus1 = 1;
int fibuMinus2 = 0;
cout << fibuMinus2 << " " << fibuMinus1;
for (int index = 2; index < n; ++index) {
int thisFibu = fibuMinus1 + fibuMinus2;
fibuMinus2 = fibuMinus1;
fibuMinus1 = thisFibu;
cout << " " << thisFibu;
}
Or something like that. It can definitely be simpler than you're doing.
I will give an additional answer that may help other users.
The basic message is: Any calculation at runtime is not necessary! Everything can be done a compile time. And then, a simple lookup mechanism can be used. That will be the most efficient and fastest solution.
With Binet's formula, we can calculate that there are only very few Fibonacci numbers that will fit in a C++ unsigned long long data type, which has usually 64 bit now in 2021 and is the "biggest" available data type. Roundabout 93. That is nowadays a really low number.
With modern C++ 17 (and above) features, we can easily create a std::array of all Fibonacci numbers for a 64bit data type at compile time. Becuase there are, as mentioned above, only 93 numbers.
So, we will spend only 93*8= 744 BYTE of none-runtime memory for our lookup array. That is really negligible.
We can easily get the Fibonacci number n by writing FIB[n].
And, if we want to know, if a number is Fibonacci, then we use std::binary_search for finding the value. So, the whole function will be:
bool isFib(const unsigned long long numberToBeChecked) {
return std::binary_search(FIB.begin(), FIB.end(), numberToBeChecked);
}
FIB is a compile time, constexpr std::array. So, how to build that array?
We will first define the default approach for calculation a Fibonacci number as a constexpr function:
// Constexpr function to calculate the nth Fibonacci number
constexpr unsigned long long getFibonacciNumber(size_t index) noexcept {
// Initialize first two even numbers
unsigned long long f1{ 0 }, f2{ 1 };
// Calculating Fibonacci value
while (index--) {
// get next value of Fibonacci sequence
unsigned long long f3 = f2 + f1;
// Move to next number
f1 = f2;
f2 = f3;
}
return f2;
}
With that, Fibonacci numbers can easily be calculated at runtime. Then, we fill a std::array with all Fibonacci numbers. We use also a constexpr and make it a template with a variadic parameter pack.
We use std::integer_sequence to create a Fibonacci number for indices 0,1,2,3,4,5, ....
That is straigtforward and not complicated:
template <size_t... ManyIndices>
constexpr auto generateArrayHelper(std::integer_sequence<size_t, ManyIndices...>) noexcept {
return std::array<unsigned long long, sizeof...(ManyIndices)>{ { getFibonacciNumber(ManyIndices)... } };
};
This function will be fed with an integer sequence 0,1,2,3,4,... and return a std::array<unsigned long long, ...> with the corresponding Fibonacci numbers.
We know that we can store maximum 93 values. And therefore we make a next function, that will call the above with the integer sequence 1,2,3,4,...,92,93, like so:
constexpr auto generateArray() noexcept {
return generateArrayHelper(std::make_integer_sequence<size_t, MaxIndexFor64BitValue>());
}
And now, finally,
constexpr auto FIB = generateArray();
will give us a compile-time std::array<unsigned long long, 93> with the name FIB containing all Fibonacci numbers. And if we need the i'th Fibonacci number, then we can simply write FIB[i]. There will be no calculation at runtime.
The whole example program will look like this:
#include <iostream>
#include <array>
#include <utility>
#include <algorithm>
#include <iomanip>
// ----------------------------------------------------------------------
// All the following will be done during compile time
// Constexpr function to calculate the nth Fibonacci number
constexpr unsigned long long getFibonacciNumber(size_t index) noexcept {
// Initialize first two even numbers
unsigned long long f1{ 0 }, f2{ 1 };
// calculating Fibonacci value
while (index--) {
// get next value of Fibonacci sequence
unsigned long long f3 = f2 + f1;
// Move to next number
f1 = f2;
f2 = f3;
}
return f2;
}
// We will automatically build an array of Fibonacci numbers at compile time
// Generate a std::array with n elements
template <size_t... ManyIndices>
constexpr auto generateArrayHelper(std::integer_sequence<size_t, ManyIndices...>) noexcept {
return std::array<unsigned long long, sizeof...(ManyIndices)>{ { getFibonacciNumber(ManyIndices)... } };
};
// Max index for Fibonaccis that for an 64bit unsigned value (Binet's formula)
constexpr size_t MaxIndexFor64BitValue = 93;
// Generate the required number of elements
constexpr auto generateArray()noexcept {
return generateArrayHelper(std::make_integer_sequence<size_t, MaxIndexFor64BitValue>());
}
// This is an constexpr array of all Fibonacci numbers
constexpr auto FIB = generateArray();
// All the above was compile time
// ----------------------------------------------------------------------
// Check, if a number belongs to the Fibonacci series
bool isFib(const unsigned long long numberToBeChecked) {
return std::binary_search(FIB.begin(), FIB.end(), numberToBeChecked);
}
// Test
int main() {
const unsigned long long testValue{ 498454011879264ull };
std::cout << std::boolalpha << "Does '" <<testValue << "' belong to Fibonacci series? --> " << isFib(testValue) << "\n\n";
for (size_t i{}; i < 10; ++i)
std::cout << i << '\t' << FIB[i] << '\n';
return 0;
}
Developed and tested with Microsoft Visual Studio Community 2019, Version 16.8.2
Additionally tested with gcc 10.2 and clang 11.0.1
Language: C++ 17

Pascal triangle calculation without using for/while loop

I would like to generate Pascal pyramid data from a given data set that looks like this
Pyramid(1,2,3,4,5,6,7,8,9);
This is what I have been doing but it reaches only the second layer while I want it to recursively loop till the top.
template<typename T>
const T Pyramid(T a, T b)
{
return a + b;
}
template<typename T, typename ...A>
const T Pyramid(T t1, T t2, A...a)
{
return Pyramid(t1, t2) + Pyramid(t2, a...);
}
Could you help me fill up the next layers ? ;)
C++17
Here is the C++17 solution (using fold expressions):
#include <iostream>
#include <stdexcept>
#include <utility>
using Integer = std::uint64_t;
constexpr auto Factorial(const Integer n)
{
Integer factorial = 1;
for (Integer i = 2; i <= n; ++i)
{
factorial *= i;
}
return factorial;
}
constexpr auto Binom(const Integer n, const Integer m)
{
if (n < m)
{
throw std::invalid_argument("Binom: n should not be less than m");
}
return Factorial(n) / Factorial(m) / Factorial(n - m);
}
template <Integer... indices, typename... Types>
constexpr auto PyramidImplementation(std::integer_sequence<Integer, indices...>, Types... values)
{
return ((Binom(sizeof...(values), indices) * values) + ...);
}
template <typename... Types>
constexpr auto Pyramid(Types... values)
{
return PyramidImplementation(std::make_integer_sequence<Integer, sizeof...(values)>{}, values...);
}
// ...
constexpr auto pyramid = Pyramid(1, 2, 3, 4, 5, 6, 7, 8, 9);
std::cout << "Pyramid = " << pyramid << std::endl;
Live demo
This solution doesn't use the recursion, because the needed result for a[i] (i = 0 ... n - 1) can be calculated as a sum of binom(n, i) * a[i] (for i = 0 ... n - 1), where binom(n, m) is the binomial coefficient. The Binom function is implemented in the simplest way, so it will work only for small values of n.
C++14
The code can be made C++14-compatible via the following PyramidImplementation function implementation:
#include <type_traits>
template <Integer... indices, typename... Types>
constexpr auto PyramidImplementation(std::integer_sequence<Integer, indices...>, Types... values)
{
using Do = int[];
std::common_type_t<Types...> pyramid{};
(void)Do{0, (pyramid += Binom(sizeof...(values), indices) * values, 0)...};
return pyramid;
}
Live demo

Fibonacci memoization algorithm in C++

I'm struggling a bit with dynamic programming. To be more specific, implementing an algorithm for finding Fibonacci numbers of n.
I have a naive algorithm that works:
int fib(int n) {
if(n <= 1)
return n;
return fib(n-1) + fib(n-2);
}
But when i try to do it with memoization the function always returns 0:
int fib_mem(int n) {
if(lookup_table[n] == NIL) {
if(n <= 1)
lookup_table[n] = n;
else
lookup_table[n] = fib_mem(n-1) + fib_mem(n-2);
}
return lookup_table[n];
}
I've defined the lookup_table and initially stored NIL in all elements.
Any ideas what could be wrong?
Here's the whole program as requested:
#include <iostream>
#define NIL -1
#define MAX 100
long int lookup_table[MAX];
using namespace std;
int fib(int n);
int fib_mem(int n);
void initialize() {
for(int i = 0; i < MAX; i++) {
lookup_table[i] == NIL;
}
}
int main() {
int n;
long int fibonnaci, fibonacci_mem;
cin >> n;
// naive solution
fibonnaci = fib(n);
// memoized solution
initialize();
fibonacci_mem = fib_mem(n);
cout << fibonnaci << endl << fibonacci_mem << endl;
return 0;
}
int fib(int n) {
if(n <= 1)
return n;
return fib(n-1) + fib(n-2);
}
int fib_mem(int n) {
if(lookup_table[n] == NIL) {
if(n <= 1)
lookup_table[n] = n;
else
lookup_table[n] = fib_mem(n-1) + fib_mem(n-2);
}
return lookup_table[n];
}
I tend to find the easiest way to write memoization by mixing the naive implementation with the memoization:
int fib_mem(int n);
int fib(int n) { return n <= 1 ? n : fib_mem(n-1) + fib_mem(n-2); }
int fib_mem(int n)
{
if (lookup_table[n] == NIL) {
lookup_table[n] = fib(n);
}
return lookup_table[n];
}
#include <iostream>
#define N 100
using namespace std;
const int NIL = -1;
int lookup_table[N];
void init()
{
for(int i=0; i<N; i++)
lookup_table[i] = NIL;
}
int fib_mem(int n) {
if(lookup_table[n] == NIL) {
if(n <= 1)
lookup_table[n] = n;
else
lookup_table[n] = fib_mem(n-1) + fib_mem(n-2);
}
return lookup_table[n];
}
int main()
{
init();
cout<<fib_mem(5);
cout<<fib_mem(7);
}
Using the exactly same function, and this is working fine.
You have done something wrong in initialisation of lookup_table.
Since the issue is initialization, the C++ standard library allows you to initialize sequences without having to write for loops and thus will prevent you from making mistakes such as using == instead of =.
The std::fill_n function does this:
#include <algorithm>
//...
void initialize()
{
std::fill_n(lookup_table, MAX, NIL);
}
Interesting concept. Speeding up by memoization.
There is a different concept. You could call it compile time memoization. But in reality it is a compile time pre calculation of all Fibonacci numbers that fit into a 64 bit value.
One important property of the Fibonacci series is that the values grow strongly exponential. So, all existing build in integer data types will overflow rather quick.
With Binet's formula you can calculate that the 93rd Fibonacci number is the last that will fit in a 64bit unsigned value.
And calculating 93 values during compilation is a really simple task.
We will first define the default approach for calculation a Fibonacci number as a constexpr function:
// Constexpr function to calculate the nth Fibonacci number
constexpr unsigned long long getFibonacciNumber(size_t index) noexcept {
// Initialize first two even numbers
unsigned long long f1{ 0 }, f2{ 1 };
// calculating Fibonacci value
while (index--) {
// get next value of Fibonacci sequence
unsigned long long f3 = f2 + f1;
// Move to next number
f1 = f2;
f2 = f3;
}
return f2;
}
With that, Fibonacci numbers can easily be calculated at runtime. Then, we fill a std::array with all Fibonacci numbers. We use also a constexpr and make it a template with a variadic parameter pack.
We use std::integer_sequence to create a Fibonacci number for indices 0,1,2,3,4,5, ....
That is straigtforward and not complicated:
template <size_t... ManyIndices>
constexpr auto generateArrayHelper(std::integer_sequence<size_t, ManyIndices...>) noexcept {
return std::array<unsigned long long, sizeof...(ManyIndices)>{ { getFibonacciNumber(ManyIndices)... } };
};
This function will be fed with an integer sequence 0,1,2,3,4,... and return a std::array<unsigned long long, ...> with the corresponding Fibonacci numbers.
We know that we can store maximum 93 values. And therefore we make a next function, that will call the above with the integer sequence 1,2,3,4,...,92,93, like so:
constexpr auto generateArray() noexcept {
return generateArrayHelper(std::make_integer_sequence<size_t, MaxIndexFor64BitValue>());
}
And now, finally,
constexpr auto FIB = generateArray();
will give us a compile-time std::array<unsigned long long, 93> with the name FIB containing all Fibonacci numbers. And if we need the i'th Fibonacci number, then we can simply write FIB[i]. There will be no calculation at runtime.
I do not think that there is a faster way to calculate the n'th Fibonacci number.
Please see the complete program below:
#include <iostream>
#include <array>
#include <utility>
// ----------------------------------------------------------------------
// All the following will be done during compile time
// Constexpr function to calculate the nth Fibonacci number
constexpr unsigned long long getFibonacciNumber(size_t index) {
// Initialize first two even numbers
unsigned long long f1{ 0 }, f2{ 1 };
// calculating Fibonacci value
while (index--) {
// get next value of Fibonacci sequence
unsigned long long f3 = f2 + f1;
// Move to next number
f1 = f2;
f2 = f3;
}
return f2;
}
// We will automatically build an array of Fibonacci numberscompile time
// Generate a std::array with n elements
template <size_t... ManyIndices>
constexpr auto generateArrayHelper(std::integer_sequence<size_t, ManyIndices...>) noexcept {
return std::array<unsigned long long, sizeof...(ManyIndices)>{ { getFibonacciNumber(ManyIndices)... } };
};
// Max index for Fibonaccis that for in an 64bit unsigned value (Binets formula)
constexpr size_t MaxIndexFor64BitValue = 93;
// Generate the required number of elements
constexpr auto generateArray()noexcept {
return generateArrayHelper(std::make_integer_sequence<size_t, MaxIndexFor64BitValue>());
}
// This is an constexpr array of all Fibonacci numbers
constexpr auto FIB = generateArray();
// ----------------------------------------------------------------------
// Test
int main() {
// Print all possible Fibonacci numbers
for (size_t i{}; i < MaxIndexFor64BitValue; ++i)
std::cout << i << "\t--> " << FIB[i] << '\n';
return 0;
}
Developed and tested with Microsoft Visual Studio Community 2019, Version 16.8.2.
Additionally compiled and tested with clang11.0 and gcc10.2
Language: C++17
There's a mistake in your initialize() function:
void initialize() {
for(int i = 0; i < MAX; i++) {
lookup_table[i] == NIL; // <- mistake
}
}
In the line pointed you compare lookup_table[i] and NIL (and don't use the result) instead of assigning NIL to lookup_table[i].
For assignment, you should use = instead of ==.
Also, in such situations the most right thing to do is compilation of your program with all warnings enabled. For example, MS VC++ shows the following warning:
warning C4553: '==': operator has no effect; did you intend '='?
The error is on initialize function (you've used comparison operator '==' where you want a attribution operator '='). But, on semantics, you don't need initialize look_table with -1 (NIL) because Fibonacci results never will be 0 (zero); so, you can initialize it all with zero.
Look below the final solution:
#include <iostream>
#define NIL 0
#define MAX 1000
long int lookup_table[MAX] = {};
using namespace std;
long int fib(int n) {
if(n <= 1)
return n;
return fib(n-1) + fib(n-2);
}
long int fib_mem(int n) {
assert(n < MAX);
if(lookup_table[n] == NIL) {
if(n <= 1)
lookup_table[n] = n;
else
lookup_table[n] = fib_mem(n-1) + fib_mem(n-2);
}
return lookup_table[n];
}
int main() {
int n;
long int fibonnaci, fibonacci_mem;
cout << " n = "; cin >> n;
// naive solution
fibonnaci = fib(n);
// memoized solution
// initialize();
fibonacci_mem = fib_mem(n);
cout << fibonnaci << endl << fibonacci_mem << endl;
return 0;
}

c++, how randomly with given probabilities choose numbers

I have N numbers n_1, n_2, ...n_N and associated probabilities p_1, p_2, ..., p_N.
function should return number n_i with probability p_i, where i =1, ..., N.
How model it in c++?
I know it is not a hard problem. But I am new to c++, want to know what function will you use.
Will you generate uniform random number between 0 and 1 like this:
((double) rand() / (RAND_MAX+1))
This is very similar to the answer I gave for this question:
changing probability of getting a random number
You can do it like this:
double val = (double)rand() / RAND_MAX;
int random;
if (val < p_1)
random = n_1;
else if (val < p_1 + p_2)
random = n_2;
else if (val < p_1 + p_2 + p_3)
random = n_3;
else
random = n_4;
Of course, this approach only makes sense if p_1 + p_2 + p_3 + p_4 == 1.0.
This can easily be generalized to a variable number of outputs and probabilities with a couple of arrays and a simple loop.
If you know the probabilities compile-time you can use this variadic template version I decided to create. Although in actuality, I don't recommend using this due to how horribly incomprehensible the source is :P.
Usage
NumChooser <
Entry<2, 10>, // Value of 2 and relative probability of 10
Entry<5, 50>,
Entry<6, 80>,
Entry<20, 01>
> chooser;
chooser.choose(); // Returns the number 2 on average 10/141 times, etc.
Efficiency
Ideone
Generally, the template based implementation is very similar to a basic one. However, there are a few differences:
With -O2 optimizations or no optimizations, the template version can be ~1-5% slower
With -O3 optimizations, the template version was actually ~1% faster when generating numbers for 1 - 10,000 times consecutively.
Notes
This uses rand() for choosing numbers. If being statistically accurate is important to you or you would like to use C++11's <random>, you can use the slightly modified version below the first source.
Source
Ideone
#define onlyAtEnd(a) typename std::enable_if<sizeof...(a) == 0 > ::type
template<int a, int b>
class Entry
{
public:
static constexpr int VAL = a;
static constexpr int PROB = b;
};
template<typename... EntryTypes>
class NumChooser
{
private:
const int SUM;
static constexpr int NUM_VALS = sizeof...(EntryTypes);
public:
static constexpr int size()
{
return NUM_VALS;
}
template<typename T, typename... args>
constexpr int calcSum()
{
return T::PROB + calcSum < args...>();
}
template <typename... Ts, typename = onlyAtEnd(Ts) >
constexpr int calcSum()
{
return 0;
}
NumChooser() : SUM(calcSum < EntryTypes... >()) { }
template<typename T, typename... args>
constexpr int find(int left, int previous = 0)
{
return left < 0 ? previous : find < args... >(left - T::PROB, T::VAL);
}
template <typename... Ts, typename = onlyAtEnd(Ts) >
constexpr int find(int left, int previous)
{
return previous;
}
constexpr int choose()
{
return find < EntryTypes... >(rand() % SUM);
}
};
C++11 <random> version
Ideone
#include <random>
#define onlyAtEnd(a) typename std::enable_if<sizeof...(a) == 0 > ::type
template<int a, int b>
class Entry
{
public:
static constexpr int VAL = a;
static constexpr int PROB = b;
};
template<typename... EntryTypes>
class NumChooser
{
private:
const int SUM;
static constexpr int NUM_VALS = sizeof...(EntryTypes);
std::mt19937 gen;
std::uniform_int_distribution<> dist;
public:
static constexpr int size()
{
return NUM_VALS;
}
template<typename T, typename... args>
constexpr int calcSum()
{
return T::PROB + calcSum < args...>();
}
template <typename... Ts, typename = onlyAtEnd(Ts) >
constexpr int calcSum()
{
return 0;
}
NumChooser() : SUM(calcSum < EntryTypes... >()), gen(std::random_device{}()), dist(1, SUM) { }
template<typename T, typename... args>
constexpr int find(int left, int previous = 0)
{
return left < 0 ? previous : find < args... >(left - T::PROB, T::VAL);
}
template <typename... Ts, typename = onlyAtEnd(Ts) >
constexpr int find(int left, int previous)
{
return previous;
}
int choose()
{
return find < EntryTypes... >(dist(gen));
}
};
// Same usage as example above
Perhaps something like (untested code!)
/* n is the size of tables, numtab[i] the number of index i,
probtab[i] its probability; the sum of all probtab should be 1.0 */
int random_inside(int n, int numtab[], double probtab[])
{
double r = drand48();
double p = 0.0;
for (int i=0; i<n; i++) {
p += probtab[i];
if (r>=p) return numtab[i];
}
}
Here you have a correct answer in my last comment:
how-to-select-a-value-from-a-list-with-non-uniform-probabilities