getNthRoots function wrong answers - c++

So i have a function
Vector getNthRoots(double a, double b, double c, int n)
{
Vector v;
int i;
v.length = 0;
double m, a2, b2, c2;
if (n % 2 == 0)
{
a2 = a;
b2 = b;
c2 = c;
if (a<0)
a2 = a*(-1);
if (b<0)
b2 = b*(-1);
if (c<0)
c2 = c*(-1);
m = floor(pow(max(a2, b2, c2),1/n));
for (i = 1; i <= m; i++)
if (pow(i, n) >= min(a2, b2, c2) && pow(i, n) <= max(a2, b2, c2))
{
v.values[v.length] = i;
v.length++;
v.values[v.length] = (-1)*i;
v.length++;
}
return v;
}
else {
for (i = ceil(pow(min(a, b, c),1/n)); i <= floor(pow(max(a, b, c),1/n)); i++)
if (pow(i, n) >= min(a, b, c) && pow(i, n) <= max(a, b, c))
{
v.values[v.length] = i;
v.length++;
}
return v;
}
}
This function is supposed to give you the numbers at power n (number^n) which are in the interval of min(a,b,c) and max(a,b,c);
Other functions/headers
double max(double a, double b, double c)
{
if (a >= b && a >= c)
return a;
if (b >= a && b >= c)
return b;
if (c >= a && c >= b)
return c;
return a;
}
double min(double a, double b, double c)
{
if (a <= b && a <= c)
return a;
if (b <= a && b <= c)
return b;
if (c <= a && c <= b)
return c;
return a;
}
#include <iostream>
#include <cmath>
using namespace std;
#define MAX_ARRAY_LENGTH 100
struct Vector
{
unsigned int length;
int values[MAX_ARRAY_LENGTH];
};
It seems i can`t receive the good answer . For example
for getNthRoots(32,15,37,5) it should return a vector [2] because 2^5 =32 which belongs to interval [15,37] but i don`t receive anything
or getNthRoots(32,1,7,5) it should return a vector [1,2] but i only receive 1 as answer
I am guessing here is the problem for (i = ceil(pow(min(a, b, c),1/n)); i <= floor(pow(max(a, b, c),1/n)); i++)but i don`t know how i could fix it

1/n evaluates to 0, because it is evaluated as an integer expression. Try replacing all the "1/n"s with "1.0/n"s.
Take care to handle the case where n is 0.

Related

sort an array based on number of set bits

Example:
Input: arr = [0,1,2,3,4,5,6,7,8]
Output: [0,1,2,4,8,3,5,6,7]
Explanation: [0] is the only integer with 0 bits.
[1,2,4,8] all have 1 bit.
[3,5,6] have 2 bits.
[7] has 3 bits.
The sorted array by bits is [0,1,2,4,8,3,5,6,7]
I have tried to use custom sorting in C++ but I am not understanding where did I go wrong!
Here's my code!
class Solution {
public:
static int setbits(int temp) {
int c, n = temp;
while(n > 0) {
if(n & 1) c++;
n = n >> 1;
}
return c;
}
static bool myfun(int a, int b) {
int c1 = setbits(a);
int c2 = setbits(b);
if(c1 == c2 || c1 < c2) return a < b;
return a > b;
}
vector<int> sortByBits(vector<int>& arr) {
sort(arr.begin(), arr.end(), myfun);
return arr;
}
};
You forgot to initialize c in the setbits function:
int c = 0;
Moreover, there was a problem in the logic of the comparator. I get correct result with
if (c1 == c2) return a < b;
return c1 < c2;
Note that the code could be more efficient by first calculating the weight of all numbers and keep them in a array.
Replace
if(c1 == c2 || c1 < c2) return a < b;
return a > b;
with
return (c1 <= c2 );

Compare roots of quadratic functions

I need function to fast compare root of quadratic function and a given value and function to fast compare two roots of two quadratic functions.
I write first function
bool isRootLessThanValue (bool sqrtDeltaSign, int a, int b, int c, int value) {
bool ret;
if(sqrtDeltaSign){
if(a < 0){
ret = (2*a*value + b < 0) || (a*value*value + b*value + c > 0);
}else{
ret = (2*a*value + b > 0) && (a*value*value + b*value + c > 0);
}
}else{
if(a < 0){
ret = (2*a*value + b < 0) && (a*value*value + b*value + c < 0);
}else{
ret = (2*a*value + b > 0) || (a*value*value + b*value + c < 0);
}
}
return ret;
};
When i try to write this for second function it grow to very big and complicated...
bool isRoot1LessThanRoot2 (bool sqrtDeltaSign1, int a1, int b1, int c1, bool sqrtDeltaSign2, int a2, int b2, int c2) {
//...
}
Have u any suggestions how can i simplify this function?
If you think thats stupid idea for optimizations, please tell me why :)
I give a simpified version of the first part of your code by comparing the greater root of the quadratic function with a given value as follows:
#include <iostream>
#include <cmath> // for main testing
int isRootLessThanValue (int a, int b, int c, int value)
{
if (a<0){ b *= -1; c *= -1; a *= -1;}
int xt, delta;
xt = 2 * a * value + b;
if (xt < 0) return false; // value is left to reflection point
delta = b*b - 4*a*c;
// compare square distance between value and the root
return ( (xt * xt) > delta )? true: false;
}
In the test main() program, the roots are first calculate for clarity purpose:
int main()
{
int a, b, c, v;
a = -2;
b = 4;
c = 3;
double r1, r2, r, dt;
dt = std::sqrt(b*b-4.0*a*c);
r1 = (-b + dt) / (2.0*a);
r2 = (-b - dt) / (2.0*a);
r = (r1>r2)? r1 : r2;
while (1)
{
std::cout << "Input the try value = ";
std::cin >> v;
if (isRootLessThanValue(a,b,c,v)) std::cout << v <<" > " << r << std::endl;
else std::cout << v <<" < " << r << std::endl;
}
return 0;
}
A test run
The following assumes that both quadratics have real, mutually distinct roots, and a1 = a2 = 1. This keeps the notations simpler, though similar logic can be used in the general case.
Suppose f(x) = x^2 + b1 x + c1 has the real roots u1 < u2, and g(x) = x^2 + b2 x + c2 has the real roots v1 < v2. Then there are 6 possible sort orders.
(1)   u1 < u2 < v1 < v2
(2)   u1 < v1 < u2 < v2
(3)   u1 < v1 < v2 < u2
(4)   v1 < u1 < u2 < v2
(5)   v1 < u1 < v2 < u2
(6)   v1 < v2 < u1 < u2
Let v be a root of g so that g(v) = v^2 + b2 v + c2 = 0 then v^2 = -b2 v - c2 and therefore f(v) = (b1 - b2) v + c1 - c2 = b12 v + c12 where b12 = b1 - b2 and c12 = c1 - c2.
It follows that Sf = f(v1) + f(v2) = b12(v1 + v2) + 2 c12 and Pf = f(v1) f(v2) = b12^2 v1 v2 + b12 c12 (v1 + v2) + c12^2. Using Vieta's relations v1 v2 = c2 and v1 + v2 = -b2 so in the end Sf = f(v1) + f(v2) = -b12 b2 + 2 c2 and Pf = f(v1) f(v2) = b12^2 c2 - b12 c12 b2 + c12^2. Similar expressions can be calculated for Sg = g(u1) + g(u2) and Pg = g(u1) g(u2).
(Should be noted that Sf, Pf, Sg, Pg above are arithmetic expressions in the coefficients, not involving sqrt square roots. There is, however, the potential for integer overflow. If that is an actual concern, then the calculations would have to be done in floating point instead of integers.)
If Pf = f(v1) f(v2) < 0 then exactly one root of f is between the roots v1, v2 of g.
If the axis of f is to the left of the g one, meaning -b1 < -b2, then that's the smaller root u1 of f which is between v1, v2 i.e. case (5).
Otherwise if -b1 > -b2 then that's the larger root i.e. case (2).
If Pf = f(v1) f(v2) > 0 then either both or none of the roots of f are between the roots of g. In this case f(v1) and f(v2) must have the same sign, and they will either be both negative if Sf = f(v1) + f(v2) < 0 or both positive if Sf > 0.
If f(v1) < 0 and f(v2) < 0 then both roots v1, v2 of g are between the roots of f i.e. case (3).
By symmetry, if Pg > 0 and Sg < 0 then g(u1) < 0 and g(u2) < 0, so both roots u1, u2 of f are between the roots of g i.e. case (4).
Otherwise the last combination left is f(v1), f(v2) > 0 and g(u1), g(u2) > 0 where the intervals (u1, u2) and (v1, v2) do not overlap. If -b1 < -b2 the axis of f is to the left of the g one i.e. case (1) else it's case (6).
Once the sort order between all roots is determined, comparing any particular pair of roots follows.
We are definitely talking micro-optimization here, but consider making calculations before performing the comparison:
bool isRootLessThanValue (bool sqrtDeltaSign, int a, int b, int c, int value)
{
const int a_value = a * value;
const int two_a_b_value = 2 * a_value + b;
const int a_squared_b = a_value * value + b * value + c;
const bool two_ab_less_zero = (two_a_b_value < 0);
bool ret = false;
if(sqrtDeltaSign)
{
const bool a_squared_b_greater_zero = (a_squared_b > 0);
if (a < 0)
{
ret = two_ab_less_zero || a_squared_b_greater_zero;
}
else
{
ret = !two_ab_less_zero && a_squared_b_greater_zero;//(edited)
}
}
else
{
const bool a_squared_b_less_zero = (a_squared_b < 0);
if (a < 0)
{
ret = two_ab_less_zero && a_squared_b_less_zero;
}
else
{
ret = !two_ab_less_zero || a_squared_b_less_zero;//(edited)
}
}
return ret;
};
Another note, is that the boolean expression is calculated and stored in a variable, thus could be counted as a data processing instruction (depending on the compiler and processor).
Compare the assembly language of this function to yours. Also benchmark. As I said, I'm not expecting much time savings here, but I don't know how many times this function is called in your code.
Im reorganising my code and have found some facilities :)
When calculate a, b and c i can keep structure to get only a > 0 :)
and i know that i want small or big root :)
so function to compare root to value is regresed to the form below
bool isRootMinLessThanValue (int a, int b, int c, int value) {
const int a_value = a * value;
const int u = 2*a_value + b;
const int v = a_value*value + b*value + c;
return u > 0 || v < 0 ;
};
bool isRootMaxLessThanValue (int a, int b, int c, int value) {
const int a_value = a*value;
const int u = 2*a_value + b;
const int v = a_value*value + b*value + c;
return u > 0 && v > 0;
}
when im testing benchmark its faster than calculate roots traditionaly (by assumptions I cannot say how much)
Below code for fast (and slow traditionaly) compare root to value without assumptions
bool isRootLessThanValue (bool sqrtDeltaSign, int a, int b, int c, int value) {
const int a_value = a*value;
const int u = 2*a_value + b;
const int v = a_value*value + b*value + c;
const bool s = sqrtDeltaSign;
return ( a < 0 && s && u < 0 ) ||
( a < 0 && s && v > 0 ) ||
( a < 0 && !s && u < 0 && v < 0) ||
(!(a < 0) && !s && u > 0 ) ||
(!(a < 0) && !s && v < 0 ) ||
(!(a < 0) && s && u > 0 && v > 0);
};
bool isRootLessThanValueTraditional (bool sqrtDeltaSign, int a, int b, int c, int value) {
double delta = b*b - 4.0*a*c;
double calculatedRoot = sqrtDeltaSign ? (-b + sqrt(delta))/(2.0*a) : (-b - sqrt(delta))/(2.0*a);
return calculatedRoot < value;
};
benchmark results below:
isRootLessThanValue (optimized): 10000000000 compares in 152.922s
isRootLessThanValueTraditional : 10000000000 compares in 196.168s
Any suggestions how can i simplify even more isRootLessThanValue function? :)
I will try to prepare function to compare two roots of different equations
edited::2020-11-30
bool isRootLessThanValue (bool sqrtDeltaSign, int a, int b, int c, int value) {
const int a_value = a*value;
const int u = 2*a_value + b;
const int v = a_value*value + b*value + c;
return sqrtDeltaSign ?
(( a < 0 && (u < 0 || v > 0) ) || (u > 0 && v > 0)) :
(( a > 0 && (u > 0 || v < 0) ) || (u < 0 && v < 0));
};

cubic function root bisection search time limit exceeded

I have implemented this solution for finding a root of a cubic function
f(x) = ax3 + bx2 + cx + d
given a, b, c, and d, ensuring it's being monotonic.
After submitting the solution to an online judge without being shown the test cases, I am being faced by a time limit error. a, b, c, and d guarantee that the function is monotonic and we know it is being continuous. The code first finds the interval [A, B] such that f(A) * f(B) < 0; then the code moves to implement the bisection search.
What I want to know is if there is some possibility to minimize the time complexity of my code so it passes the online judge. The input is a, b, c, d, and the output should be the root with an error 0.000001.
Code:
#include <iostream>
#include <algorithm>
//#include <cmath>
//#include <string>
using namespace std;
int f(double a, double b, double c, double d, double x) {
return x*(x*(a*x + b) + c) + d;
}
int main() {
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
double a, b, c, d, A, B, x = 1, res;
cin >> a >> b >> c >> d;
//determinning the interval
double f_x = f(a, b, c, d, x);
if (a > 0) { // strictly increasing
if (f_x > 0) { B = 0;
while (f(a, b, c, d, x) >= 0) { x -= x; }
A = x; }
else { A = 0;
while (f(a, b, c, d, x) <= 0) { x += x; }
B = x; }
}
else { //strictly decreasing
if (f_x > 0) { A = 0;
while (f(a, b, c, d, x) >= 0) { x += x; }
B = x; }
else { B = 0;
while (f(a, b, c, d, x) <= 0) { x -= x; }
A = x; }
}
// Bisection Search
double l = A;
while ((B - A) >= 0.000001)
{
// Find middle point
l = (A + B) / 2;
// Check if middle point is root
if (f(a, b, c, d, l) == 0.0)
break;
// Decide the side to repeat the steps
else if (f(a, b, c, d, l)*f(a, b, c, d, A) < 0)
B = l;
else
A = l;
}
res = l;
cout.precision(6);
cout << fixed << " " << res;
return 0;
}
There is no need to determine the initial interval, just take [-DBL_MAX, +DBL_MAX]. The tolerance can be chosen to be 1 ULP.
The following code implements these ideas:
// This function will be available in C++20 as std::midpoint
double midpoint(double x, double y) {
if (std::isnormal(x) && std::isnormal(y))
return x / 2 + y / 2;
else
return (x + y) / 2;
}
int main() {
...
const auto fn = [=](double x) { return x * (x * (x * a + b) + c) + d; };
auto left = -std::numeric_limits<double>::max();
auto right = std::numeric_limits<double>::max();
while (true) {
const auto mid = midpoint(left, right);
if (mid <= left || mid >= right)
break;
if (std::signbit(fn(left)) == std::signbit(fn(mid)))
left = mid;
else
right = mid;
}
const double answer = left;
...
}
Initially, fn(x) can overflow and return inf. No special handling of this case is needed.

C++ returning wrong integer on if statement

I am using HackerRank which will input 4 numbers (3, 4, 6, 5) respectively for the parameters and the task is to be able to return the highest number, however when I compile this program it will output 3 (a) instead of 6 (b) and I am unsure where I am going wrong.
#include <iostream>
#include <cstdio>
using namespace std;
int max_of_four(int a, int b, int c, int d) {
if ((a > b) && (a > c) && (a > d)) {
return a;
}
if ((b > a) && (b > c) && (b > d)) {
return a;
}
if ((c > b) && (c > a) && (c > d)) {
return a;
}
else {
return d;
}
}
int main() {
int a, b, c, d;
scanf("%d %d %d %d", &a, &b, &c, &d);
int ans = max_of_four(a, b, c, d);
printf("%d", ans);
return 0;
}
Instead have this simpler version:
int max_of_four(int a, int b, int c, int d) {
int max = a;
if(b > max) max = b;
if(c > max) max = c;
if(d > max) max = d;
return max;
}
second and third return statements return a instead of b and c.
You are not returning right variables in 2nd and 3rd if statements. Return b and c.

C++ strange jump in unsigned long long int values

I have the following question, which is actually from a coding test I recently took:
Question:
A function f(n) = a*n + b*n*(floor(log(n)/log(2))) + c*n*n*n exists.
At a particular value, let f(n) = k;
Given k, a, b, c, find n.
For a given value of k, if no n value exists, then return 0.
Limits:
1 <= n < 2^63-1
0 < a, b < 100
0 <= c < 100
0 < k < 2^63-1
The logic here is that since f(n) is purely increasing for a given a, b and c, I can find n by binary search.
The code I wrote was as follows:
#include<iostream>
#include<stdlib.h>
#include<math.h>
using namespace std;
unsigned long long logToBase2Floor(unsigned long long n){
return (unsigned long long)(double(log(n))/double(log(2)));
}
#define f(n, a, b, c) (a*n + b*n*(logToBase2Floor(n)) + c*n*n*n)
unsigned long long findNByBinarySearch(unsigned long long k, unsigned long long a, unsigned long long b, unsigned long long c){
unsigned long long low = 1;
unsigned long long high = (unsigned long long)(pow(2, 63)) - 1;
unsigned long long n;
while(low<=high){
n = (low+high)/2;
cout<<"\n\n k= "<<k;
cout<<"\n f(n,a,b,c)= "<<f(n,a,b,c)<<" low = "<<low<<" mid="<<n<<" high = "<<high;
if(f(n,a,b,c) == k)
return n;
else if(f(n,a,b,c) < k)
low = n+1;
else high = n-1;
}
return 0;
}
I then tried it with a few test cases:
int main(){
unsigned long long n, a, b, c;
n = (unsigned long long)pow(2,63)-1;
a = 99;
b = 99;
c = 99;
cout<<"\nn="<<n<<" a="<<a<<" b="<<b<<" c="<<c<<" k = "<<f(n, a, b, c);
cout<<"\nANSWER: "<<findNByBinarySearch(f(n, a, b, c), a, b, c)<<endl;
n = 1000;
cout<<"\nn="<<n<<" a="<<a<<" b="<<b<<" c="<<c<<" k = "<<f(n, a, b, c);
cout<<"\nANSWER: "<<findNByBinarySearch(f(n, a, b, c), a, b, c)<<endl;
return 0;
}
Then something weird happened.
The code works for the test case n = (unsigned long long)pow(2,63)-1;, correctly returning that value of n. But it did not work for n=1000. I printed the output and saw the following:
n=1000 a=99 b=99 c=99 k = 99000990000
k= 99000990000
f(n,a,b,c)= 4611686018427387904 low = 1 mid=4611686018427387904 high = 9223372036854775807
...
...
k= 99000990000
f(n,a,b,c)= 172738215936 low = 1 mid=67108864 high = 134217727
k= 99000990000
f(n,a,b,c)= 86369107968 low = 1 mid=33554432 high = 67108863
k= 99000990000
f(n,a,b,c)= 129553661952 low = 33554433 mid=50331648 high = 67108863**
...
...
k= 99000990000
f(n,a,b,c)= 423215328047139441 low = 37748737 mid=37748737 high = 37748737
ANSWER: 0
Something didn't seem right mathematically. How was it that the value of f(1000) was greater than the value of f(33554432)?
So I tried the same code in Python, and got the following values:
>>> f(1000, 99, 99, 99)
99000990000L
>>> f(33554432, 99, 99, 99)
3740114254432845378355200L
So, the value is definitely larger.
Questions:
What is happening exactly?
How should I solve it?
What is happening exactly?
The problem is here:
unsigned long long low = 1;
// Side note: This is simply (2ULL << 62) - 1
unsigned long long high = (unsigned long long)(pow(2, 63)) - 1;
unsigned long long n;
while (/* irrelevant */) {
n = (low + high) / 2;
// Some stuff that do not modify n...
f(n, a, b, c) // <-- Here!
}
In the first iteration, you have low = 1 and high = 2^63 - 1, which mean that n = 2^63 / 2 = 2^62. Now, let's look at f:
#define f(n, a, b, c) (/* I do not care about this... */ + c*n*n*n)
You have n^3 in f, so for n = 2^62, n^3 = 2^186, which is probably way too large for your unsigned long long (which is likely to be 64-bits long).
How should I solve it?
The main issue here is overflow when doing the binary search, so you should simply handle the overflowing case separatly.
Preamble: I am using ull_t because I am lazy, and you should avoid macro in C++, prefer using a function and let the compiler inline it. Also, I prefer a loop against using the log function to compute the log2 of an unsigned long long (see the bottom of this answer for the implementation of log2 and is_overflow).
using ull_t = unsigned long long;
constexpr auto f (ull_t n, ull_t a, ull_t b, ull_t c) {
if (n == 0ULL) { // Avoid log2(0)
return 0ULL;
}
if (is_overflow(n, a, b, c)) {
return 0ULL;
}
return a * n + b * n * log2(n) + c * n * n * n;
}
Here is slightly modified binary search version:
constexpr auto find_n (ull_t k, ull_t a, ull_t b, ull_t c) {
constexpr ull_t max = std::numeric_limits<ull_t>::max();
auto lb = 1ULL, ub = (1ULL << 63) - 1;
while (lb <= ub) {
if (ub > max - lb) {
// This should never happens since ub < 2^63 and lb <= ub so lb + ub < 2^64
return 0ULL;
}
// Compute middle point (no overflow guarantee).
auto tn = (lb + ub) / 2;
// If there is an overflow, then change the upper bound.
if (is_overflow(tn, a, b, c)) {
ub = tn - 1;
}
// Otherwize, do a standard binary search...
else {
auto val = f(tn, a, b, c);
if (val < k) {
lb = tn + 1;
}
else if (val > k) {
ub = tn - 1;
}
else {
return tn;
}
}
}
return 0ULL;
}
As you can see, there is only one test that is relevant here, which is is_overflow(tn, a, b, c) (the first test regarding lb + ub is irrelevant here since ub < 2^63 and lb <= ub < 2^63 so ub + lb < 2^64 which is ok for unsigned long long in our case).
Complete implementation:
#include <limits>
#include <type_traits>
using ull_t = unsigned long long;
template <typename T,
typename = std::enable_if_t<std::is_integral<T>::value>>
constexpr auto log2 (T n) {
T log = 0;
while (n >>= 1) ++log;
return log;
}
constexpr bool is_overflow (ull_t n, ull_t a, ull_t b, ull_t c) {
ull_t max = std::numeric_limits<ull_t>::max();
if (n > max / a) {
return true;
}
if (n > max / b) {
return true;
}
if (b * n > max / log2(n)) {
return true;
}
if (c != 0) {
if (n > max / c) return true;
if (c * n > max / n) return true;
if (c * n * n > max / n) return true;
}
if (a * n > max - c * n * n * n) {
return true;
}
if (a * n + c * n * n * n > max - b * n * log2(n)) {
return true;
}
return false;
}
constexpr auto f (ull_t n, ull_t a, ull_t b, ull_t c) {
if (n == 0ULL) {
return 0ULL;
}
if (is_overflow(n, a, b, c)) {
return 0ULL;
}
return a * n + b * n * log2(n) + c * n * n * n;
}
constexpr auto find_n (ull_t k, ull_t a, ull_t b, ull_t c) {
constexpr ull_t max = std::numeric_limits<ull_t>::max();
auto lb = 1ULL, ub = (1ULL << 63) - 1;
while (lb <= ub) {
if (ub > max - lb) {
return 0ULL; // Problem here
}
auto tn = (lb + ub) / 2;
if (is_overflow(tn, a, b, c)) {
ub = tn - 1;
}
else {
auto val = f(tn, a, b, c);
if (val < k) {
lb = tn + 1;
}
else if (val > k) {
ub = tn - 1;
}
else {
return tn;
}
}
}
return 0ULL;
}
Compile time check:
Below is a little piece of code that you can use to check if the above code at compile time (since everything is constexpr):
template <unsigned long long n, unsigned long long a,
unsigned long long b, unsigned long long c>
struct check: public std::true_type {
enum {
k = f(n, a, b, c)
};
static_assert(k != 0, "Value out of bound for (n, a, b, c).");
static_assert(n == find_n(k, a, b, c), "");
};
template <unsigned long long a,
unsigned long long b,
unsigned long long c>
struct check<0, a, b, c>: public std::true_type {
static_assert(a != a, "Ambiguous values for n when k = 0.");
};
template <unsigned long long n>
struct check<n, 0, 0, 0>: public std::true_type {
static_assert(n != n, "Ambiguous values for n when a = b = c = 0.");
};
#define test(n, a, b, c) static_assert(check<n, a, b, c>::value, "");
test(1000, 99, 99, 0);
test(1000, 99, 99, 99);
test(453333, 99, 99, 99);
test(495862, 99, 99, 9);
test(10000000, 1, 1, 0);
Note: The maximum value of k is about 2^63, so for a given triplet (a, b, c), the maximum value of n is the one such as f(n, a, b, c) < 2 ^ 63 and f(n + 1, a, b, c) >= 2 ^ 63. For a = b = c = 99, this maximum value is n = 453333 (empirically found), which is why I tested it above.