Files
primecount/test/isqrt.cpp
2024-06-17 18:36:05 +02:00

179 lines
4.6 KiB
C++

///
/// @file isqrt.cpp
/// @brief Test integer square root function.
///
/// Copyright (C) 2021 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///
#include <isqrt.hpp>
#include <imath.hpp>
#include <int128_t.hpp>
#include <calculator.hpp>
#include <stdint.h>
#include <iostream>
#include <cmath>
#include <cstdlib>
using namespace primecount;
void check(bool OK)
{
std::cout << " " << (OK ? "OK" : "ERROR") << "\n";
if (!OK)
std::exit(1);
}
int main()
{
uint64_t n;
uint64_t res1;
double res2;
for (n = 0; n < 100000; n++)
{
res1 = isqrt(n);
res2 = std::sqrt((double) n);
std::cout << "isqrt(" << n << ") = " << res1;
check(res1 == (uint64_t) res2);
}
n = (1ull << 32) - 1;
res1 = isqrt(n);
res2 = std::sqrt((double) n);
std::cout << "isqrt(" << n << ") = " << res1;
check(res1 == (uint64_t) res2);
n = 1ull << 32;
res1 = isqrt(n);
res2 = std::sqrt((double) n);
std::cout << "isqrt(" << n << ") = " << res1;
check(res1 == (uint64_t) res2);
n = 1000000000000000000ull - 1;
res1 = isqrt(n);
std::cout << "isqrt(" << n << ") = " << res1;
check(res1 == 999999999);
n = 1000000000000000000ull;
res1 = isqrt(n);
std::cout << "isqrt(" << n << ") = " << res1;
check(res1 == 1000000000);
n = pstd::numeric_limits<int8_t>::max();
res1 = isqrt(n);
std::cout << "isqrt(" << n << ") = " << res1;
check(res1 == 11);
n = pstd::numeric_limits<uint8_t>::max();
res1 = isqrt(n);
std::cout << "isqrt(" << n << ") = " << res1;
check(res1 == 15);
n = pstd::numeric_limits<int16_t>::max();
res1 = isqrt(n);
std::cout << "isqrt(" << n << ") = " << res1;
check(res1 == 181);
n = pstd::numeric_limits<uint16_t>::max();
res1 = isqrt(n);
std::cout << "isqrt(" << n << ") = " << res1;
check(res1 == 255);
n = pstd::numeric_limits<int32_t>::max();
res1 = isqrt(n);
std::cout << "isqrt(" << n << ") = " << res1;
check(res1 == 46340);
n = pstd::numeric_limits<uint32_t>::max();
res1 = isqrt(n);
std::cout << "isqrt(" << n << ") = " << res1;
check(res1 == 65535);
n = pstd::numeric_limits<int64_t>::max();
res1 = isqrt(n);
std::cout << "isqrt(" << n << ") = " << res1;
check(res1 == 3037000499ll);
n = pstd::numeric_limits<uint64_t>::max();
res1 = isqrt(n);
std::cout << "isqrt(" << n << ") = " << res1;
check(res1 == 4294967295ull);
#ifdef HAVE_INT128_T
for (n = 0; n < 100000; n++)
{
res1 = isqrt((int128_t) n);
res2 = std::sqrt((double) n);
std::cout << "isqrt(" << n << ") = " << res1;
check(res1 == (uint64_t) res2);
}
int128_t x = ((int128_t) 1) << 100;
int128_t res3 = isqrt(x);
std::cout << "isqrt(" << x << ") = " << res3;
check(res3 == 1ll << 50);
x -= 1;
res3 = isqrt(x);
std::cout << "isqrt(" << x << ") = " << res3;
check(res3 == 1125899906842623ll);
x = ipow<31>((int128_t) 10);
res3 = isqrt(x);
std::cout << "isqrt(" << x << ") = " << res3;
check(res3 == 3162277660168379ll);
x = ipow<30>((int128_t) 10);
res3 = isqrt(x);
std::cout << "isqrt(" << x << ") = " << res3;
check(res3 == 1000000000000000ll);
x -= 1;
res3 = isqrt(x);
std::cout << "isqrt(" << x << ") = " << res3;
check(res3 == 999999999999999ll);
// In my tests the first occurrences where std::sqrt((double) x)
// is off by more than 1 happened above 10^32. If std::sqrt(x)
// is off by more than 1 our isqrt(x) function corrects the
// result using a while loop. Since primecount can only compute
// pi(x) for x <= 10^31 our isqrt(x) function is guaranteed to
// execute in O(1) instructions.
// here std::sqrt((double) x) is 1 too small
x = calculator::eval<int128_t>("443075998594972078030832658571409090");
res3 = isqrt(x);
std::cout << "isqrt(" << x << ") = " << res3;
check(res3 == 665639541039271553ll);
// here std::sqrt((double) x) is 1 too large
x = calculator::eval<int128_t>("443075998594972075382716071791084150");
res3 = isqrt(x);
std::cout << "isqrt(" << x << ") = " << res3;
check(res3 == 665639541039271551ll);
// here std::sqrt((double) x) is 38 too small
x = calculator::eval<int128_t>("443075998594971958032420320541208365");
res3 = isqrt(x);
std::cout << "isqrt(" << x << ") = " << res3;
check(res3 == 665639541039271462ll);
// here std::sqrt((double) x) is 81 too large
x = calculator::eval<int128_t>("443075998594971969939937761777907585");
res3 = isqrt(x);
std::cout << "isqrt(" << x << ") = " << res3;
check(res3 == 665639541039271471ll);
#endif
std::cout << std::endl;
std::cout << "All tests passed successfully!" << std::endl;
return 0;
}