I am unable to tell the clang compiler to perform tail-recursive optimisation in my C++ code. I saw this post Which, if any, C++ compilers do tail-recursion optimization?, where the advice is to use the -O3 flag with clang and it would do it. But in spite of that, I am having stack overflow for large inputs to the below primality testing code.
#include <iostream>
#include <chrono>
#include <gmp.h>
#include <string>
bool mpz_is_divisible(mpz_t n, mpz_t d);
void mpz_sqr(mpz_t res, mpz_t x) {
//computes square of x and puts the result into res
mpz_pow_ui(res, x, 2);
}
//the below function causes stack overflow for large inputs
void smallest_divisor(mpz_t n, mpz_t div, mpz_t div_sqr, mpz_t smallest_div) {
//finds the smallest number which divides n and puts the result into smallest_div
mpz_sqr(div_sqr, div);
if (mpz_cmp(div_sqr, n) > 0) {
mpz_set(smallest_div, n);
return;
}
if (mpz_is_divisible(n, div)) {
mpz_set(smallest_div, div);
return;
}
mpz_add_ui(div, div, 1);
smallest_divisor(n, div, div_sqr, smallest_div); //<-- should do tail recursion optimisation?
}
bool mpz_prime_test_basic(mpz_t n) {
//checks if n is prime
mpz_t div, div_sqr, smallest_div;
mpz_inits(div, div_sqr, smallest_div, NULL);
mpz_set_ui(div, 2);
smallest_divisor(n, div, div_sqr, smallest_div);
if (mpz_cmp(smallest_div, n) == 0) {
mpz_clear(div);
mpz_clear(div_sqr);
mpz_clear(smallest_div);
return true;
}
mpz_clear(div);
mpz_clear(div_sqr);
mpz_clear(smallest_div);
return false;
}
bool mpz_is_divisible(mpz_t n, mpz_t d) {
//checks if n is divisible by d
mpz_t rem;
mpz_init(rem);
mpz_tdiv_r(rem, n, d);
int cmp = mpz_cmp_si(rem, 0); //checks if remainder is equal to 0
if (cmp == 0) return true;
return false;
}
int main() {
std::string num_str;
mpz_t num;
mpz_init(num);
std::cout << "Enter number to check" << '\n';
std::cin >> num_str;
mpz_set_str(num, num_str.c_str(), 10);
bool is_prime = mpz_prime_test_basic(num);
if (is_prime) {
std::cout << num_str << " is a prime\n";
} else {
std::cout << num_str << " is not a prime\n";
}
return 0;
}
I am going through chapter 1 of SICP right now and there's an exercise (1.22) about checking primality using an O(√n) algorithm. Tail-recursion is enforced by the Scheme standard, hence there is no problem there for large inputs but I am doing the same problem in C++, and for large numbers, the smallest-divisor function consumes the stack. I am using the GMP library for big integer arithmetic.
Is it possible to enforce tail recursion in such a program?
Thanks