mirror of
https://github.com/kimwalisch/primecount.git
synced 2026-06-07 03:09:48 +09:00
179 lines
4.6 KiB
C++
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;
|
|
}
|