-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Number_types: fix Lazy_exact_nt operator<< to write exact() value #9431
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 7 commits
c2b1004
5013864
a3c59ff
299654d
eaf296e
c890824
fbc2039
483027e
8ccae13
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,179 @@ | ||||||||
| // Regression test for issue #135: | ||||||||
| // Lazy_exact_nt operator<< used to_double(), losing precision and breaking | ||||||||
| // round-trip save/load of exact kernel coordinates. | ||||||||
| // | ||||||||
| // The default operator<< still writes to_double(). CGAL::IO::set_exact_mode(os) | ||||||||
| // switches it to write the exact value. For a rational backend (Exact_rational) | ||||||||
| // that round-trips losslessly through operator>>; for CORE::Expr, whose operator<< | ||||||||
| // writes a decimal approximation, exact mode is not lossless (see Test 9). | ||||||||
|
|
||||||||
| #include <CGAL/Lazy_exact_nt.h> | ||||||||
| #include <CGAL/Exact_rational.h> | ||||||||
|
|
||||||||
| #include <CGAL/CORE_Expr.h> | ||||||||
|
|
||||||||
| #include <cassert> | ||||||||
| #include <iostream> | ||||||||
| #include <sstream> | ||||||||
| #include <string> | ||||||||
|
|
||||||||
| typedef CGAL::Lazy_exact_nt<CGAL::Exact_rational> Lazy_nt; | ||||||||
|
|
||||||||
| int main() | ||||||||
| { | ||||||||
| // Test 1: exact rational round-trip | ||||||||
| { | ||||||||
| std::cout << "Test 1: round-trip of 1/3" << std::endl; | ||||||||
| Lazy_nt a(CGAL::Exact_rational(1, 3)); | ||||||||
| std::ostringstream oss; | ||||||||
| CGAL::IO::set_exact_mode(oss); | ||||||||
| oss << a; | ||||||||
| // Should output "1/3", not "0.333333..." | ||||||||
| std::istringstream iss(oss.str()); | ||||||||
| Lazy_nt b; | ||||||||
| iss >> b; | ||||||||
| assert(iss); | ||||||||
| assert(a == b); | ||||||||
| std::cout << " OK: wrote \"" << oss.str() << "\", read back equal" << std::endl; | ||||||||
| } | ||||||||
|
|
||||||||
| // Test 2: integer value | ||||||||
| { | ||||||||
| std::cout << "Test 2: round-trip of 42" << std::endl; | ||||||||
| Lazy_nt a(42); | ||||||||
| std::ostringstream oss; | ||||||||
| CGAL::IO::set_exact_mode(oss); | ||||||||
| oss << a; | ||||||||
| std::istringstream iss(oss.str()); | ||||||||
| Lazy_nt b; | ||||||||
| iss >> b; | ||||||||
| assert(iss); | ||||||||
| assert(a == b); | ||||||||
|
Comment on lines
+47
to
+51
|
||||||||
| std::cout << " OK: wrote \"" << oss.str() << "\"" << std::endl; | ||||||||
| } | ||||||||
|
|
||||||||
| // Test 3: negative rational | ||||||||
| { | ||||||||
| std::cout << "Test 3: round-trip of -5/7" << std::endl; | ||||||||
| Lazy_nt a(CGAL::Exact_rational(-5, 7)); | ||||||||
| std::ostringstream oss; | ||||||||
| CGAL::IO::set_exact_mode(oss); | ||||||||
| oss << a; | ||||||||
| std::istringstream iss(oss.str()); | ||||||||
| Lazy_nt b; | ||||||||
| iss >> b; | ||||||||
| assert(iss); | ||||||||
| assert(a == b); | ||||||||
|
Comment on lines
+62
to
+66
|
||||||||
| std::cout << " OK: wrote \"" << oss.str() << "\"" << std::endl; | ||||||||
| } | ||||||||
|
|
||||||||
| // Test 4: value that cannot be represented exactly as double | ||||||||
| // 1/3 + 1/7 = 10/21, to_double() would give 0.476190476190... | ||||||||
| { | ||||||||
| std::cout << "Test 4: round-trip of computed 1/3 + 1/7 = 10/21" << std::endl; | ||||||||
| Lazy_nt a(CGAL::Exact_rational(1, 3)); | ||||||||
| Lazy_nt b(CGAL::Exact_rational(1, 7)); | ||||||||
| Lazy_nt c = a + b; | ||||||||
| std::ostringstream oss; | ||||||||
| CGAL::IO::set_exact_mode(oss); | ||||||||
| oss << c; | ||||||||
| std::istringstream iss(oss.str()); | ||||||||
| Lazy_nt d; | ||||||||
| iss >> d; | ||||||||
|
||||||||
| iss >> d; | |
| iss >> d; | |
| assert(iss); |
Copilot
AI
Apr 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue as above: assert successful extraction after iss >> b so the test can’t pass if parsing fails.
Copilot
AI
Apr 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue as above: because the expected value is 0 here, a failed parse could leave b at the default value and make the assertion pass. Add an assert(iss) / assert(!iss.fail()) after iss >> b.
| iss >> b; | |
| iss >> b; | |
| assert(iss); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test doesn’t verify that extraction succeeded (stream state) before comparing values. If parsing fails,
bcan remain at its default value (which is 0 for Lazy_exact_nt), potentially making the test pass spuriously (notably in the zero case). Add an assertion likeassert(iss)/assert(!iss.fail())afteriss >> b(and similarly in the other test blocks).