Skip to content

Commit 08ea260

Browse files
Number_types: add regression test for to_interval(cpp_int) with large values
Add a dedicated test that exercises CGAL::to_interval() on boost::multiprecision::cpp_int values whose double conversion overflows to infinity (2^10000, 2^1024, -2^10000), as well as well-behaved values (2^52, 2^100, 0). The old implementation in RET_boost_mp_base::To_interval called x.compare(double), which Boost.MP implements via convert_to<number>, throwing 'Cannot convert a non-finite number to an integer' when the double is ±infinity. The fix (integer specialization dispatching to Boost_MP_internal::to_interval, using bit-level extraction) is already in place; this test ensures it does not regress. Closes #5990
1 parent a3e5596 commit 08ea260

2 files changed

Lines changed: 117 additions & 0 deletions

File tree

Number_types/test/Number_types/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ create_single_source_cgal_program("Sqrt_extension_true.cpp")
5757
create_single_source_cgal_program("_test_valid_finite_double.cpp")
5858
create_single_source_cgal_program("_test_valid_finite_float.cpp")
5959
create_single_source_cgal_program("to_interval_test.cpp")
60+
create_single_source_cgal_program("to_interval_cpp_int_large.cpp")
6061
create_single_source_cgal_program("unsigned.cpp")
6162
create_single_source_cgal_program("utilities.cpp")
6263
create_single_source_cgal_program("Exact_rational.cpp")
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Regression test for https://github.com/CGAL/cgal/issues/5990
2+
//
3+
// to_interval(cpp_int) threw "Cannot convert a non-finite number to an
4+
// integer" for values whose double conversion overflows to infinity.
5+
// The old implementation called x.compare(double), which Boost.MP
6+
// implements via convert_to<number>, failing on ±infinity.
7+
//
8+
// The fix (Boost_MP_internal::to_interval) uses bit-level extraction
9+
// instead. This test ensures the fix does not regress.
10+
11+
#include <cassert>
12+
#include <cmath>
13+
#include <iostream>
14+
#include <limits>
15+
16+
#ifndef CGAL_DO_NOT_USE_BOOST_MP
17+
#include <CGAL/boost_mp.h>
18+
#endif
19+
20+
int main()
21+
{
22+
#ifndef CGAL_DO_NOT_USE_BOOST_MP
23+
typedef boost::multiprecision::cpp_int I;
24+
const double inf = std::numeric_limits<double>::infinity();
25+
26+
std::cout << "Testing to_interval(cpp_int) for large numbers (issue #5990)..."
27+
<< std::endl;
28+
29+
// --- Exact reproducer from the issue ---
30+
// i = 2^10000, which overflows double to +inf.
31+
// The old code threw std::runtime_error here.
32+
{
33+
I i = 1;
34+
i <<= 10000;
35+
auto interval = CGAL::to_interval(i);
36+
double lo = interval.first;
37+
double hi = interval.second;
38+
std::cout << " 2^10000: [" << lo << ", " << hi << "]" << std::endl;
39+
assert(lo > 0);
40+
assert(hi == inf || hi == (std::numeric_limits<double>::max)());
41+
assert(lo <= hi);
42+
// The lower bound must be at least double_max.
43+
assert(lo >= (std::numeric_limits<double>::max)());
44+
}
45+
46+
// --- Negative large value ---
47+
{
48+
I i = -1;
49+
i <<= 10000;
50+
auto interval = CGAL::to_interval(i);
51+
double lo = interval.first;
52+
double hi = interval.second;
53+
std::cout << " -2^10000: [" << lo << ", " << hi << "]" << std::endl;
54+
assert(hi < 0);
55+
assert(lo == -inf || lo == std::numeric_limits<double>::lowest());
56+
assert(lo <= hi);
57+
assert(hi <= std::numeric_limits<double>::lowest());
58+
}
59+
60+
// --- Moderately large value: 2^1024 (just above double_max ≈ 2^1023.999) ---
61+
{
62+
I i = 1;
63+
i <<= 1024;
64+
auto interval = CGAL::to_interval(i);
65+
double lo = interval.first;
66+
double hi = interval.second;
67+
std::cout << " 2^1024: [" << lo << ", " << hi << "]" << std::endl;
68+
assert(lo > 0);
69+
assert(lo <= hi);
70+
assert(lo >= (std::numeric_limits<double>::max)());
71+
}
72+
73+
// --- Value that fits in double: 2^52 ---
74+
{
75+
I i = 1;
76+
i <<= 52;
77+
auto interval = CGAL::to_interval(i);
78+
double lo = interval.first;
79+
double hi = interval.second;
80+
double expected = std::ldexp(1.0, 52);
81+
std::cout << " 2^52: [" << lo << ", " << hi << "]" << std::endl;
82+
assert(lo == expected);
83+
assert(hi == expected);
84+
}
85+
86+
// --- Zero ---
87+
{
88+
I i = 0;
89+
auto interval = CGAL::to_interval(i);
90+
std::cout << " 0: [" << interval.first << ", " << interval.second << "]"
91+
<< std::endl;
92+
assert(interval.first == 0.0);
93+
assert(interval.second == 0.0);
94+
}
95+
96+
// --- Large value that is exactly representable: 2^100 ---
97+
{
98+
I i = 1;
99+
i <<= 100;
100+
auto interval = CGAL::to_interval(i);
101+
double lo = interval.first;
102+
double hi = interval.second;
103+
double expected = std::ldexp(1.0, 100);
104+
std::cout << " 2^100: [" << lo << ", " << hi << "]" << std::endl;
105+
assert(lo == expected);
106+
assert(hi == expected);
107+
}
108+
109+
std::cout << "All tests passed." << std::endl;
110+
111+
#else
112+
std::cout << "Test skipped (Boost.Multiprecision not available)." << std::endl;
113+
#endif
114+
115+
return 0;
116+
}

0 commit comments

Comments
 (0)