From 334181775be4af1c609bf3bffc1239e68473c8d7 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 10 Aug 2021 16:29:58 +0200 Subject: [PATCH 001/127] add flag to disable gmpxx support --- Installation/CMakeLists.txt | 5 +++++ Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake | 3 +++ Installation/cmake/modules/CGAL_SetupGMP.cmake | 4 +++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Installation/CMakeLists.txt b/Installation/CMakeLists.txt index 16abec88e952..8b404e4c6aab 100644 --- a/Installation/CMakeLists.txt +++ b/Installation/CMakeLists.txt @@ -517,6 +517,11 @@ if($ENV{CGAL_DISABLE_GMP}) ON CACHE INTERNAL "") endif() +if($ENV{CGAL_DISABLE_GMPXX}) + set(CGAL_DISABLE_GMPXX + ON + CACHE INTERNAL "") +endif() if(CGAL_DISABLE_GMP) message("Disable the GMP support") list(LENGTH CGAL_ESSENTIAL_3RD_PARTY_LIBRARIES CGAL_ESSENTIAL_LENGTH) diff --git a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake index cb16e161fc7a..51f2bb333abc 100644 --- a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake +++ b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake @@ -74,6 +74,9 @@ endif() # keyword. # function(CGAL_setup_CGAL_dependencies target) + if(CGAL_DISABLE_GMPXX) + target_compile_definitions(${target} INTERFACE CGAL_DISABLE_GMPXX=1) + endif() if(CGAL_DISABLE_GMP) target_compile_definitions(${target} INTERFACE CGAL_DISABLE_GMP=1) else() diff --git a/Installation/cmake/modules/CGAL_SetupGMP.cmake b/Installation/cmake/modules/CGAL_SetupGMP.cmake index 4a1df74eabc4..7777bb74cbf2 100644 --- a/Installation/cmake/modules/CGAL_SetupGMP.cmake +++ b/Installation/cmake/modules/CGAL_SetupGMP.cmake @@ -68,7 +68,9 @@ function(use_CGAL_GMP_support target) if(WITH_GMPXX OR CGAL_WITH_GMPXX) target_include_directories(${target} SYSTEM INTERFACE ${GMPXX_INCLUDE_DIR}) target_link_libraries(${target} INTERFACE ${GMPXX_LIBRARIES}) - target_compile_definitions(${target} INTERFACE CGAL_USE_GMPXX=1) + if(NOT CGAL_DISABLE_GMPXX) + target_compile_definitions(${target} INTERFACE CGAL_USE_GMPXX=1) + endif() endif() target_link_libraries(${target} INTERFACE ${MPFR_LIBRARIES} ${GMP_LIBRARIES}) endfunction() From b0f7d84cdddbe0d5961c5f76ab0ea7881935fcbd Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 10 Aug 2021 16:57:05 +0200 Subject: [PATCH 002/127] turned on boost mp option --- Number_types/include/CGAL/internal/Exact_type_selector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/internal/Exact_type_selector.h b/Number_types/include/CGAL/internal/Exact_type_selector.h index 209adf40028b..94f783c2a987 100644 --- a/Number_types/include/CGAL/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/internal/Exact_type_selector.h @@ -64,7 +64,7 @@ struct Exact_field_selector # endif #elif defined(CGAL_USE_LEDA) { typedef leda_rational Type; }; -#elif 0 && defined(CGAL_USE_BOOST_MP) +#elif defined(CGAL_USE_BOOST_MP) // See the discussion in https://github.com/CGAL/cgal/pull/3614 // This is disabled for now because cpp_rational is even slower than Quotient. Quotient will be a good candidate after some polishing. { typedef BOOST_cpp_arithmetic_kernel::Rational Type; }; From 4f7b7a6e9337b43b3696ff7dadcceea56f396855 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 12 Aug 2021 11:31:30 +0200 Subject: [PATCH 003/127] make sure gmpxx is not linked when cgal_disable_gmpxx is on --- Installation/CMakeLists.txt | 18 ++++++++++++++++++ Installation/cmake/modules/CGAL_SetupGMP.cmake | 15 ++++++++++----- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/Installation/CMakeLists.txt b/Installation/CMakeLists.txt index 8b404e4c6aab..84cc57dc100c 100644 --- a/Installation/CMakeLists.txt +++ b/Installation/CMakeLists.txt @@ -551,6 +551,24 @@ else() file(REMOVE "${CGAL_BINARY_DIR}/include/gmp.h") endif() +if(CGAL_DISABLE_GMPXX) + message("Disable the GMPXX support") + list(REMOVE_ITEM CGAL_ESSENTIAL_3RD_PARTY_LIBRARIES GMPXX) + unset(GMPXX_FOUND) + unset(GMPXX_FOUND CACHE) + unset(CGAL_USE_GMPXX) + unset(CGAL_USE_GMPXX CACHE) + # Nasty trick to make sure is not used when CGAL_DISABLE_GMPXX is TRUE + file(WRITE "${CGAL_BINARY_DIR}/include/gmpxx.h" + "#error GMPXX is disabled by the CMake option CGAL_DISABLE_GMPXX") +else() + list(APPEND CGAL_ESSENTIAL_3RD_PARTY_LIBRARIES GMPXX) + + # When CMake is run several times, to avoid duplicates. + list(REMOVE_DUPLICATES CGAL_ESSENTIAL_3RD_PARTY_LIBRARIES) + + file(REMOVE "${CGAL_BINARY_DIR}/include/gmpxx.h") +endif() hide_variable(CGAL_ESSENTIAL_3RD_PARTY_LIBRARIES) #-------------------------------------------------------------------------------------------------- diff --git a/Installation/cmake/modules/CGAL_SetupGMP.cmake b/Installation/cmake/modules/CGAL_SetupGMP.cmake index 7777bb74cbf2..7895f7e01a67 100644 --- a/Installation/cmake/modules/CGAL_SetupGMP.cmake +++ b/Installation/cmake/modules/CGAL_SetupGMP.cmake @@ -23,7 +23,12 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CGAL_MODULES_DIR}) find_package(GMP REQUIRED) find_package(MPFR REQUIRED) -find_package(GMPXX QUIET) + +if(NOT CGAL_DISABLE_GMPXX) + find_package(GMPXX QUIET) +else() + message("GMPXX IS DISABLED!") +endif() if(NOT GMPXX_FOUND) option(CGAL_WITH_GMPXX "Use CGAL with GMPXX: use C++ classes of GNU MP instead of CGAL wrappers" OFF) @@ -65,10 +70,10 @@ function(use_CGAL_GMP_support target) $ $) endif() - if(WITH_GMPXX OR CGAL_WITH_GMPXX) - target_include_directories(${target} SYSTEM INTERFACE ${GMPXX_INCLUDE_DIR}) - target_link_libraries(${target} INTERFACE ${GMPXX_LIBRARIES}) - if(NOT CGAL_DISABLE_GMPXX) + if(NOT CGAL_DISABLE_GMPXX) + if(WITH_GMPXX OR CGAL_WITH_GMPXX) + target_include_directories(${target} SYSTEM INTERFACE ${GMPXX_INCLUDE_DIR}) + target_link_libraries(${target} INTERFACE ${GMPXX_LIBRARIES}) target_compile_definitions(${target} INTERFACE CGAL_USE_GMPXX=1) endif() endif() From 6e1f4a3187cf1378f8c08aef2077cbe544593fe8 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 13 Aug 2021 13:45:54 +0200 Subject: [PATCH 004/127] added support for cppint config --- Number_types/include/CGAL/internal/Exact_type_selector.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Number_types/include/CGAL/internal/Exact_type_selector.h b/Number_types/include/CGAL/internal/Exact_type_selector.h index 94f783c2a987..ad668818b11c 100644 --- a/Number_types/include/CGAL/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/internal/Exact_type_selector.h @@ -67,7 +67,11 @@ struct Exact_field_selector #elif defined(CGAL_USE_BOOST_MP) // See the discussion in https://github.com/CGAL/cgal/pull/3614 // This is disabled for now because cpp_rational is even slower than Quotient. Quotient will be a good candidate after some polishing. +#if defined(CGAL_USE_CPP_INT) +{ typedef Quotient Type; }; +#else { typedef BOOST_cpp_arithmetic_kernel::Rational Type; }; +# endif #else { typedef Quotient Type; }; #endif From a143b88b7246a15c9686080e0b402dcb29bc55d4 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 17 Aug 2021 13:47:11 +0200 Subject: [PATCH 005/127] cleanup --- .../Kernel_23/Exact_predicates_exact_constructions_kernel.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Kernel_23/test/Kernel_23/Exact_predicates_exact_constructions_kernel.cpp b/Kernel_23/test/Kernel_23/Exact_predicates_exact_constructions_kernel.cpp index b3ed4921e7a2..a7f91a857d82 100644 --- a/Kernel_23/test/Kernel_23/Exact_predicates_exact_constructions_kernel.cpp +++ b/Kernel_23/test/Kernel_23/Exact_predicates_exact_constructions_kernel.cpp @@ -21,5 +21,7 @@ int main(){ CGAL_USE_TYPE(EPEKR); #endif + std::cout << EPEK::Point_3(0,0,0) << std::endl; + return 0; } From 783c9bdcf084baad2f93325eddcc4a12b3528999 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 18 Aug 2021 14:14:33 +0200 Subject: [PATCH 006/127] added cpp_rational config --- Number_types/include/CGAL/internal/Exact_type_selector.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Number_types/include/CGAL/internal/Exact_type_selector.h b/Number_types/include/CGAL/internal/Exact_type_selector.h index ad668818b11c..e2907fc10e4d 100644 --- a/Number_types/include/CGAL/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/internal/Exact_type_selector.h @@ -69,6 +69,8 @@ struct Exact_field_selector // This is disabled for now because cpp_rational is even slower than Quotient. Quotient will be a good candidate after some polishing. #if defined(CGAL_USE_CPP_INT) { typedef Quotient Type; }; +#elif defined(CGAL_USE_CPP_RATIONAL) +{ typedef Quotient Type; }; #else { typedef BOOST_cpp_arithmetic_kernel::Rational Type; }; # endif From 6264543c2201ac8ab9fb6eab5ab0c9af881df743 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 18 Aug 2021 18:49:58 +0200 Subject: [PATCH 007/127] updated benches --- Number_types/include/CGAL/Quotient.h | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 9e5ac07cb595..9a28fe35a587 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -44,7 +44,19 @@ namespace CGAL { // This function is not documented as a number type requirement for now. template < typename NT > inline void -simplify_quotient(NT &, NT &) {} +simplify_quotient(NT & /*a*/, NT & /*b*/) { + + // const auto r = gcd(a, b); + // std::cout << "r: " << r << std::endl; + // std::cout << "a: " << a << std::endl; + // std::cout << "b: " << b << std::endl; + // a = a / r; + // std::cout << "new a: " << a << std::endl; + // b = b / r; + // std::cout << "new b: " << b << std::endl; + // std::cout << std::endl; + +} // This one should be replaced by some functor or tag. // Meanwhile, the class is specialized for Gmpz, mpz_class, leda_integer. @@ -687,6 +699,19 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { public: std::pair operator()( const Type& x ) const { + + // auto x = xx; + // auto& a = x.num; auto& b = x.den; + // const auto r = gcd(a, b); + // std::cout << "r: " << r << std::endl; + // std::cout << "a: " << a << std::endl; + // std::cout << "b: " << b << std::endl; + // a = a / r; + // std::cout << "new a: " << a << std::endl; + // b = b / r; + // std::cout << "new b: " << b << std::endl; + // std::cout << std::endl; + Interval_nt<> quot = Interval_nt<>(CGAL_NTS to_interval(x.numerator())) / Interval_nt<>(CGAL_NTS to_interval(x.denominator())); From af8c9794da3bdc76689cff8f4523395274576d01 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 20 Aug 2021 17:22:56 +0200 Subject: [PATCH 008/127] different kernel by default --- Number_types/include/CGAL/MP_Float.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Number_types/include/CGAL/MP_Float.h b/Number_types/include/CGAL/MP_Float.h index 68cfdecde448..620e756a7667 100644 --- a/Number_types/include/CGAL/MP_Float.h +++ b/Number_types/include/CGAL/MP_Float.h @@ -777,6 +777,9 @@ inline void simplify_quotient(MP_Float & numerator, MP_Float & denominator) { + // return; + // std::cout << "a: " << numerator << std::endl; + // std::cout << "b: " << denominator << std::endl; // Currently only simplifies the two exponents. #if 0 // This better version causes problems as the I/O is changed for @@ -793,12 +796,16 @@ simplify_quotient(MP_Float & numerator, MP_Float & denominator) numerator.exp -= denominator.exp; denominator.exp = 0; const MP_Float g = gcd(numerator, denominator); + // std::cout << "r: " << g << std::endl; numerator = integral_division(numerator, g); denominator = integral_division(denominator, g); } numerator.exp -= denominator.exp; denominator.exp = 0; #endif + // std::cout << "new a: " << numerator << std::endl; + // std::cout << "new b: " << denominator << std::endl; + // std::cout << std::endl; } inline void simplify_root_of_2(MP_Float &/*a*/, MP_Float &/*b*/, MP_Float&/*c*/) { From 77742f6a9842734f84dbf4d9c243c18e178d0d16 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 23 Aug 2021 17:36:26 +0200 Subject: [PATCH 009/127] some fixes to cpp_int --- Number_types/include/CGAL/Quotient.h | 79 ++++++++++++++++++++++------ Number_types/include/CGAL/boost_mp.h | 19 ++++++- 2 files changed, 80 insertions(+), 18 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 9a28fe35a587..a371aa22fee9 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -33,6 +33,8 @@ #include #include +#include +#include namespace CGAL { @@ -44,15 +46,15 @@ namespace CGAL { // This function is not documented as a number type requirement for now. template < typename NT > inline void -simplify_quotient(NT & /*a*/, NT & /*b*/) { +simplify_quotient(NT & a, NT & b) { - // const auto r = gcd(a, b); + const NT r = boost::multiprecision::gcd(a, b); // std::cout << "r: " << r << std::endl; // std::cout << "a: " << a << std::endl; // std::cout << "b: " << b << std::endl; - // a = a / r; + a = a / r; // std::cout << "new a: " << a << std::endl; - // b = b / r; + b = b / r; // std::cout << "new b: " << b << std::endl; // std::cout << std::endl; @@ -700,21 +702,66 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > public: std::pair operator()( const Type& x ) const { - // auto x = xx; - // auto& a = x.num; auto& b = x.den; - // const auto r = gcd(a, b); + // Type x = xx; + // const decltype(x.num) r = gcd(x.num, x.den); // std::cout << "r: " << r << std::endl; - // std::cout << "a: " << a << std::endl; - // std::cout << "b: " << b << std::endl; - // a = a / r; - // std::cout << "new a: " << a << std::endl; - // b = b / r; - // std::cout << "new b: " << b << std::endl; + // std::cout << "a: " << x.num << std::endl; + // std::cout << "b: " << x.den << std::endl; + // x.num = x.num / r; + // std::cout << "new a: " << x.num << std::endl; + // x.den = x.den / r; + // std::cout << "new b: " << x.den << std::endl; // std::cout << std::endl; - Interval_nt<> quot = - Interval_nt<>(CGAL_NTS to_interval(x.numerator())) / - Interval_nt<>(CGAL_NTS to_interval(x.denominator())); + // std::cout << "n: " << x.numerator() << std::endl; + // std::cout << "d: " << x.denominator() << std::endl; + + Interval_nt<> quot; + const double inf = std::numeric_limits::infinity(); + const double xn = x.num.template convert_to(); + const double xd = x.den.template convert_to(); + if (xn == inf || xd == inf) { + + // decltype(x.num) q, r; + // boost::multiprecision::divide_qr(x.num, x.den, q, r); + + // std::cout << "type: " << boost::typeindex::type_id() << std::endl; + + // std::cout << "x num: " << x.num << std::endl; + // std::cout << "x den: " << x.den << std::endl; + + // std::cout << "q: " << q << std::endl; + // std::cout << "r: " << r << std::endl; + + CGAL_assertion(CGAL::abs(x.num) < CGAL::abs(x.den)); + if (x.num > 0 && x.den > 0) + return std::make_pair(0.0, 1.0); + else if (x.num < 0 && x.den < 0) + return std::make_pair(0.0, 1.0); + else + return std::make_pair(-1.0, 0.0); + + // quot = + // Interval_nt<>(CGAL_NTS to_interval(q)) + + // Interval_nt<>(CGAL_NTS to_interval(Type(r, x.den))); + + // quot = + // Interval_nt<>(CGAL_NTS to_interval(q)) + + // Interval_nt<>(CGAL_NTS to_interval(r)) / + // Interval_nt<>(CGAL_NTS to_interval(x.den)); + + // std::cout << "new inf1: " << quot.inf() << std::endl; + // std::cout << "new sup1: " << quot.sup() << std::endl; + + } else { + + quot = + Interval_nt<>(CGAL_NTS to_interval(x.num)) / + Interval_nt<>(CGAL_NTS to_interval(x.den)); + + // std::cout << "new inf2: " << quot.inf() << std::endl; + // std::cout << "new sup2: " << quot.sup() << std::endl; + } return std::make_pair(quot.inf(), quot.sup()); } }; diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 3548fdc249a5..50419f636669 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -199,14 +199,29 @@ struct RET_boost_mp_base // adding IA::smallest() doesn't work because inf-e=inf, even rounded down. double i = x.template convert_to(); double s = i; - double inf = std::numeric_limits::infinity(); - int cmp = x.compare(i); + + // std::cout << "x: " << x << std::endl; + // std::cout << "i: " << i << std::endl; + + const double inf = std::numeric_limits::infinity(); + CGAL_assertion(i != inf && s != inf); + const int cmp = x.compare(i); if (cmp > 0) { s = nextafter(s, +inf); + if (x.compare(i) >= 0) { + // std::cout << "s after1: " << i << std::endl; + s = nextafter(s, +inf); + // std::cout << "s after2: " << i << std::endl; + } CGAL_assertion(x.compare(s) < 0); } else if (cmp < 0) { i = nextafter(i, -inf); + if (x.compare(i) <= 0) { + // std::cout << "i after1: " << i << std::endl; + i = nextafter(i, -inf); + // std::cout << "i after2: " << i << std::endl; + } CGAL_assertion(x.compare(i) > 0); } return std::pair (i, s); From fcf1ff8d104d6a2bdd8f08092ea903ea1cd01547 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 24 Aug 2021 12:20:24 +0200 Subject: [PATCH 010/127] new fix --- Number_types/include/CGAL/Quotient.h | 54 +++++++++++++------ Number_types/include/CGAL/boost_mp.h | 23 ++++---- .../CGAL/internal/Exact_type_selector.h | 2 - 3 files changed, 52 insertions(+), 27 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index a371aa22fee9..e15887020c08 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -717,10 +717,10 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // std::cout << "d: " << x.denominator() << std::endl; Interval_nt<> quot; - const double inf = std::numeric_limits::infinity(); - const double xn = x.num.template convert_to(); - const double xd = x.den.template convert_to(); - if (xn == inf || xd == inf) { + // const double inf = std::numeric_limits::infinity(); + // const double xn = x.num.template convert_to(); + // const double xd = x.den.template convert_to(); + // if (xn == inf || xd == inf) { // decltype(x.num) q, r; // boost::multiprecision::divide_qr(x.num, x.den, q, r); @@ -733,13 +733,14 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // std::cout << "q: " << q << std::endl; // std::cout << "r: " << r << std::endl; - CGAL_assertion(CGAL::abs(x.num) < CGAL::abs(x.den)); - if (x.num > 0 && x.den > 0) - return std::make_pair(0.0, 1.0); - else if (x.num < 0 && x.den < 0) - return std::make_pair(0.0, 1.0); - else - return std::make_pair(-1.0, 0.0); + // CGAL_assertion(CGAL::abs(x.num) < CGAL::abs(x.den)); + // if (x.num > 0 && x.den > 0) { + // return std::make_pair( 0.0, 1.0); + // } else if (x.num < 0 && x.den < 0) { + // return std::make_pair( 0.0, 1.0); + // } else { + // return std::make_pair(-1.0, 0.0); + // } // quot = // Interval_nt<>(CGAL_NTS to_interval(q)) + @@ -753,15 +754,38 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // std::cout << "new inf1: " << quot.inf() << std::endl; // std::cout << "new sup1: " << quot.sup() << std::endl; + // } else { + + boost::multiprecision::cpp_rational rat; + if (x.den < 0) { + rat = boost::multiprecision::cpp_rational(-x.num, -x.den); } else { + rat = boost::multiprecision::cpp_rational(x.num, x.den); + } + + double i = static_cast(rat); + double s = i; + + const double inf = std::numeric_limits::infinity(); + CGAL_assertion(i != inf && s != inf); + const int cmp = rat.compare(i); + if (cmp > 0) { + s = nextafter(s, +inf); + CGAL_assertion(rat.compare(s) < 0); + } + else if (cmp < 0) { + i = nextafter(i, -inf); + CGAL_assertion(rat.compare(i) > 0); + } + return std::make_pair(i, s); - quot = - Interval_nt<>(CGAL_NTS to_interval(x.num)) / - Interval_nt<>(CGAL_NTS to_interval(x.den)); + // quot = + // Interval_nt<>(CGAL_NTS to_interval(x.num)) / + // Interval_nt<>(CGAL_NTS to_interval(x.den)); // std::cout << "new inf2: " << quot.inf() << std::endl; // std::cout << "new sup2: " << quot.sup() << std::endl; - } + // } return std::make_pair(quot.inf(), quot.sup()); } }; diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 50419f636669..da3899c1e18e 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -194,6 +194,7 @@ struct RET_boost_mp_base : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { std::pair operator()(const Type& x) const { + // See if https://github.com/boostorg/multiprecision/issues/108 suggests anything better // assume the conversion is within 1 ulp // adding IA::smallest() doesn't work because inf-e=inf, even rounded down. @@ -204,24 +205,26 @@ struct RET_boost_mp_base // std::cout << "i: " << i << std::endl; const double inf = std::numeric_limits::infinity(); + // std::cout << i << std::endl; CGAL_assertion(i != inf && s != inf); const int cmp = x.compare(i); + // std::cout << "cmp: " << cmp << std::endl; if (cmp > 0) { s = nextafter(s, +inf); - if (x.compare(i) >= 0) { - // std::cout << "s after1: " << i << std::endl; - s = nextafter(s, +inf); - // std::cout << "s after2: " << i << std::endl; - } + // if (x.compare(s) >= 0) { + // // std::cout << "s after1: " << i << std::endl; + // s = nextafter(s, +inf); + // // std::cout << "s after2: " << i << std::endl; + // } CGAL_assertion(x.compare(s) < 0); } else if (cmp < 0) { i = nextafter(i, -inf); - if (x.compare(i) <= 0) { - // std::cout << "i after1: " << i << std::endl; - i = nextafter(i, -inf); - // std::cout << "i after2: " << i << std::endl; - } + // if (x.compare(i) <= 0) { + // // std::cout << "i after1: " << i << std::endl; + // i = nextafter(i, -inf); + // // std::cout << "i after2: " << i << std::endl; + // } CGAL_assertion(x.compare(i) > 0); } return std::pair (i, s); diff --git a/Number_types/include/CGAL/internal/Exact_type_selector.h b/Number_types/include/CGAL/internal/Exact_type_selector.h index e2907fc10e4d..ad668818b11c 100644 --- a/Number_types/include/CGAL/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/internal/Exact_type_selector.h @@ -69,8 +69,6 @@ struct Exact_field_selector // This is disabled for now because cpp_rational is even slower than Quotient. Quotient will be a good candidate after some polishing. #if defined(CGAL_USE_CPP_INT) { typedef Quotient Type; }; -#elif defined(CGAL_USE_CPP_RATIONAL) -{ typedef Quotient Type; }; #else { typedef BOOST_cpp_arithmetic_kernel::Rational Type; }; # endif From 36c554b6fe9dab37ef2af029e589ea199f1de503 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 24 Aug 2021 13:12:05 +0200 Subject: [PATCH 011/127] various cpp_int fixes + tighter bounds --- ..._predicates_exact_constructions_kernel.cpp | 2 - Number_types/include/CGAL/Quotient.h | 108 +++++++++--------- Number_types/include/CGAL/boost_mp.h | 61 +++++----- 3 files changed, 88 insertions(+), 83 deletions(-) diff --git a/Kernel_23/test/Kernel_23/Exact_predicates_exact_constructions_kernel.cpp b/Kernel_23/test/Kernel_23/Exact_predicates_exact_constructions_kernel.cpp index a7f91a857d82..b3ed4921e7a2 100644 --- a/Kernel_23/test/Kernel_23/Exact_predicates_exact_constructions_kernel.cpp +++ b/Kernel_23/test/Kernel_23/Exact_predicates_exact_constructions_kernel.cpp @@ -21,7 +21,5 @@ int main(){ CGAL_USE_TYPE(EPEKR); #endif - std::cout << EPEK::Point_3(0,0,0) << std::endl; - return 0; } diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index e15887020c08..f643fb4b63b9 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -48,6 +48,10 @@ template < typename NT > inline void simplify_quotient(NT & a, NT & b) { +// TODO: +// - move it to the boost_mp.h +// - can we use gcd only sometimes to save time? +#if true const NT r = boost::multiprecision::gcd(a, b); // std::cout << "r: " << r << std::endl; // std::cout << "a: " << a << std::endl; @@ -57,6 +61,7 @@ simplify_quotient(NT & a, NT & b) { b = b / r; // std::cout << "new b: " << b << std::endl; // std::cout << std::endl; +#endif } @@ -702,25 +707,14 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > public: std::pair operator()( const Type& x ) const { - // Type x = xx; - // const decltype(x.num) r = gcd(x.num, x.den); - // std::cout << "r: " << r << std::endl; - // std::cout << "a: " << x.num << std::endl; - // std::cout << "b: " << x.den << std::endl; - // x.num = x.num / r; - // std::cout << "new a: " << x.num << std::endl; - // x.den = x.den / r; - // std::cout << "new b: " << x.den << std::endl; - // std::cout << std::endl; - - // std::cout << "n: " << x.numerator() << std::endl; + #if false // rough bounds + // std::cout << "n: " << x.numerator() << std::endl; // std::cout << "d: " << x.denominator() << std::endl; - Interval_nt<> quot; - // const double inf = std::numeric_limits::infinity(); - // const double xn = x.num.template convert_to(); - // const double xd = x.den.template convert_to(); - // if (xn == inf || xd == inf) { + const double inf = std::numeric_limits::infinity(); + const double xn = x.num.template convert_to(); + const double xd = x.den.template convert_to(); + if (xn == inf || xd == inf) { // decltype(x.num) q, r; // boost::multiprecision::divide_qr(x.num, x.den, q, r); @@ -733,20 +727,22 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // std::cout << "q: " << q << std::endl; // std::cout << "r: " << r << std::endl; - // CGAL_assertion(CGAL::abs(x.num) < CGAL::abs(x.den)); - // if (x.num > 0 && x.den > 0) { - // return std::make_pair( 0.0, 1.0); - // } else if (x.num < 0 && x.den < 0) { - // return std::make_pair( 0.0, 1.0); - // } else { - // return std::make_pair(-1.0, 0.0); - // } + // We do not have here a tight bound! + // TODO: Use a binary search or limbs to find a tighter bound! + CGAL_assertion(CGAL::abs(x.num) < CGAL::abs(x.den)); + if (x.num > 0 && x.den > 0) { + return std::make_pair( 0.0, 1.0); + } else if (x.num < 0 && x.den < 0) { + return std::make_pair( 0.0, 1.0); + } else { + return std::make_pair(-1.0, 0.0); + } - // quot = + // Interval_nt<> quot = // Interval_nt<>(CGAL_NTS to_interval(q)) + // Interval_nt<>(CGAL_NTS to_interval(Type(r, x.den))); - // quot = + // Interval_nt<> quot = // Interval_nt<>(CGAL_NTS to_interval(q)) + // Interval_nt<>(CGAL_NTS to_interval(r)) / // Interval_nt<>(CGAL_NTS to_interval(x.den)); @@ -754,39 +750,47 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // std::cout << "new inf1: " << quot.inf() << std::endl; // std::cout << "new sup1: " << quot.sup() << std::endl; - // } else { + // return std::make_pair(quot.inf(), quot.sup()); + + } else { + + Interval_nt<> quot = + Interval_nt<>(CGAL_NTS to_interval(x.num)) / + Interval_nt<>(CGAL_NTS to_interval(x.den)); + + // std::cout << "new inf2: " << quot.inf() << std::endl; + // std::cout << "new sup2: " << quot.sup() << std::endl; + + return std::make_pair(quot.inf(), quot.sup()); + } - boost::multiprecision::cpp_rational rat; + #else // tight bounds + + boost::multiprecision::cpp_rational rat; // TODO: Is it fast enough? + CGAL_assertion(x.den != 0); if (x.den < 0) { rat = boost::multiprecision::cpp_rational(-x.num, -x.den); } else { - rat = boost::multiprecision::cpp_rational(x.num, x.den); + rat = boost::multiprecision::cpp_rational( x.num, x.den); } - double i = static_cast(rat); - double s = i; + double i = static_cast(rat); + double s = i; - const double inf = std::numeric_limits::infinity(); - CGAL_assertion(i != inf && s != inf); - const int cmp = rat.compare(i); - if (cmp > 0) { - s = nextafter(s, +inf); - CGAL_assertion(rat.compare(s) < 0); - } - else if (cmp < 0) { - i = nextafter(i, -inf); - CGAL_assertion(rat.compare(i) > 0); - } - return std::make_pair(i, s); - - // quot = - // Interval_nt<>(CGAL_NTS to_interval(x.num)) / - // Interval_nt<>(CGAL_NTS to_interval(x.den)); + const double inf = std::numeric_limits::infinity(); + CGAL_assertion(i != inf && s != inf); + const int cmp = rat.compare(i); + if (cmp > 0) { + s = nextafter(s, +inf); + CGAL_assertion(rat.compare(s) < 0); + } + else if (cmp < 0) { + i = nextafter(i, -inf); + CGAL_assertion(rat.compare(i) > 0); + } + return std::make_pair(i, s); - // std::cout << "new inf2: " << quot.inf() << std::endl; - // std::cout << "new sup2: " << quot.sup() << std::endl; - // } - return std::make_pair(quot.inf(), quot.sup()); + #endif } }; diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index da3899c1e18e..2c093aaf33e1 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -195,39 +195,42 @@ struct RET_boost_mp_base std::pair operator()(const Type& x) const { - // See if https://github.com/boostorg/multiprecision/issues/108 suggests anything better - // assume the conversion is within 1 ulp - // adding IA::smallest() doesn't work because inf-e=inf, even rounded down. - double i = x.template convert_to(); - double s = i; - - // std::cout << "x: " << x << std::endl; - // std::cout << "i: " << i << std::endl; - - const double inf = std::numeric_limits::infinity(); - // std::cout << i << std::endl; - CGAL_assertion(i != inf && s != inf); - const int cmp = x.compare(i); - // std::cout << "cmp: " << cmp << std::endl; - if (cmp > 0) { + // See if https://github.com/boostorg/multiprecision/issues/108 suggests anything better + // assume the conversion is within 1 ulp + // adding IA::smallest() doesn't work because inf-e=inf, even rounded down. + double i = x.template convert_to(); + double s = i; + + // std::cout << "x: " << x << std::endl; + // std::cout << "i: " << i << std::endl; + // std::cout << "s: " << s << std::endl; + + const double inf = std::numeric_limits::infinity(); + CGAL_assertion(i != inf && s != inf); + const int cmp = x.compare(i); + if (cmp > 0) { + s = nextafter(s, +inf); + #if false + if (x.compare(s) >= 0) { // TODO: We may need to run it in a while loop! + // std::cout << "s after1: " << i << std::endl; s = nextafter(s, +inf); - // if (x.compare(s) >= 0) { - // // std::cout << "s after1: " << i << std::endl; - // s = nextafter(s, +inf); - // // std::cout << "s after2: " << i << std::endl; - // } - CGAL_assertion(x.compare(s) < 0); + // std::cout << "s after2: " << i << std::endl; } - else if (cmp < 0) { + #endif + CGAL_assertion(x.compare(s) < 0); + } + else if (cmp < 0) { + i = nextafter(i, -inf); + #if false + if (x.compare(i) <= 0) { // TODO: We may need to run it in a while loop! + // std::cout << "i after1: " << i << std::endl; i = nextafter(i, -inf); - // if (x.compare(i) <= 0) { - // // std::cout << "i after1: " << i << std::endl; - // i = nextafter(i, -inf); - // // std::cout << "i after2: " << i << std::endl; - // } - CGAL_assertion(x.compare(i) > 0); + // std::cout << "i after2: " << i << std::endl; } - return std::pair (i, s); + #endif + CGAL_assertion(x.compare(i) > 0); + } + return std::pair (i, s); } }; }; From 0d1347343bb38914208204c1c89c635a0e0aeefd Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 24 Aug 2021 15:22:42 +0200 Subject: [PATCH 012/127] bug with nextafter --- Number_types/include/CGAL/Quotient.h | 5 ++++- Number_types/include/CGAL/boost_mp.h | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index f643fb4b63b9..cf607ed77631 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -707,7 +707,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > public: std::pair operator()( const Type& x ) const { - #if false // rough bounds + #if true // rough bounds // std::cout << "n: " << x.numerator() << std::endl; // std::cout << "d: " << x.denominator() << std::endl; @@ -729,6 +729,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // We do not have here a tight bound! // TODO: Use a binary search or limbs to find a tighter bound! + // TODO: Try to use here the conversion to cpp_rational from below. CGAL_assertion(CGAL::abs(x.num) < CGAL::abs(x.den)); if (x.num > 0 && x.den > 0) { return std::make_pair( 0.0, 1.0); @@ -766,6 +767,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > #else // tight bounds + // TODO: Should we use this one instead: + // https://github.com/boostorg/multiprecision/blob/3094249d7c30026b39fef77344e187bf93f24c6c/include/boost/multiprecision/detail/generic_interconvert.hpp#L305 ? boost::multiprecision::cpp_rational rat; // TODO: Is it fast enough? CGAL_assertion(x.den != 0); if (x.den < 0) { diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 2c093aaf33e1..e7d10ffd42b1 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -210,19 +210,27 @@ struct RET_boost_mp_base const int cmp = x.compare(i); if (cmp > 0) { s = nextafter(s, +inf); - #if false + #if true if (x.compare(s) >= 0) { // TODO: We may need to run it in a while loop! - // std::cout << "s after1: " << i << std::endl; + std::cout << "i is correct: " << std::endl; + std::cout << "x : " << x << std::endl; + std::cout << "s before : " << i << std::endl; + std::cout << "s after : " << s << std::endl; + // std::cout << "s after1: " << s << std::endl; s = nextafter(s, +inf); - // std::cout << "s after2: " << i << std::endl; + // std::cout << "s after2: " << s << std::endl; } #endif CGAL_assertion(x.compare(s) < 0); } else if (cmp < 0) { i = nextafter(i, -inf); - #if false + #if true if (x.compare(i) <= 0) { // TODO: We may need to run it in a while loop! + std::cout << "s is correct: " << std::endl; + std::cout << "x : " << x << std::endl; + std::cout << "i before : " << s << std::endl; + std::cout << "i after : " << i << std::endl; // std::cout << "i after1: " << i << std::endl; i = nextafter(i, -inf); // std::cout << "i after2: " << i << std::endl; From 99d5168d6f02eb3b41b3cd6db35d7688e9cf4683 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 24 Aug 2021 19:06:06 +0200 Subject: [PATCH 013/127] fixed fpu rounding bug --- Number_types/include/CGAL/Quotient.h | 42 ++++++++++++++++++++++------ Number_types/include/CGAL/boost_mp.h | 22 ++++++++++----- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index cf607ed77631..64705c793a6c 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -730,14 +730,40 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // We do not have here a tight bound! // TODO: Use a binary search or limbs to find a tighter bound! // TODO: Try to use here the conversion to cpp_rational from below. - CGAL_assertion(CGAL::abs(x.num) < CGAL::abs(x.den)); - if (x.num > 0 && x.den > 0) { - return std::make_pair( 0.0, 1.0); - } else if (x.num < 0 && x.den < 0) { - return std::make_pair( 0.0, 1.0); - } else { - return std::make_pair(-1.0, 0.0); - } + #if false + CGAL_assertion(CGAL::abs(x.num) < CGAL::abs(x.den)); + if (x.num > 0 && x.den > 0) { + return std::make_pair( 0.0, 1.0); + } else if (x.num < 0 && x.den < 0) { + return std::make_pair( 0.0, 1.0); + } else { + return std::make_pair(-1.0, 0.0); + } + #else + boost::multiprecision::cpp_rational rat; // TODO: Is it fast enough? + CGAL_assertion(x.den != 0); + if (x.den < 0) { + rat = boost::multiprecision::cpp_rational(-x.num, -x.den); + } else { + rat = boost::multiprecision::cpp_rational( x.num, x.den); + } + + double i = static_cast(rat); + double s = i; + + const double inf = std::numeric_limits::infinity(); + CGAL_assertion(i != inf && s != inf); + const int cmp = rat.compare(i); + if (cmp > 0) { + s = nextafter(s, +inf); + CGAL_assertion(rat.compare(s) < 0); + } + else if (cmp < 0) { + i = nextafter(i, -inf); + CGAL_assertion(rat.compare(i) > 0); + } + return std::make_pair(i, s); + #endif // Interval_nt<> quot = // Interval_nt<>(CGAL_NTS to_interval(q)) + diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index e7d10ffd42b1..b9a95c28e3d2 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -195,10 +195,18 @@ struct RET_boost_mp_base std::pair operator()(const Type& x) const { + // std::cout << "- before ... " << std::endl; + // test_minimal_nextafter(false); + // std::cout << "- after ... " << std::endl; + // See if https://github.com/boostorg/multiprecision/issues/108 suggests anything better // assume the conversion is within 1 ulp // adding IA::smallest() doesn't work because inf-e=inf, even rounded down. - double i = x.template convert_to(); + double i; + { + Protect_FPU_rounding P(CGAL_FE_TONEAREST); + i = x.template convert_to(); + } double s = i; // std::cout << "x: " << x << std::endl; @@ -210,30 +218,30 @@ struct RET_boost_mp_base const int cmp = x.compare(i); if (cmp > 0) { s = nextafter(s, +inf); - #if true + #if false if (x.compare(s) >= 0) { // TODO: We may need to run it in a while loop! std::cout << "i is correct: " << std::endl; + test_minimal_nextafter(true); std::cout << "x : " << x << std::endl; std::cout << "s before : " << i << std::endl; std::cout << "s after : " << s << std::endl; - // std::cout << "s after1: " << s << std::endl; + CGAL_assertion(x.compare(s) < 0); s = nextafter(s, +inf); - // std::cout << "s after2: " << s << std::endl; } #endif CGAL_assertion(x.compare(s) < 0); } else if (cmp < 0) { i = nextafter(i, -inf); - #if true + #if false if (x.compare(i) <= 0) { // TODO: We may need to run it in a while loop! std::cout << "s is correct: " << std::endl; + test_minimal_nextafter(true); std::cout << "x : " << x << std::endl; std::cout << "i before : " << s << std::endl; std::cout << "i after : " << i << std::endl; - // std::cout << "i after1: " << i << std::endl; + CGAL_assertion(x.compare(i) > 0); i = nextafter(i, -inf); - // std::cout << "i after2: " << i << std::endl; } #endif CGAL_assertion(x.compare(i) > 0); From b9a7161d7cec08f5416fe186db9524958249856f Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 25 Aug 2021 12:46:48 +0200 Subject: [PATCH 014/127] make modifs only for cpp_int and keep master --- Number_types/include/CGAL/Quotient.h | 53 ++++++++++------------------ Number_types/include/CGAL/boost_mp.h | 51 +++++++++++--------------- 2 files changed, 39 insertions(+), 65 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 64705c793a6c..7fa94bf655b3 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -51,7 +51,8 @@ simplify_quotient(NT & a, NT & b) { // TODO: // - move it to the boost_mp.h // - can we use gcd only sometimes to save time? -#if true +#if defined(CGAL_USE_CPP_INT) + const NT r = boost::multiprecision::gcd(a, b); // std::cout << "r: " << r << std::endl; // std::cout << "a: " << a << std::endl; @@ -61,6 +62,7 @@ simplify_quotient(NT & a, NT & b) { b = b / r; // std::cout << "new b: " << b << std::endl; // std::cout << std::endl; + #endif } @@ -707,7 +709,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > public: std::pair operator()( const Type& x ) const { - #if true // rough bounds + #if defined(CGAL_USE_CPP_INT) + // std::cout << "n: " << x.numerator() << std::endl; // std::cout << "d: " << x.denominator() << std::endl; @@ -727,10 +730,10 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // std::cout << "q: " << q << std::endl; // std::cout << "r: " << r << std::endl; - // We do not have here a tight bound! - // TODO: Use a binary search or limbs to find a tighter bound! - // TODO: Try to use here the conversion to cpp_rational from below. - #if false + #if false // rough bounds + + // We do not have here a tight bound! + // TODO: Use a binary search or limbs to find a tighter bound! CGAL_assertion(CGAL::abs(x.num) < CGAL::abs(x.den)); if (x.num > 0 && x.den > 0) { return std::make_pair( 0.0, 1.0); @@ -739,7 +742,9 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } else { return std::make_pair(-1.0, 0.0); } - #else + + #else // tight bounds using cpp_rational + boost::multiprecision::cpp_rational rat; // TODO: Is it fast enough? CGAL_assertion(x.den != 0); if (x.den < 0) { @@ -763,6 +768,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(rat.compare(i) > 0); } return std::make_pair(i, s); + #endif // Interval_nt<> quot = @@ -781,7 +787,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } else { - Interval_nt<> quot = + const Interval_nt<> quot = Interval_nt<>(CGAL_NTS to_interval(x.num)) / Interval_nt<>(CGAL_NTS to_interval(x.den)); @@ -791,33 +797,12 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > return std::make_pair(quot.inf(), quot.sup()); } - #else // tight bounds + #else // master version - // TODO: Should we use this one instead: - // https://github.com/boostorg/multiprecision/blob/3094249d7c30026b39fef77344e187bf93f24c6c/include/boost/multiprecision/detail/generic_interconvert.hpp#L305 ? - boost::multiprecision::cpp_rational rat; // TODO: Is it fast enough? - CGAL_assertion(x.den != 0); - if (x.den < 0) { - rat = boost::multiprecision::cpp_rational(-x.num, -x.den); - } else { - rat = boost::multiprecision::cpp_rational( x.num, x.den); - } - - double i = static_cast(rat); - double s = i; - - const double inf = std::numeric_limits::infinity(); - CGAL_assertion(i != inf && s != inf); - const int cmp = rat.compare(i); - if (cmp > 0) { - s = nextafter(s, +inf); - CGAL_assertion(rat.compare(s) < 0); - } - else if (cmp < 0) { - i = nextafter(i, -inf); - CGAL_assertion(rat.compare(i) > 0); - } - return std::make_pair(i, s); + const Interval_nt<> quot = + Interval_nt<>(CGAL_NTS to_interval(x.numerator())) / + Interval_nt<>(CGAL_NTS to_interval(x.denominator())); + return std::make_pair(quot.inf(), quot.sup()); #endif } diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index b9a95c28e3d2..b37b64a72f14 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -195,19 +195,30 @@ struct RET_boost_mp_base std::pair operator()(const Type& x) const { - // std::cout << "- before ... " << std::endl; - // test_minimal_nextafter(false); - // std::cout << "- after ... " << std::endl; + // std::cout << "- before test minimal nextafter ... " << std::endl; + // test_minimal_nextafter(); + // std::cout << "- after test minimal nextafter ... " << std::endl; // See if https://github.com/boostorg/multiprecision/issues/108 suggests anything better // assume the conversion is within 1 ulp // adding IA::smallest() doesn't work because inf-e=inf, even rounded down. - double i; - { - Protect_FPU_rounding P(CGAL_FE_TONEAREST); - i = x.template convert_to(); - } - double s = i; + + #if defined(CGAL_USE_CPP_INT) + + // We must use to_nearest with cpp_int. + double i; + { + Protect_FPU_rounding P(CGAL_FE_TONEAREST); + i = x.template convert_to(); + } + double s = i; + + #else // master version + + double i = x.template convert_to(); + double s = i; + + #endif // std::cout << "x: " << x << std::endl; // std::cout << "i: " << i << std::endl; @@ -218,32 +229,10 @@ struct RET_boost_mp_base const int cmp = x.compare(i); if (cmp > 0) { s = nextafter(s, +inf); - #if false - if (x.compare(s) >= 0) { // TODO: We may need to run it in a while loop! - std::cout << "i is correct: " << std::endl; - test_minimal_nextafter(true); - std::cout << "x : " << x << std::endl; - std::cout << "s before : " << i << std::endl; - std::cout << "s after : " << s << std::endl; - CGAL_assertion(x.compare(s) < 0); - s = nextafter(s, +inf); - } - #endif CGAL_assertion(x.compare(s) < 0); } else if (cmp < 0) { i = nextafter(i, -inf); - #if false - if (x.compare(i) <= 0) { // TODO: We may need to run it in a while loop! - std::cout << "s is correct: " << std::endl; - test_minimal_nextafter(true); - std::cout << "x : " << x << std::endl; - std::cout << "i before : " << s << std::endl; - std::cout << "i after : " << i << std::endl; - CGAL_assertion(x.compare(i) > 0); - i = nextafter(i, -inf); - } - #endif CGAL_assertion(x.compare(i) > 0); } return std::pair (i, s); From 871dccb394f68718e33b9e771dcd5e42c614d3dc Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 25 Aug 2021 13:37:44 +0200 Subject: [PATCH 015/127] added shape regularization bench --- Number_types/include/CGAL/Quotient.h | 5 +++-- Number_types/include/CGAL/boost_mp.h | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 7fa94bf655b3..f37bba87e257 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -51,7 +51,7 @@ simplify_quotient(NT & a, NT & b) { // TODO: // - move it to the boost_mp.h // - can we use gcd only sometimes to save time? -#if defined(CGAL_USE_CPP_INT) +#if defined(CGAL_USE_CPP_INT) && true const NT r = boost::multiprecision::gcd(a, b); // std::cout << "r: " << r << std::endl; @@ -709,7 +709,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > public: std::pair operator()( const Type& x ) const { - #if defined(CGAL_USE_CPP_INT) + #if defined(CGAL_USE_CPP_INT) && true // std::cout << "n: " << x.numerator() << std::endl; // std::cout << "d: " << x.denominator() << std::endl; @@ -734,6 +734,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // We do not have here a tight bound! // TODO: Use a binary search or limbs to find a tighter bound! + // For REG tests this assertion fails! CGAL_assertion(CGAL::abs(x.num) < CGAL::abs(x.den)); if (x.num > 0 && x.den > 0) { return std::make_pair( 0.0, 1.0); diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index b37b64a72f14..ff30b933c574 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -203,7 +203,7 @@ struct RET_boost_mp_base // assume the conversion is within 1 ulp // adding IA::smallest() doesn't work because inf-e=inf, even rounded down. - #if defined(CGAL_USE_CPP_INT) + #if defined(CGAL_USE_CPP_INT) && true // should always be true because it is a bug on CGAL/macOS // We must use to_nearest with cpp_int. double i; @@ -226,6 +226,9 @@ struct RET_boost_mp_base const double inf = std::numeric_limits::infinity(); CGAL_assertion(i != inf && s != inf); + + // Throws uncaught exception: Cannot convert a non-finite number to an integer. + // We can catch it earlier by using the CGAL_assertion() one line above. const int cmp = x.compare(i); if (cmp > 0) { s = nextafter(s, +inf); From 5d3c3a20c672de2252526c0840cf2199245d4097 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 25 Aug 2021 14:07:56 +0200 Subject: [PATCH 016/127] cleanup --- Number_types/include/CGAL/Quotient.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index f37bba87e257..e3ea2f500c5f 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -711,6 +711,12 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > #if defined(CGAL_USE_CPP_INT) && true + #if false // tight bounds optimized + + // make tight and fast bounds for x here + + #endif + // std::cout << "n: " << x.numerator() << std::endl; // std::cout << "d: " << x.denominator() << std::endl; From 746506ce9333b064cbe5b33dde5c8af5cca3dd34 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 25 Aug 2021 16:04:51 +0200 Subject: [PATCH 017/127] added test calling a generic_function --- Number_types/include/CGAL/Quotient.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index e3ea2f500c5f..b06769aedb7f 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -761,6 +761,10 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } double i = static_cast(rat); + // double i; + // decltype(x) xx = x; + // const std::integral_constant tag; + // boost::multiprecision::detail::generic_convert_rational_to_float_imp(i, xx.num, xx.den, tag); double s = i; const double inf = std::numeric_limits::infinity(); From 98661690fcf0cccb81181298925b5178cf0df074 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 25 Aug 2021 16:16:18 +0200 Subject: [PATCH 018/127] added spread --- Number_types/include/CGAL/Quotient.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index b06769aedb7f..32bae45eebe5 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -713,7 +713,9 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > #if false // tight bounds optimized - // make tight and fast bounds for x here + // Make tight and fast bounds for x here. + // 1. Gmpzf.h - line 156 and Gmpzf_type.h - line 412. + // 2. generic_interconvert.hpp - line 305. #endif From 9a1c07e6b59e8a2cad3cdf3d7e11363ff746407d Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 26 Aug 2021 11:57:13 +0200 Subject: [PATCH 019/127] getting started with tight interval --- Number_types/include/CGAL/Quotient.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 32bae45eebe5..196cd9e7f0dc 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -709,14 +709,25 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > public: std::pair operator()( const Type& x ) const { + // std::cout << "xx: " << x << std::endl; + // std::cout << "xn: " << x.num << std::endl; + // std::cout << "xd: " << x.den << std::endl; + #if defined(CGAL_USE_CPP_INT) && true - #if false // tight bounds optimized + #if true // tight bounds optimized // Make tight and fast bounds for x here. // 1. Gmpzf.h - line 156 and Gmpzf_type.h - line 412. // 2. generic_interconvert.hpp - line 305. + double i, s; + + + + CGAL_assertion_msg(false, "TODO: FINISH CONVERSION TO INTERVAL!"); + return std::make_pair(i, s); + #endif // std::cout << "n: " << x.numerator() << std::endl; @@ -780,6 +791,10 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > i = nextafter(i, -inf); CGAL_assertion(rat.compare(i) > 0); } + + // std::cout << "new inf1: " << i << std::endl; + // std::cout << "new sup1: " << s << std::endl; + return std::make_pair(i, s); #endif From 3fe4e044b863cedfd723ce1731bb120dcec75950 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 26 Aug 2021 13:28:31 +0200 Subject: [PATCH 020/127] added soft and hard tests for new tight to_interval() --- Number_types/include/CGAL/Quotient.h | 43 ++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 196cd9e7f0dc..53d4ff73a3d8 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -721,12 +721,49 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // 1. Gmpzf.h - line 156 and Gmpzf_type.h - line 412. // 2. generic_interconvert.hpp - line 305. - double i, s; + double i = 0.0, s = 0.0; + // Using 1 as reference: + // get surrounding interval of the form [l * 2 ^ k, u * 2^ k] + // first get mantissa in the form l*2^k, with 0.5 <= d < 1; + // truncation is guaranteed to go towards zero + // Exponent k = 0; + // double l = mpz_get_d_2exp (&k, man()); - CGAL_assertion_msg(false, "TODO: FINISH CONVERSION TO INTERVAL!"); - return std::make_pair(i, s); + // l = +/- 0.1*...* + // ------ + // 53 digits + // in order to round away from zero, it suffices to add/subtract 2^-53 + + // double u = l; + // if (l < 0) + // // u is already the upper bound, decrease l to get lower bound + // l -= std::ldexp(1.0, -53); + // else + // // l is already the lower bound, increase u to get upper bound + // u += std::ldexp(1.0, -53); + + // the interval is now [l * 2^(k + exp()), u * 2^(k + exp())] + // we may cast the exponents to int, since if that's going to + // create an overflow, we correctly get infinities + + // return std::pair, long> + // (std::pair(l, u), k + exp()); + + // // do here as MP_Float does + // std::pair, long> n = + // q.numerator().to_interval_exp(); + // std::pair, long> d = + // q.denominator().to_interval_exp(); + + // CGAL_assertion_msg(CGAL::abs(double(n.second) - double(d.second)) < (1<<30)*2.0, + // "Exponent overflow in Quotient to_interval"); + // return ldexp(Interval_nt<>(n.first) / Interval_nt<>(d.first), + // static_cast(n.second - d.second)).pair(); + + + return std::make_pair(i, s); #endif From ed3d8495b1e5d4bba4e15cb53bde4c8112508118 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 26 Aug 2021 13:43:52 +0200 Subject: [PATCH 021/127] starting work on gmpzf similar func --- Number_types/include/CGAL/Quotient.h | 98 ++++++++++++++++------------ 1 file changed, 56 insertions(+), 42 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 53d4ff73a3d8..f0b363f0e3d8 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -707,63 +707,77 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > class To_interval : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { public: - std::pair operator()( const Type& x ) const { - // std::cout << "xx: " << x << std::endl; - // std::cout << "xn: " << x.num << std::endl; - // std::cout << "xd: " << x.den << std::endl; + std::pair< std::pair, long > get_interval_exp(const NT& x) const { - #if defined(CGAL_USE_CPP_INT) && true + std::cout << std::endl; + std::cout << " --- debugging get_interval_exp() --- " << std::endl; + std::cout << "x: " << x << std::endl; - #if true // tight bounds optimized + // Get surrounding interval of the form [l*2^k, u*2^k] + // first get mantissa in the form l*2^k, with 0.5 <= d < 1; + // truncation is guaranteed to go towards zero. - // Make tight and fast bounds for x here. - // 1. Gmpzf.h - line 156 and Gmpzf_type.h - line 412. - // 2. generic_interconvert.hpp - line 305. - - double i = 0.0, s = 0.0; + // Exponent k = 0; + // double l = mpz_get_d_2exp (&k, man()); - // Using 1 as reference: - // get surrounding interval of the form [l * 2 ^ k, u * 2^ k] - // first get mantissa in the form l*2^k, with 0.5 <= d < 1; - // truncation is guaranteed to go towards zero + // l = +/- 0.1*...* + // ------ + // 53 digits + // in order to round away from zero, it suffices to add/subtract 2^-53 - // Exponent k = 0; - // double l = mpz_get_d_2exp (&k, man()); + // double u = l; + // if (l < 0) { + // // u is already the upper bound, decrease l to get lower bound + // l -= std::ldexp(1.0, -53); + // } else { + // // l is already the lower bound, increase u to get upper bound + // u += std::ldexp(1.0, -53); + // } - // l = +/- 0.1*...* - // ------ - // 53 digits - // in order to round away from zero, it suffices to add/subtract 2^-53 + // The interval is now [l * 2^(k + exp()), u * 2^(k + exp())] + // we may cast the exponents to int, since if that's going to + // create an overflow, we correctly get infinities. - // double u = l; - // if (l < 0) - // // u is already the upper bound, decrease l to get lower bound - // l -= std::ldexp(1.0, -53); - // else - // // l is already the lower bound, increase u to get upper bound - // u += std::ldexp(1.0, -53); + // return std::pair, long> + // (std::pair(l, u), k + exp()); + } - // the interval is now [l * 2^(k + exp()), u * 2^(k + exp())] - // we may cast the exponents to int, since if that's going to - // create an overflow, we correctly get infinities + std::pair get_interval_as_gmpzf( const Type& x ) const { - // return std::pair, long> - // (std::pair(l, u), k + exp()); + // Do here as MP_Float does. + double i = 0.0, s = 0.0; - // // do here as MP_Float does - // std::pair, long> n = - // q.numerator().to_interval_exp(); - // std::pair, long> d = - // q.denominator().to_interval_exp(); + const auto n = get_interval_exp(x.numerator()); + // const auto d = get_interval_exp(x.denominator()); - // CGAL_assertion_msg(CGAL::abs(double(n.second) - double(d.second)) < (1<<30)*2.0, - // "Exponent overflow in Quotient to_interval"); - // return ldexp(Interval_nt<>(n.first) / Interval_nt<>(d.first), - // static_cast(n.second - d.second)).pair(); + // CGAL_assertion_msg( + // CGAL::abs(double(n.second) - double(d.second)) < (1<<30)*2.0, + // "Exponent overflow in Quotient to_interval"); + // return ldexp( + // Interval_nt<>(n.first) / Interval_nt<>(d.first), + // static_cast(n.second - d.second)).pair(); return std::make_pair(i, s); + } + + std::pair operator()( const Type& x ) const { + + // std::cout << "xx: " << x << std::endl; + // std::cout << "xn: " << x.num << std::endl; + // std::cout << "xd: " << x.den << std::endl; + + #if defined(CGAL_USE_CPP_INT) && true + + #if true // tight bounds optimized + + // Make tight and fast bounds for x here. + // 1. Gmpzf.h - line 156 and Gmpzf_type.h - line 412. + // 2. generic_interconvert.hpp - line 305. + + // Using 1 as reference: + return get_interval_as_gmpzf(x); #endif From 9983beb9dfc93c431c30d7182cd61f18f052f641 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 26 Aug 2021 17:24:55 +0200 Subject: [PATCH 022/127] finished first version of two new tight to_interval() based on gmzf and boost --- Number_types/include/CGAL/Quotient.h | 186 +++++++++++++++++++++++++-- 1 file changed, 173 insertions(+), 13 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index f0b363f0e3d8..5a54ff5c7b93 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -708,7 +708,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { public: - std::pair< std::pair, long > get_interval_exp(const NT& x) const { + std::pair< std::pair, long > get_interval_exp( NT& x ) const { std::cout << std::endl; std::cout << " --- debugging get_interval_exp() --- " << std::endl; @@ -718,8 +718,38 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // first get mantissa in the form l*2^k, with 0.5 <= d < 1; // truncation is guaranteed to go towards zero. - // Exponent k = 0; - // double l = mpz_get_d_2exp (&k, man()); + const unsigned n = msb(x); + std::cout << "msb before shift: " << msb(x) << std::endl; + + if (n > 52) { + + const unsigned d = n - 52; + x = x >> d; + std::cout << "shifting.... " << std::endl; + std::cout << "msb after shift: " << msb(x) << std::endl; + std::cout << "shift difference: " << d << std::endl; + std::cout << "shifted x: " << x << std::endl; + const double l(x); + const double u(x + 1); + std::cout << "l: " << l << std::endl; + std::cout << "u: " << u << std::endl; + return std::make_pair( std::make_pair(l, u), d ); + + } else { + + std::cout << "no shifting required " << std::endl; + const double l(x); + const double u(l); + std::cout << "l: " << l << std::endl; + std::cout << "u: " << u << std::endl; + return std::make_pair( std::make_pair(l, u), 0 ); + + } + + // exit(EXIT_SUCCESS); + + // long k = 0; + // double l = mpz_get_d_2exp (&k, man()); // we miss this function for cpp_int // l = +/- 0.1*...* // ------ @@ -743,23 +773,145 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // (std::pair(l, u), k + exp()); } - std::pair get_interval_as_gmpzf( const Type& x ) const { + std::pair get_interval_as_gmpzf( Type& x ) const { // Do here as MP_Float does. - double i = 0.0, s = 0.0; + // double i = 0.0, s = 0.0; + + Protect_FPU_rounding P(CGAL_FE_TONEAREST); + const auto n = get_interval_exp(x.num); + const auto d = get_interval_exp(x.den); - const auto n = get_interval_exp(x.numerator()); - // const auto d = get_interval_exp(x.denominator()); + // exit(EXIT_SUCCESS); // CGAL_assertion_msg( // CGAL::abs(double(n.second) - double(d.second)) < (1<<30)*2.0, // "Exponent overflow in Quotient to_interval"); - // return ldexp( - // Interval_nt<>(n.first) / Interval_nt<>(d.first), - // static_cast(n.second - d.second)).pair(); + const Interval_nt<> num(n.first); + const Interval_nt<> den(d.first); + const Interval_nt<> div = num / den; + + std::cout << std::endl; + std::cout << " --- debugging get_interval_as_gmpzf() --- " << std::endl; + std::cout << "interval nt num: " << num << std::endl; + std::cout << "interval nt den: " << den << std::endl; + std::cout << "interval nt div: " << div << std::endl; + + const long e = static_cast(n.second - d.second); + std::cout << "exp: " << e << std::endl; + const auto pair = ldexp(div, e).pair(); + std::cout << "ldexp l: " << pair.first << std::endl; + std::cout << "ldexp u: " << pair.second << std::endl; + std::cout << std::endl; - return std::make_pair(i, s); + // TODO: Do not forget to change sign here! + + // exit(EXIT_SUCCESS); + + return pair; + } + + std::pair get_interval_as_boost( Type& x ) const { + + double l = 0.0, u = 0.0; + + if (x.num == 0) { + return std::make_pair(l, u); + } + + bool change_sign = false; + if (x.num < 0) { + change_sign = true; + x.num = -x.num; + } + + const int denom_bits = msb(x.den); + const int shift = std::numeric_limits::digits + denom_bits - msb(x.num); + + std::cout << std::endl; + std::cout << " --- debugging get_interval_as_boost() --- " << std::endl; + std::cout << "num before shift: " << x.num << std::endl; + std::cout << "den before shift: " << x.den << std::endl; + + std::cout << "num bits: " << msb(x.num) << std::endl; + std::cout << "den bits: " << msb(x.den) << std::endl; + std::cout << "shift : " << shift << std::endl; + std::cout << std::endl; + + if (shift > 0) { + x.num <<= shift; + } else if (shift < 0) { + x.den <<= boost::multiprecision::detail::unsigned_abs(shift); + } + std::cout << "num after shift: " << x.num << std::endl; + std::cout << "den after shift: " << x.den << std::endl; + std::cout << std::endl; + + // exit(EXIT_SUCCESS); + + decltype(x.num) q, r; + boost::multiprecision::divide_qr(x.num, x.den, q, r); + decltype(q) p = q; + const int q_bits = msb(q); + std::cout << "q bits: " << q_bits << std::endl; + std::cout << "p before: " << p << std::endl; + std::cout << "q before: " << q << std::endl; + std::cout << "r before: " << r << std::endl; + std::cout << std::endl; + const int num_dbl_digits = std::numeric_limits::digits; + + // exit(EXIT_SUCCESS); + + if (q != 0) { + if (q_bits == num_dbl_digits - 1) { + + // Round up if 2 * r > denom: + r <<= 1; + const int c = r.compare(x.den); + if (c > 0) { + ++q; + } else if ((c == 0) && (q & 1u)) { + ++q; + } + std::cout << "p after1: " << p << std::endl; + std::cout << "q after1: " << q << std::endl; + std::cout << "r after1: " << r << std::endl; + + } else { + + CGAL_assertion(q_bits == num_dbl_digits); + // We basically already have the rounding info: + if (q & 1u) { + if (r || (q & 2u)) { + ++q; + } + } + std::cout << "p after2: " << p << std::endl; + std::cout << "q after2: " << q << std::endl; + std::cout << "r after2: " << r << std::endl; + } + + } + std::cout << std::endl; + + // exit(EXIT_SUCCESS); + + l = boost::multiprecision::detail::do_cast(p); + l = std::ldexp(l, -shift); + u = boost::multiprecision::detail::do_cast(q); + u = std::ldexp(u, -shift); + if (change_sign) { + l = -l; + u = -u; + } + + std::cout << "l: " << l << std::endl; + std::cout << "u: " << u << std::endl; + + // exit(EXIT_SUCCESS); + + return std::make_pair(l, u); } std::pair operator()( const Type& x ) const { @@ -770,14 +922,22 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > #if defined(CGAL_USE_CPP_INT) && true - #if true // tight bounds optimized + #if false // tight bounds optimized // Make tight and fast bounds for x here. // 1. Gmpzf.h - line 156 and Gmpzf_type.h - line 412. // 2. generic_interconvert.hpp - line 305. // Using 1 as reference: - return get_interval_as_gmpzf(x); + // TODO: Can we avoid this copying by getting x without const? + Type xx = x; + + // Does not yet take into account the sign and gives slightly + // different result for the HARD CASE. + // return get_interval_as_gmpzf(xx); + + // Works slightly better than the first one and it is more complete. + return get_interval_as_boost(xx); #endif From 41c6473c8f999bf81e33c3674b1cd58f9dbf9aaa Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 27 Aug 2021 12:05:12 +0200 Subject: [PATCH 023/127] cleanup --- Number_types/include/CGAL/Quotient.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 5a54ff5c7b93..09aa6950c113 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -928,7 +928,6 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // 1. Gmpzf.h - line 156 and Gmpzf_type.h - line 412. // 2. generic_interconvert.hpp - line 305. - // Using 1 as reference: // TODO: Can we avoid this copying by getting x without const? Type xx = x; @@ -965,6 +964,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // We do not have here a tight bound! // TODO: Use a binary search or limbs to find a tighter bound! // For REG tests this assertion fails! + // Are they real bounds? When q = 0, we can be arbitrarily far away + // from the lower and upper bound. CGAL_assertion(CGAL::abs(x.num) < CGAL::abs(x.den)); if (x.num > 0 && x.den > 0) { return std::make_pair( 0.0, 1.0); @@ -976,9 +977,11 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > #else // tight bounds using cpp_rational - boost::multiprecision::cpp_rational rat; // TODO: Is it fast enough? + // TODO: Is it fast enough? Seems so because this conversion happens + // only a few times during the run, at least for NEF. + boost::multiprecision::cpp_rational rat; CGAL_assertion(x.den != 0); - if (x.den < 0) { + if (x.den < 0) { // we do it due to the bug in boost rat = boost::multiprecision::cpp_rational(-x.num, -x.den); } else { rat = boost::multiprecision::cpp_rational( x.num, x.den); From 28c29f8d4d9bd86402fd56232d05e601316fad3c Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 27 Aug 2021 15:31:29 +0200 Subject: [PATCH 024/127] finished tight interval with boost --- Number_types/include/CGAL/Quotient.h | 70 ++++++++++++++++++---------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 09aa6950c113..7462e341ac85 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -815,35 +815,52 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > std::pair get_interval_as_boost( Type& x ) const { double l = 0.0, u = 0.0; - - if (x.num == 0) { + if (x.num == 0) { // return [0.0, 0.0] return std::make_pair(l, u); } + CGAL_assertion(x.num != 0); + CGAL_assertion(x.den != 0); + // Hnalde signs. bool change_sign = false; - if (x.num < 0) { + if (x.num < 0 && x.den < 0) { + x.num = -x.num; + x.den = -x.den; + } else if (x.num < 0 && x.den > 0) { change_sign = true; x.num = -x.num; + } else if (x.num > 0 && x.den < 0) { + change_sign = true; + x.den = -x.den; } - const int denom_bits = msb(x.den); - const int shift = std::numeric_limits::digits + denom_bits - msb(x.num); - std::cout << std::endl; std::cout << " --- debugging get_interval_as_boost() --- " << std::endl; + std::cout << std::endl; + + std::cout << "change sign: " << change_sign << std::endl; + + const int num_dbl_digits = std::numeric_limits::digits; + const int shift = num_dbl_digits + (msb(x.den) - msb(x.num)); + std::cout << "num before shift: " << x.num << std::endl; std::cout << "den before shift: " << x.den << std::endl; - std::cout << "num bits: " << msb(x.num) << std::endl; - std::cout << "den bits: " << msb(x.den) << std::endl; - std::cout << "shift : " << shift << std::endl; - std::cout << std::endl; + std::cout << "digits : " << num_dbl_digits << std::endl; + std::cout << "diff1 : " << int(msb(x.den) - msb(x.num)) << std::endl; + std::cout << "num msb: " << int(msb(x.num)) << std::endl; + std::cout << "den msb: " << int(msb(x.den)) << std::endl; + std::cout << "shift : " << shift << std::endl; if (shift > 0) { - x.num <<= shift; + x.num <<= shift; // that is multiply bu 2^shift } else if (shift < 0) { x.den <<= boost::multiprecision::detail::unsigned_abs(shift); } + CGAL_assertion(int(msb(x.den) - msb(x.num)) == -53); + std::cout << "diff2 : " << int(msb(x.den) - msb(x.num)) << std::endl; + std::cout << std::endl; + std::cout << "num after shift: " << x.num << std::endl; std::cout << "den after shift: " << x.den << std::endl; std::cout << std::endl; @@ -854,32 +871,36 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > boost::multiprecision::divide_qr(x.num, x.den, q, r); decltype(q) p = q; const int q_bits = msb(q); - std::cout << "q bits: " << q_bits << std::endl; + std::cout << "q msb : " << q_bits << std::endl; std::cout << "p before: " << p << std::endl; std::cout << "q before: " << q << std::endl; std::cout << "r before: " << r << std::endl; std::cout << std::endl; - const int num_dbl_digits = std::numeric_limits::digits; // exit(EXIT_SUCCESS); - if (q != 0) { + if (r != 0) { if (q_bits == num_dbl_digits - 1) { - // Round up if 2 * r > denom: - r <<= 1; + CGAL_assertion(r > 0); + // Round up if 2 * r > x.den: + r <<= 1; // multiply r by 2 const int c = r.compare(x.den); - if (c > 0) { + std::cout << "cmp: " << c << std::endl; + if (c > 0) { // we are in the second half of the interval between two doubles ++q; } else if ((c == 0) && (q & 1u)) { ++q; } + // otherwise we are already in the correct position + std::cout << "p after1: " << p << std::endl; std::cout << "q after1: " << q << std::endl; std::cout << "r after1: " << r << std::endl; } else { + CGAL_assertion(r > 0); CGAL_assertion(q_bits == num_dbl_digits); // We basically already have the rounding info: if (q & 1u) { @@ -891,19 +912,20 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > std::cout << "q after2: " << q << std::endl; std::cout << "r after2: " << r << std::endl; } - } - std::cout << std::endl; // exit(EXIT_SUCCESS); l = boost::multiprecision::detail::do_cast(p); - l = std::ldexp(l, -shift); + std::cout << "do cast l: " << l << std::endl; + l = std::ldexp(l, -shift); // divide by 2^shift u = boost::multiprecision::detail::do_cast(q); - u = std::ldexp(u, -shift); + std::cout << "do cast u: " << u << std::endl; + u = std::ldexp(u, -shift); // divide by 2^shift if (change_sign) { - l = -l; - u = -u; + const double t = l; + l = -u; + u = -t; } std::cout << "l: " << l << std::endl; @@ -922,7 +944,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > #if defined(CGAL_USE_CPP_INT) && true - #if false // tight bounds optimized + #if true // tight bounds optimized // Make tight and fast bounds for x here. // 1. Gmpzf.h - line 156 and Gmpzf_type.h - line 412. From fada5ffb26bb4e3fbb4ad8f847340849b5214bef Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 27 Aug 2021 15:43:16 +0200 Subject: [PATCH 025/127] added verbose --- Number_types/include/CGAL/Quotient.h | 199 +++++++++++++++------------ 1 file changed, 108 insertions(+), 91 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 7462e341ac85..31c6624148ed 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -708,79 +708,74 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { public: - std::pair< std::pair, long > get_interval_exp( NT& x ) const { + std::pair< std::pair, long > get_interval_exp( const bool verbose, NT& x ) const { - std::cout << std::endl; - std::cout << " --- debugging get_interval_exp() --- " << std::endl; - std::cout << "x: " << x << std::endl; + if (verbose) { + std::cout << std::endl; + std::cout << " --- debugging get_interval_exp() --- " << std::endl; + std::cout << std::endl; + + std::cout << "x: " << x << std::endl; + } // Get surrounding interval of the form [l*2^k, u*2^k] // first get mantissa in the form l*2^k, with 0.5 <= d < 1; // truncation is guaranteed to go towards zero. const unsigned n = msb(x); - std::cout << "msb before shift: " << msb(x) << std::endl; + if (verbose) { + std::cout << "msb before shift: " << msb(x) << std::endl; + } if (n > 52) { const unsigned d = n - 52; x = x >> d; - std::cout << "shifting.... " << std::endl; - std::cout << "msb after shift: " << msb(x) << std::endl; - std::cout << "shift difference: " << d << std::endl; - std::cout << "shifted x: " << x << std::endl; + + if (verbose) { + std::cout << "shifting.... " << std::endl; + std::cout << "msb after shift: " << msb(x) << std::endl; + std::cout << "shift difference: " << d << std::endl; + std::cout << "shifted x: " << x << std::endl; + } + + // const double l = boost::multiprecision::detail::do_cast(x); + // const double u = boost::multiprecision::detail::do_cast(x + 1); + const double l(x); const double u(x + 1); - std::cout << "l: " << l << std::endl; - std::cout << "u: " << u << std::endl; + + if (verbose) { + std::cout << "l: " << l << std::endl; + std::cout << "u: " << u << std::endl; + } return std::make_pair( std::make_pair(l, u), d ); } else { - std::cout << "no shifting required " << std::endl; + // const double l = boost::multiprecision::detail::do_cast(x); + // const double u = l; + const double l(x); const double u(l); - std::cout << "l: " << l << std::endl; - std::cout << "u: " << u << std::endl; - return std::make_pair( std::make_pair(l, u), 0 ); + if (verbose) { + std::cout << "no shifting required " << std::endl; + std::cout << "l: " << l << std::endl; + std::cout << "u: " << u << std::endl; + } + return std::make_pair( std::make_pair(l, u), 0 ); } - - // exit(EXIT_SUCCESS); - - // long k = 0; - // double l = mpz_get_d_2exp (&k, man()); // we miss this function for cpp_int - - // l = +/- 0.1*...* - // ------ - // 53 digits - // in order to round away from zero, it suffices to add/subtract 2^-53 - - // double u = l; - // if (l < 0) { - // // u is already the upper bound, decrease l to get lower bound - // l -= std::ldexp(1.0, -53); - // } else { - // // l is already the lower bound, increase u to get upper bound - // u += std::ldexp(1.0, -53); - // } - - // The interval is now [l * 2^(k + exp()), u * 2^(k + exp())] - // we may cast the exponents to int, since if that's going to - // create an overflow, we correctly get infinities. - - // return std::pair, long> - // (std::pair(l, u), k + exp()); } - std::pair get_interval_as_gmpzf( Type& x ) const { + std::pair get_interval_as_gmpzf( const bool verbose, Type& x ) const { // Do here as MP_Float does. // double i = 0.0, s = 0.0; Protect_FPU_rounding P(CGAL_FE_TONEAREST); - const auto n = get_interval_exp(x.num); - const auto d = get_interval_exp(x.den); + const auto n = get_interval_exp(verbose, x.num); + const auto d = get_interval_exp(verbose, x.den); // exit(EXIT_SUCCESS); @@ -792,27 +787,31 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const Interval_nt<> den(d.first); const Interval_nt<> div = num / den; - std::cout << std::endl; - std::cout << " --- debugging get_interval_as_gmpzf() --- " << std::endl; - std::cout << "interval nt num: " << num << std::endl; - std::cout << "interval nt den: " << den << std::endl; - std::cout << "interval nt div: " << div << std::endl; + if (verbose) { + std::cout << std::endl; + std::cout << " --- debugging get_interval_as_gmpzf() --- " << std::endl; + std::cout << "interval nt num: " << num << std::endl; + std::cout << "interval nt den: " << den << std::endl; + std::cout << "interval nt div: " << div << std::endl; + } const long e = static_cast(n.second - d.second); - std::cout << "exp: " << e << std::endl; const auto pair = ldexp(div, e).pair(); - std::cout << "ldexp l: " << pair.first << std::endl; - std::cout << "ldexp u: " << pair.second << std::endl; - std::cout << std::endl; - // TODO: Do not forget to change sign here! + if (verbose) { + std::cout << "exp: " << e << std::endl; + std::cout << "ldexp l: " << pair.first << std::endl; + std::cout << "ldexp u: " << pair.second << std::endl; + std::cout << std::endl; + } + // TODO: Do not forget to change sign here! // exit(EXIT_SUCCESS); return pair; } - std::pair get_interval_as_boost( Type& x ) const { + std::pair get_interval_as_boost( const bool verbose, Type& x ) const { double l = 0.0, u = 0.0; if (x.num == 0) { // return [0.0, 0.0] @@ -821,7 +820,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(x.num != 0); CGAL_assertion(x.den != 0); - // Hnalde signs. + // Handle signs. bool change_sign = false; if (x.num < 0 && x.den < 0) { x.num = -x.num; @@ -834,23 +833,27 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > x.den = -x.den; } - std::cout << std::endl; - std::cout << " --- debugging get_interval_as_boost() --- " << std::endl; - std::cout << std::endl; + if (verbose) { + std::cout << std::endl; + std::cout << " --- debugging get_interval_as_boost() --- " << std::endl; + std::cout << std::endl; - std::cout << "change sign: " << change_sign << std::endl; + std::cout << "change sign: " << change_sign << std::endl; + } const int num_dbl_digits = std::numeric_limits::digits; const int shift = num_dbl_digits + (msb(x.den) - msb(x.num)); - std::cout << "num before shift: " << x.num << std::endl; - std::cout << "den before shift: " << x.den << std::endl; + if (verbose) { + std::cout << "num before shift: " << x.num << std::endl; + std::cout << "den before shift: " << x.den << std::endl; - std::cout << "digits : " << num_dbl_digits << std::endl; - std::cout << "diff1 : " << int(msb(x.den) - msb(x.num)) << std::endl; - std::cout << "num msb: " << int(msb(x.num)) << std::endl; - std::cout << "den msb: " << int(msb(x.den)) << std::endl; - std::cout << "shift : " << shift << std::endl; + std::cout << "digits : " << num_dbl_digits << std::endl; + std::cout << "diff1 : " << int(msb(x.den) - msb(x.num)) << std::endl; + std::cout << "num msb: " << int(msb(x.num)) << std::endl; + std::cout << "den msb: " << int(msb(x.den)) << std::endl; + std::cout << "shift : " << shift << std::endl; + } if (shift > 0) { x.num <<= shift; // that is multiply bu 2^shift @@ -858,12 +861,15 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > x.den <<= boost::multiprecision::detail::unsigned_abs(shift); } CGAL_assertion(int(msb(x.den) - msb(x.num)) == -53); - std::cout << "diff2 : " << int(msb(x.den) - msb(x.num)) << std::endl; - std::cout << std::endl; - std::cout << "num after shift: " << x.num << std::endl; - std::cout << "den after shift: " << x.den << std::endl; - std::cout << std::endl; + if (verbose) { + std::cout << "diff2 : " << int(msb(x.den) - msb(x.num)) << std::endl; + std::cout << std::endl; + + std::cout << "num after shift: " << x.num << std::endl; + std::cout << "den after shift: " << x.den << std::endl; + std::cout << std::endl; + } // exit(EXIT_SUCCESS); @@ -871,11 +877,14 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > boost::multiprecision::divide_qr(x.num, x.den, q, r); decltype(q) p = q; const int q_bits = msb(q); - std::cout << "q msb : " << q_bits << std::endl; - std::cout << "p before: " << p << std::endl; - std::cout << "q before: " << q << std::endl; - std::cout << "r before: " << r << std::endl; - std::cout << std::endl; + + if (verbose) { + std::cout << "q msb : " << q_bits << std::endl; + std::cout << "p before: " << p << std::endl; + std::cout << "q before: " << q << std::endl; + std::cout << "r before: " << r << std::endl; + std::cout << std::endl; + } // exit(EXIT_SUCCESS); @@ -886,7 +895,6 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // Round up if 2 * r > x.den: r <<= 1; // multiply r by 2 const int c = r.compare(x.den); - std::cout << "cmp: " << c << std::endl; if (c > 0) { // we are in the second half of the interval between two doubles ++q; } else if ((c == 0) && (q & 1u)) { @@ -894,9 +902,12 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } // otherwise we are already in the correct position - std::cout << "p after1: " << p << std::endl; - std::cout << "q after1: " << q << std::endl; - std::cout << "r after1: " << r << std::endl; + if (verbose) { + std::cout << "cmp: " << c << std::endl; + std::cout << "p after1: " << p << std::endl; + std::cout << "q after1: " << q << std::endl; + std::cout << "r after1: " << r << std::endl; + } } else { @@ -908,19 +919,22 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > ++q; } } - std::cout << "p after2: " << p << std::endl; - std::cout << "q after2: " << q << std::endl; - std::cout << "r after2: " << r << std::endl; + + if (verbose) { + std::cout << "p after2: " << p << std::endl; + std::cout << "q after2: " << q << std::endl; + std::cout << "r after2: " << r << std::endl; + } } } // exit(EXIT_SUCCESS); l = boost::multiprecision::detail::do_cast(p); - std::cout << "do cast l: " << l << std::endl; + if (verbose) std::cout << "do cast l: " << l << std::endl; l = std::ldexp(l, -shift); // divide by 2^shift u = boost::multiprecision::detail::do_cast(q); - std::cout << "do cast u: " << u << std::endl; + if (verbose) std::cout << "do cast u: " << u << std::endl; u = std::ldexp(u, -shift); // divide by 2^shift if (change_sign) { const double t = l; @@ -928,8 +942,10 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > u = -t; } - std::cout << "l: " << l << std::endl; - std::cout << "u: " << u << std::endl; + if (verbose) { + std::cout << "l: " << l << std::endl; + std::cout << "u: " << u << std::endl; + } // exit(EXIT_SUCCESS); @@ -952,13 +968,14 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // TODO: Can we avoid this copying by getting x without const? Type xx = x; + const bool verbose = false; // Does not yet take into account the sign and gives slightly // different result for the HARD CASE. - // return get_interval_as_gmpzf(xx); + // return get_interval_as_gmpzf(verbose, xx); - // Works slightly better than the first one and it is more complete. - return get_interval_as_boost(xx); + // Works slightly better than the first one. + return get_interval_as_boost(verbose, xx); #endif From 49b3c28338058862f9dd6222fd656872684b0aed Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 27 Aug 2021 16:21:16 +0200 Subject: [PATCH 026/127] finished tight interval as gmpzf --- Number_types/include/CGAL/Quotient.h | 81 ++++++++++++++++++---------- 1 file changed, 54 insertions(+), 27 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 31c6624148ed..bd002c8c5657 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -722,14 +722,16 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // first get mantissa in the form l*2^k, with 0.5 <= d < 1; // truncation is guaranteed to go towards zero. + CGAL_assertion(x >= 0); const unsigned n = msb(x); if (verbose) { std::cout << "msb before shift: " << msb(x) << std::endl; } - if (n > 52) { + const unsigned num_dbl_digits = std::numeric_limits::digits; + if (n > num_dbl_digits) { - const unsigned d = n - 52; + const unsigned d = n - num_dbl_digits; x = x >> d; if (verbose) { @@ -739,11 +741,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > std::cout << "shifted x: " << x << std::endl; } - // const double l = boost::multiprecision::detail::do_cast(x); - // const double u = boost::multiprecision::detail::do_cast(x + 1); - - const double l(x); - const double u(x + 1); + const double l = boost::multiprecision::detail::do_cast(x); + const double u = boost::multiprecision::detail::do_cast(x + 1); if (verbose) { std::cout << "l: " << l << std::endl; @@ -753,11 +752,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } else { - // const double l = boost::multiprecision::detail::do_cast(x); - // const double u = l; - - const double l(x); - const double u(l); + const double l = boost::multiprecision::detail::do_cast(x); + const double u = l; if (verbose) { std::cout << "no shifting required " << std::endl; @@ -770,8 +766,26 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > std::pair get_interval_as_gmpzf( const bool verbose, Type& x ) const { - // Do here as MP_Float does. - // double i = 0.0, s = 0.0; + double l = 0.0, u = 0.0; + if (x.num == 0) { // return [0.0, 0.0] + return std::make_pair(l, u); + } + CGAL_assertion(x.num != 0); + CGAL_assertion(x.den != 0); + + // Handle signs. + bool change_sign = false; + if (x.num < 0 && x.den < 0) { + x.num = -x.num; + x.den = -x.den; + } else if (x.num < 0 && x.den > 0) { + change_sign = true; + x.num = -x.num; + } else if (x.num > 0 && x.den < 0) { + change_sign = true; + x.den = -x.den; + } + CGAL_assertion(x.num > 0 && x.den > 0); Protect_FPU_rounding P(CGAL_FE_TONEAREST); const auto n = get_interval_exp(verbose, x.num); @@ -779,9 +793,9 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // exit(EXIT_SUCCESS); - // CGAL_assertion_msg( - // CGAL::abs(double(n.second) - double(d.second)) < (1<<30)*2.0, - // "Exponent overflow in Quotient to_interval"); + CGAL_assertion_msg( + CGAL::abs(double(n.second) - double(d.second)) < (1<<30)*2.0, + "Exponent overflow in Quotient to_interval()!"); const Interval_nt<> num(n.first); const Interval_nt<> den(d.first); @@ -790,25 +804,37 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > if (verbose) { std::cout << std::endl; std::cout << " --- debugging get_interval_as_gmpzf() --- " << std::endl; + std::cout << std::endl; + + std::cout << "change sign: " << change_sign << std::endl; std::cout << "interval nt num: " << num << std::endl; std::cout << "interval nt den: " << den << std::endl; std::cout << "interval nt div: " << div << std::endl; } - const long e = static_cast(n.second - d.second); - const auto pair = ldexp(div, e).pair(); + const int e = static_cast(n.second - d.second); + std::tie(l, u) = ldexp(div, e).pair(); if (verbose) { std::cout << "exp: " << e << std::endl; - std::cout << "ldexp l: " << pair.first << std::endl; - std::cout << "ldexp u: " << pair.second << std::endl; + std::cout << "ldexp l: " << l << std::endl; + std::cout << "ldexp u: " << u << std::endl; std::cout << std::endl; } - // TODO: Do not forget to change sign here! - // exit(EXIT_SUCCESS); + if (change_sign) { + const double t = l; + l = -u; + u = -t; + } - return pair; + if (verbose) { + std::cout << "l: " << l << std::endl; + std::cout << "u: " << u << std::endl; + } + + // exit(EXIT_SUCCESS); + return std::make_pair(l, u); } std::pair get_interval_as_boost( const bool verbose, Type& x ) const { @@ -832,6 +858,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > change_sign = true; x.den = -x.den; } + CGAL_assertion(x.num > 0 && x.den > 0); if (verbose) { std::cout << std::endl; @@ -936,6 +963,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > u = boost::multiprecision::detail::do_cast(q); if (verbose) std::cout << "do cast u: " << u << std::endl; u = std::ldexp(u, -shift); // divide by 2^shift + if (change_sign) { const double t = l; l = -u; @@ -948,7 +976,6 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } // exit(EXIT_SUCCESS); - return std::make_pair(l, u); } @@ -972,10 +999,10 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // Does not yet take into account the sign and gives slightly // different result for the HARD CASE. - // return get_interval_as_gmpzf(verbose, xx); + return get_interval_as_gmpzf(verbose, xx); // Works slightly better than the first one. - return get_interval_as_boost(verbose, xx); + // return get_interval_as_boost(verbose, xx); #endif From 8aefedce37aefdb8e67abe0b5c7e03264495b340 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 27 Aug 2021 16:31:05 +0200 Subject: [PATCH 027/127] all simple tests are passing for new tight intervals --- Number_types/include/CGAL/Quotient.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index bd002c8c5657..70d1ca4e8430 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -997,12 +997,12 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > Type xx = x; const bool verbose = false; - // Does not yet take into account the sign and gives slightly - // different result for the HARD CASE. - return get_interval_as_gmpzf(verbose, xx); + // Seems to be less precise and we rarely end up with an interval [d,d] + // even for numbers, which are exactly representable as double. + // return get_interval_as_gmpzf(verbose, xx); // Works slightly better than the first one. - // return get_interval_as_boost(verbose, xx); + return get_interval_as_boost(verbose, xx); #endif From e9694bf2a4cc27f3f689207063b9300860b3fafa Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 27 Aug 2021 17:19:51 +0200 Subject: [PATCH 028/127] better verbose --- Number_types/include/CGAL/Quotient.h | 326 +++++++++++++++++++-------- 1 file changed, 231 insertions(+), 95 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 70d1ca4e8430..cbe256796163 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -708,15 +708,167 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { public: - std::pair< std::pair, long > get_interval_exp( const bool verbose, NT& x ) const { + // =========================================================================== // - if (verbose) { - std::cout << std::endl; - std::cout << " --- debugging get_interval_exp() --- " << std::endl; - std::cout << std::endl; + // CURRENT VERSION - std::cout << "x: " << x << std::endl; + // =========================================================================== // + + std::pair< std::pair, long > get_interval_exp( NT& x ) const { + + CGAL_assertion(x >= 0); + const unsigned n = msb(x); + const unsigned num_dbl_digits = std::numeric_limits::digits; + if (n > num_dbl_digits) { + + const unsigned d = n - num_dbl_digits; + x = x >> d; + + const double l = boost::multiprecision::detail::do_cast(x); + const double u = boost::multiprecision::detail::do_cast(x + 1); + return std::make_pair( std::make_pair(l, u), d ); + + } else { + + const double l = boost::multiprecision::detail::do_cast(x); + const double u = l; + return std::make_pair( std::make_pair(l, u), 0 ); + } + } + + std::pair get_interval_as_gmpzf( Type& x ) const { + + double l = 0.0, u = 0.0; + if (x.num == 0) { // return [0.0, 0.0] + return std::make_pair(l, u); + } + CGAL_assertion(x.num != 0); + CGAL_assertion(x.den != 0); + + // Handle signs. + bool change_sign = false; + if (x.num < 0 && x.den < 0) { + x.num = -x.num; + x.den = -x.den; + } else if (x.num < 0 && x.den > 0) { + change_sign = true; + x.num = -x.num; + } else if (x.num > 0 && x.den < 0) { + change_sign = true; + x.den = -x.den; + } + CGAL_assertion(x.num > 0 && x.den > 0); + + Protect_FPU_rounding P(CGAL_FE_TONEAREST); + const auto n = get_interval_exp(x.num); + const auto d = get_interval_exp(x.den); + + CGAL_assertion_msg( + CGAL::abs(double(n.second) - double(d.second)) < (1<<30)*2.0, + "Exponent overflow in Quotient to_interval()!"); + + const Interval_nt<> num(n.first); + const Interval_nt<> den(d.first); + const Interval_nt<> div = num / den; + + const int e = static_cast(n.second - d.second); + std::tie(l, u) = ldexp(div, e).pair(); + + if (change_sign) { + const double t = l; + l = -u; + u = -t; + } + return std::make_pair(l, u); + } + + std::pair get_interval_as_boost( Type& x ) const { + + double l = 0.0, u = 0.0; + if (x.num == 0) { // return [0.0, 0.0] + return std::make_pair(l, u); } + CGAL_assertion(x.num != 0); + CGAL_assertion(x.den != 0); + + // Handle signs. + bool change_sign = false; + if (x.num < 0 && x.den < 0) { + x.num = -x.num; + x.den = -x.den; + } else if (x.num < 0 && x.den > 0) { + change_sign = true; + x.num = -x.num; + } else if (x.num > 0 && x.den < 0) { + change_sign = true; + x.den = -x.den; + } + CGAL_assertion(x.num > 0 && x.den > 0); + + const int num_dbl_digits = std::numeric_limits::digits; + const int shift = num_dbl_digits + (msb(x.den) - msb(x.num)); + if (shift > 0) { + x.num <<= shift; + } else if (shift < 0) { + x.den <<= boost::multiprecision::detail::unsigned_abs(shift); + } + CGAL_assertion(int(msb(x.den) - msb(x.num)) == -53); + + decltype(x.num) q, r; + boost::multiprecision::divide_qr(x.num, x.den, q, r); + decltype(q) p = q; + const int q_bits = msb(q); + + if (r != 0) { + if (q_bits == num_dbl_digits - 1) { + + CGAL_assertion(r > 0); + r <<= 1; + const int c = r.compare(x.den); + if (c > 0) { + ++q; + } else if ((c == 0) && (q & 1u)) { + ++q; + } + + } else { + + CGAL_assertion(r > 0); + CGAL_assertion(q_bits == num_dbl_digits); + if (q & 1u) { + if (r || (q & 2u)) { + ++q; + } + } + } + } + + l = boost::multiprecision::detail::do_cast(p); + l = std::ldexp(l, -shift); + u = boost::multiprecision::detail::do_cast(q); + u = std::ldexp(u, -shift); + + if (change_sign) { + const double t = l; + l = -u; + u = -t; + } + return std::make_pair(l, u); + } + + // =========================================================================== // + + // WORK IN PROGRESS + + // =========================================================================== // + + std::pair< std::pair, long > get_interval_exp_work_in_progress( NT& x ) const { + + std::cout << std::endl; + std::cout << " --- debugging get_interval_exp() --- " << std::endl; + std::cout << std::endl; + + std::cout << "x: " << x << std::endl; // Get surrounding interval of the form [l*2^k, u*2^k] // first get mantissa in the form l*2^k, with 0.5 <= d < 1; @@ -724,9 +876,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(x >= 0); const unsigned n = msb(x); - if (verbose) { - std::cout << "msb before shift: " << msb(x) << std::endl; - } + std::cout << "msb before shift: " << msb(x) << std::endl; const unsigned num_dbl_digits = std::numeric_limits::digits; if (n > num_dbl_digits) { @@ -734,20 +884,17 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const unsigned d = n - num_dbl_digits; x = x >> d; - if (verbose) { - std::cout << "shifting.... " << std::endl; - std::cout << "msb after shift: " << msb(x) << std::endl; - std::cout << "shift difference: " << d << std::endl; - std::cout << "shifted x: " << x << std::endl; - } + std::cout << "shifting.... " << std::endl; + std::cout << "msb after shift: " << msb(x) << std::endl; + std::cout << "shift difference: " << d << std::endl; + std::cout << "shifted x: " << x << std::endl; const double l = boost::multiprecision::detail::do_cast(x); const double u = boost::multiprecision::detail::do_cast(x + 1); - if (verbose) { - std::cout << "l: " << l << std::endl; - std::cout << "u: " << u << std::endl; - } + std::cout << "l: " << l << std::endl; + std::cout << "u: " << u << std::endl; + return std::make_pair( std::make_pair(l, u), d ); } else { @@ -755,16 +902,15 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const double l = boost::multiprecision::detail::do_cast(x); const double u = l; - if (verbose) { - std::cout << "no shifting required " << std::endl; - std::cout << "l: " << l << std::endl; - std::cout << "u: " << u << std::endl; - } + std::cout << "no shifting required " << std::endl; + std::cout << "l: " << l << std::endl; + std::cout << "u: " << u << std::endl; + return std::make_pair( std::make_pair(l, u), 0 ); } } - std::pair get_interval_as_gmpzf( const bool verbose, Type& x ) const { + std::pair get_interval_as_gmpzf_work_in_progress( Type& x ) const { double l = 0.0, u = 0.0; if (x.num == 0) { // return [0.0, 0.0] @@ -788,8 +934,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(x.num > 0 && x.den > 0); Protect_FPU_rounding P(CGAL_FE_TONEAREST); - const auto n = get_interval_exp(verbose, x.num); - const auto d = get_interval_exp(verbose, x.den); + const auto n = get_interval_exp_work_in_progress(x.num); + const auto d = get_interval_exp_work_in_progress(x.den); // exit(EXIT_SUCCESS); @@ -801,26 +947,22 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const Interval_nt<> den(d.first); const Interval_nt<> div = num / den; - if (verbose) { - std::cout << std::endl; - std::cout << " --- debugging get_interval_as_gmpzf() --- " << std::endl; - std::cout << std::endl; + std::cout << std::endl; + std::cout << " --- debugging get_interval_as_gmpzf() --- " << std::endl; + std::cout << std::endl; - std::cout << "change sign: " << change_sign << std::endl; - std::cout << "interval nt num: " << num << std::endl; - std::cout << "interval nt den: " << den << std::endl; - std::cout << "interval nt div: " << div << std::endl; - } + std::cout << "change sign: " << change_sign << std::endl; + std::cout << "interval nt num: " << num << std::endl; + std::cout << "interval nt den: " << den << std::endl; + std::cout << "interval nt div: " << div << std::endl; const int e = static_cast(n.second - d.second); std::tie(l, u) = ldexp(div, e).pair(); - if (verbose) { - std::cout << "exp: " << e << std::endl; - std::cout << "ldexp l: " << l << std::endl; - std::cout << "ldexp u: " << u << std::endl; - std::cout << std::endl; - } + std::cout << "exp: " << e << std::endl; + std::cout << "ldexp l: " << l << std::endl; + std::cout << "ldexp u: " << u << std::endl; + std::cout << std::endl; if (change_sign) { const double t = l; @@ -828,16 +970,14 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > u = -t; } - if (verbose) { - std::cout << "l: " << l << std::endl; - std::cout << "u: " << u << std::endl; - } + std::cout << "l: " << l << std::endl; + std::cout << "u: " << u << std::endl; // exit(EXIT_SUCCESS); return std::make_pair(l, u); } - std::pair get_interval_as_boost( const bool verbose, Type& x ) const { + std::pair get_interval_as_boost_work_in_progress( Type& x ) const { double l = 0.0, u = 0.0; if (x.num == 0) { // return [0.0, 0.0] @@ -860,27 +1000,23 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } CGAL_assertion(x.num > 0 && x.den > 0); - if (verbose) { - std::cout << std::endl; - std::cout << " --- debugging get_interval_as_boost() --- " << std::endl; - std::cout << std::endl; + std::cout << std::endl; + std::cout << " --- debugging get_interval_as_boost() --- " << std::endl; + std::cout << std::endl; - std::cout << "change sign: " << change_sign << std::endl; - } + std::cout << "change sign: " << change_sign << std::endl; const int num_dbl_digits = std::numeric_limits::digits; const int shift = num_dbl_digits + (msb(x.den) - msb(x.num)); - if (verbose) { - std::cout << "num before shift: " << x.num << std::endl; - std::cout << "den before shift: " << x.den << std::endl; + std::cout << "num before shift: " << x.num << std::endl; + std::cout << "den before shift: " << x.den << std::endl; - std::cout << "digits : " << num_dbl_digits << std::endl; - std::cout << "diff1 : " << int(msb(x.den) - msb(x.num)) << std::endl; - std::cout << "num msb: " << int(msb(x.num)) << std::endl; - std::cout << "den msb: " << int(msb(x.den)) << std::endl; - std::cout << "shift : " << shift << std::endl; - } + std::cout << "digits : " << num_dbl_digits << std::endl; + std::cout << "diff1 : " << int(msb(x.den) - msb(x.num)) << std::endl; + std::cout << "num msb: " << int(msb(x.num)) << std::endl; + std::cout << "den msb: " << int(msb(x.den)) << std::endl; + std::cout << "shift : " << shift << std::endl; if (shift > 0) { x.num <<= shift; // that is multiply bu 2^shift @@ -889,14 +1025,12 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } CGAL_assertion(int(msb(x.den) - msb(x.num)) == -53); - if (verbose) { - std::cout << "diff2 : " << int(msb(x.den) - msb(x.num)) << std::endl; - std::cout << std::endl; + std::cout << "diff2 : " << int(msb(x.den) - msb(x.num)) << std::endl; + std::cout << std::endl; - std::cout << "num after shift: " << x.num << std::endl; - std::cout << "den after shift: " << x.den << std::endl; - std::cout << std::endl; - } + std::cout << "num after shift: " << x.num << std::endl; + std::cout << "den after shift: " << x.den << std::endl; + std::cout << std::endl; // exit(EXIT_SUCCESS); @@ -905,13 +1039,11 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > decltype(q) p = q; const int q_bits = msb(q); - if (verbose) { - std::cout << "q msb : " << q_bits << std::endl; - std::cout << "p before: " << p << std::endl; - std::cout << "q before: " << q << std::endl; - std::cout << "r before: " << r << std::endl; - std::cout << std::endl; - } + std::cout << "q msb : " << q_bits << std::endl; + std::cout << "p before: " << p << std::endl; + std::cout << "q before: " << q << std::endl; + std::cout << "r before: " << r << std::endl; + std::cout << std::endl; // exit(EXIT_SUCCESS); @@ -929,12 +1061,10 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } // otherwise we are already in the correct position - if (verbose) { - std::cout << "cmp: " << c << std::endl; - std::cout << "p after1: " << p << std::endl; - std::cout << "q after1: " << q << std::endl; - std::cout << "r after1: " << r << std::endl; - } + std::cout << "cmp: " << c << std::endl; + std::cout << "p after1: " << p << std::endl; + std::cout << "q after1: " << q << std::endl; + std::cout << "r after1: " << r << std::endl; } else { @@ -947,21 +1077,19 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } } - if (verbose) { - std::cout << "p after2: " << p << std::endl; - std::cout << "q after2: " << q << std::endl; - std::cout << "r after2: " << r << std::endl; - } + std::cout << "p after2: " << p << std::endl; + std::cout << "q after2: " << q << std::endl; + std::cout << "r after2: " << r << std::endl; } } // exit(EXIT_SUCCESS); l = boost::multiprecision::detail::do_cast(p); - if (verbose) std::cout << "do cast l: " << l << std::endl; + std::cout << "do cast l: " << l << std::endl; l = std::ldexp(l, -shift); // divide by 2^shift u = boost::multiprecision::detail::do_cast(q); - if (verbose) std::cout << "do cast u: " << u << std::endl; + std::cout << "do cast u: " << u << std::endl; u = std::ldexp(u, -shift); // divide by 2^shift if (change_sign) { @@ -970,10 +1098,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > u = -t; } - if (verbose) { - std::cout << "l: " << l << std::endl; - std::cout << "u: " << u << std::endl; - } + std::cout << "l: " << l << std::endl; + std::cout << "u: " << u << std::endl; // exit(EXIT_SUCCESS); return std::make_pair(l, u); @@ -994,15 +1120,25 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // 2. generic_interconvert.hpp - line 305. // TODO: Can we avoid this copying by getting x without const? + // TODO: Both versions do not fully work with NEF, leading to NEF assertions, + // however they both pass for REG and all test cases. Type xx = x; const bool verbose = false; // Seems to be less precise and we rarely end up with an interval [d,d] // even for numbers, which are exactly representable as double. - // return get_interval_as_gmpzf(verbose, xx); + // if (verbose) { + // return get_interval_as_gmpzf_work_in_progress(xx); + // } else { + // return get_interval_as_gmpzf(xx); + // } // Works slightly better than the first one. - return get_interval_as_boost(verbose, xx); + if (verbose) { + return get_interval_as_boost_work_in_progress(xx); + } else { + return get_interval_as_boost(xx); + } #endif From b6686591a8bdcf006258b47d6ea46f16d32dc3e3 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 27 Aug 2021 17:29:40 +0200 Subject: [PATCH 029/127] factoring out stable bounds --- Number_types/include/CGAL/Quotient.h | 80 +++++++++++++++------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index cbe256796163..304eb72073a4 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -1105,42 +1105,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > return std::make_pair(l, u); } - std::pair operator()( const Type& x ) const { - - // std::cout << "xx: " << x << std::endl; - // std::cout << "xn: " << x.num << std::endl; - // std::cout << "xd: " << x.den << std::endl; - - #if defined(CGAL_USE_CPP_INT) && true - - #if true // tight bounds optimized - - // Make tight and fast bounds for x here. - // 1. Gmpzf.h - line 156 and Gmpzf_type.h - line 412. - // 2. generic_interconvert.hpp - line 305. - - // TODO: Can we avoid this copying by getting x without const? - // TODO: Both versions do not fully work with NEF, leading to NEF assertions, - // however they both pass for REG and all test cases. - Type xx = x; - const bool verbose = false; - - // Seems to be less precise and we rarely end up with an interval [d,d] - // even for numbers, which are exactly representable as double. - // if (verbose) { - // return get_interval_as_gmpzf_work_in_progress(xx); - // } else { - // return get_interval_as_gmpzf(xx); - // } - - // Works slightly better than the first one. - if (verbose) { - return get_interval_as_boost_work_in_progress(xx); - } else { - return get_interval_as_boost(xx); - } - - #endif + std::pair get_interval_using_cpp_rational_stable( const Type& x ) const { // std::cout << "n: " << x.numerator() << std::endl; // std::cout << "d: " << x.denominator() << std::endl; @@ -1240,6 +1205,49 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > return std::make_pair(quot.inf(), quot.sup()); } + } + + std::pair operator()( const Type& x ) const { + + // std::cout << "xx: " << x << std::endl; + // std::cout << "xn: " << x.num << std::endl; + // std::cout << "xd: " << x.den << std::endl; + + #if defined(CGAL_USE_CPP_INT) && true + + #if false // tight bounds optimized + + // Make tight and fast bounds for x here. + // 1. Gmpzf.h - line 156 and Gmpzf_type.h - line 412. + // 2. generic_interconvert.hpp - line 305. + + // TODO: Can we avoid this copying by getting x without const? + // TODO: Both versions do not fully work with NEF, leading to NEF assertions, + // however they both pass for REG and all test cases. + Type xx = x; + const bool verbose = false; + + // Seems to be less precise and we rarely end up with an interval [d,d] + // even for numbers, which are exactly representable as double. + // if (verbose) { + // return get_interval_as_gmpzf_work_in_progress(xx); + // } else { + // return get_interval_as_gmpzf(xx); + // } + + // Works slightly better than the first one. + if (verbose) { + return get_interval_as_boost_work_in_progress(xx); + } else { + return get_interval_as_boost(xx); + } + + #else // cpp_rational based tight bounds + + // These are slower but stable bounds, pass all tests and benches. + return get_interval_using_cpp_rational_stable(x); + + #endif #else // master version From f2d4180dadd1f2159b334cebbd965c7e180a162f Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 27 Aug 2021 17:39:12 +0200 Subject: [PATCH 030/127] added more todo --- Number_types/include/CGAL/Quotient.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 304eb72073a4..21626e14d4ee 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -1227,6 +1227,9 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > Type xx = x; const bool verbose = false; + // TODO: compare both below with the stable cpp_rational-based implementation + // and see which configurations fail for NEF data. + // Seems to be less precise and we rarely end up with an interval [d,d] // even for numbers, which are exactly representable as double. // if (verbose) { From ba11c951a71f321c5d4420b103fd89b8bbf75d3f Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 27 Aug 2021 18:31:59 +0200 Subject: [PATCH 031/127] better boost version --- Number_types/include/CGAL/Quotient.h | 33 ++++++++-------------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 21626e14d4ee..ff164a73e2b3 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -820,26 +820,11 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const int q_bits = msb(q); if (r != 0) { - if (q_bits == num_dbl_digits - 1) { - - CGAL_assertion(r > 0); - r <<= 1; - const int c = r.compare(x.den); - if (c > 0) { - ++q; - } else if ((c == 0) && (q & 1u)) { - ++q; - } - + if (q_bits == num_dbl_digits + 1) { + q <<= 1; + ++q; } else { - - CGAL_assertion(r > 0); - CGAL_assertion(q_bits == num_dbl_digits); - if (q & 1u) { - if (r || (q & 2u)) { - ++q; - } - } + ++q; } } @@ -1225,22 +1210,22 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // TODO: Both versions do not fully work with NEF, leading to NEF assertions, // however they both pass for REG and all test cases. Type xx = x; - const bool verbose = false; + const bool work_in_progress = false; // TODO: compare both below with the stable cpp_rational-based implementation // and see which configurations fail for NEF data. // Seems to be less precise and we rarely end up with an interval [d,d] // even for numbers, which are exactly representable as double. - // if (verbose) { - // return get_interval_as_gmpzf_work_in_progress(xx); + // if (work_in_progress) { + // return get_interval_as_gmpzf_work_in_progress(xx); // might be non stable // } else { // return get_interval_as_gmpzf(xx); // } // Works slightly better than the first one. - if (verbose) { - return get_interval_as_boost_work_in_progress(xx); + if (work_in_progress) { + return get_interval_as_boost_work_in_progress(xx); // might be non stable } else { return get_interval_as_boost(xx); } From 0532efb3b659f24ecd7cf93343b170ec81d8561a Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 27 Aug 2021 18:40:15 +0200 Subject: [PATCH 032/127] even more better boost version --- Number_types/include/CGAL/Quotient.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index ff164a73e2b3..ee9947fa15ee 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -814,18 +814,21 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } CGAL_assertion(int(msb(x.den) - msb(x.num)) == -53); - decltype(x.num) q, r; + decltype(x.num) p, q, r; boost::multiprecision::divide_qr(x.num, x.den, q, r); - decltype(q) p = q; - const int q_bits = msb(q); if (r != 0) { + const int q_bits = msb(q); if (q_bits == num_dbl_digits + 1) { q <<= 1; + p = q; ++q; } else { + p = q; ++q; } + } else { + p = q; } l = boost::multiprecision::detail::do_cast(p); From 08c5d5a4adbc74df6d7f1dfbc3cbdacfb8eab309 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 6 Sep 2021 16:33:17 +0200 Subject: [PATCH 033/127] change settings --- Number_types/include/CGAL/Quotient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index ee9947fa15ee..280e17a91b36 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -1203,7 +1203,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > #if defined(CGAL_USE_CPP_INT) && true - #if false // tight bounds optimized + #if true // tight bounds optimized // Make tight and fast bounds for x here. // 1. Gmpzf.h - line 156 and Gmpzf_type.h - line 412. From ac4703580592550c24271f09b2d63f459a8ea4fd Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 7 Sep 2021 10:39:18 +0200 Subject: [PATCH 034/127] remove work in progress --- Number_types/include/CGAL/Quotient.h | 404 ++++----------------------- 1 file changed, 53 insertions(+), 351 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 280e17a91b36..c2a08795af0f 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -708,12 +708,6 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { public: - // =========================================================================== // - - // CURRENT VERSION - - // =========================================================================== // - std::pair< std::pair, long > get_interval_exp( NT& x ) const { CGAL_assertion(x >= 0); @@ -779,6 +773,12 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > l = -u; u = -t; } + + Type lb(l), ub(u); + CGAL_assertion(lb <= ub); + CGAL_assertion(lb <= x); + CGAL_assertion(ub >= x); + return std::make_pair(l, u); } @@ -836,351 +836,58 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > u = boost::multiprecision::detail::do_cast(q); u = std::ldexp(u, -shift); - if (change_sign) { - const double t = l; - l = -u; - u = -t; - } - return std::make_pair(l, u); - } - - // =========================================================================== // - - // WORK IN PROGRESS - - // =========================================================================== // - - std::pair< std::pair, long > get_interval_exp_work_in_progress( NT& x ) const { - - std::cout << std::endl; - std::cout << " --- debugging get_interval_exp() --- " << std::endl; - std::cout << std::endl; - - std::cout << "x: " << x << std::endl; - - // Get surrounding interval of the form [l*2^k, u*2^k] - // first get mantissa in the form l*2^k, with 0.5 <= d < 1; - // truncation is guaranteed to go towards zero. - - CGAL_assertion(x >= 0); - const unsigned n = msb(x); - std::cout << "msb before shift: " << msb(x) << std::endl; - - const unsigned num_dbl_digits = std::numeric_limits::digits; - if (n > num_dbl_digits) { - - const unsigned d = n - num_dbl_digits; - x = x >> d; - - std::cout << "shifting.... " << std::endl; - std::cout << "msb after shift: " << msb(x) << std::endl; - std::cout << "shift difference: " << d << std::endl; - std::cout << "shifted x: " << x << std::endl; - - const double l = boost::multiprecision::detail::do_cast(x); - const double u = boost::multiprecision::detail::do_cast(x + 1); - - std::cout << "l: " << l << std::endl; - std::cout << "u: " << u << std::endl; - - return std::make_pair( std::make_pair(l, u), d ); - - } else { - - const double l = boost::multiprecision::detail::do_cast(x); - const double u = l; - - std::cout << "no shifting required " << std::endl; - std::cout << "l: " << l << std::endl; - std::cout << "u: " << u << std::endl; - - return std::make_pair( std::make_pair(l, u), 0 ); - } - } - - std::pair get_interval_as_gmpzf_work_in_progress( Type& x ) const { - - double l = 0.0, u = 0.0; - if (x.num == 0) { // return [0.0, 0.0] - return std::make_pair(l, u); - } - CGAL_assertion(x.num != 0); - CGAL_assertion(x.den != 0); - - // Handle signs. - bool change_sign = false; - if (x.num < 0 && x.den < 0) { - x.num = -x.num; - x.den = -x.den; - } else if (x.num < 0 && x.den > 0) { - change_sign = true; - x.num = -x.num; - } else if (x.num > 0 && x.den < 0) { - change_sign = true; - x.den = -x.den; - } - CGAL_assertion(x.num > 0 && x.den > 0); - - Protect_FPU_rounding P(CGAL_FE_TONEAREST); - const auto n = get_interval_exp_work_in_progress(x.num); - const auto d = get_interval_exp_work_in_progress(x.den); - - // exit(EXIT_SUCCESS); - - CGAL_assertion_msg( - CGAL::abs(double(n.second) - double(d.second)) < (1<<30)*2.0, - "Exponent overflow in Quotient to_interval()!"); - - const Interval_nt<> num(n.first); - const Interval_nt<> den(d.first); - const Interval_nt<> div = num / den; - - std::cout << std::endl; - std::cout << " --- debugging get_interval_as_gmpzf() --- " << std::endl; - std::cout << std::endl; - - std::cout << "change sign: " << change_sign << std::endl; - std::cout << "interval nt num: " << num << std::endl; - std::cout << "interval nt den: " << den << std::endl; - std::cout << "interval nt div: " << div << std::endl; - - const int e = static_cast(n.second - d.second); - std::tie(l, u) = ldexp(div, e).pair(); - - std::cout << "exp: " << e << std::endl; - std::cout << "ldexp l: " << l << std::endl; - std::cout << "ldexp u: " << u << std::endl; - std::cout << std::endl; - if (change_sign) { const double t = l; l = -u; u = -t; } - std::cout << "l: " << l << std::endl; - std::cout << "u: " << u << std::endl; + Type lb(l), ub(u); + CGAL_assertion(lb <= ub); + CGAL_assertion(lb <= x); + CGAL_assertion(ub >= x); - // exit(EXIT_SUCCESS); return std::make_pair(l, u); } - std::pair get_interval_as_boost_work_in_progress( Type& x ) const { - - double l = 0.0, u = 0.0; - if (x.num == 0) { // return [0.0, 0.0] - return std::make_pair(l, u); - } - CGAL_assertion(x.num != 0); - CGAL_assertion(x.den != 0); - - // Handle signs. - bool change_sign = false; - if (x.num < 0 && x.den < 0) { - x.num = -x.num; - x.den = -x.den; - } else if (x.num < 0 && x.den > 0) { - change_sign = true; - x.num = -x.num; - } else if (x.num > 0 && x.den < 0) { - change_sign = true; - x.den = -x.den; - } - CGAL_assertion(x.num > 0 && x.den > 0); - - std::cout << std::endl; - std::cout << " --- debugging get_interval_as_boost() --- " << std::endl; - std::cout << std::endl; - - std::cout << "change sign: " << change_sign << std::endl; - - const int num_dbl_digits = std::numeric_limits::digits; - const int shift = num_dbl_digits + (msb(x.den) - msb(x.num)); - - std::cout << "num before shift: " << x.num << std::endl; - std::cout << "den before shift: " << x.den << std::endl; - - std::cout << "digits : " << num_dbl_digits << std::endl; - std::cout << "diff1 : " << int(msb(x.den) - msb(x.num)) << std::endl; - std::cout << "num msb: " << int(msb(x.num)) << std::endl; - std::cout << "den msb: " << int(msb(x.den)) << std::endl; - std::cout << "shift : " << shift << std::endl; - - if (shift > 0) { - x.num <<= shift; // that is multiply bu 2^shift - } else if (shift < 0) { - x.den <<= boost::multiprecision::detail::unsigned_abs(shift); - } - CGAL_assertion(int(msb(x.den) - msb(x.num)) == -53); + std::pair get_interval_using_cpp_rational( const Type& x ) const { - std::cout << "diff2 : " << int(msb(x.den) - msb(x.num)) << std::endl; - std::cout << std::endl; - - std::cout << "num after shift: " << x.num << std::endl; - std::cout << "den after shift: " << x.den << std::endl; - std::cout << std::endl; - - // exit(EXIT_SUCCESS); - - decltype(x.num) q, r; - boost::multiprecision::divide_qr(x.num, x.den, q, r); - decltype(q) p = q; - const int q_bits = msb(q); - - std::cout << "q msb : " << q_bits << std::endl; - std::cout << "p before: " << p << std::endl; - std::cout << "q before: " << q << std::endl; - std::cout << "r before: " << r << std::endl; - std::cout << std::endl; - - // exit(EXIT_SUCCESS); - - if (r != 0) { - if (q_bits == num_dbl_digits - 1) { - - CGAL_assertion(r > 0); - // Round up if 2 * r > x.den: - r <<= 1; // multiply r by 2 - const int c = r.compare(x.den); - if (c > 0) { // we are in the second half of the interval between two doubles - ++q; - } else if ((c == 0) && (q & 1u)) { - ++q; - } - // otherwise we are already in the correct position - - std::cout << "cmp: " << c << std::endl; - std::cout << "p after1: " << p << std::endl; - std::cout << "q after1: " << q << std::endl; - std::cout << "r after1: " << r << std::endl; + const double inf = std::numeric_limits::infinity(); + const double xn = x.num.template convert_to(); + const double xd = x.den.template convert_to(); + if (xn == inf || xd == inf) { + // TODO: Is it fast enough? Seems so because this conversion happens + // only a few times during the run, at least for NEF. + boost::multiprecision::cpp_rational rat; + CGAL_assertion(x.den != 0); + if (x.den < 0) { + rat = boost::multiprecision::cpp_rational(-x.num, -x.den); } else { - - CGAL_assertion(r > 0); - CGAL_assertion(q_bits == num_dbl_digits); - // We basically already have the rounding info: - if (q & 1u) { - if (r || (q & 2u)) { - ++q; - } - } - - std::cout << "p after2: " << p << std::endl; - std::cout << "q after2: " << q << std::endl; - std::cout << "r after2: " << r << std::endl; + rat = boost::multiprecision::cpp_rational( x.num, x.den); } - } - - // exit(EXIT_SUCCESS); - l = boost::multiprecision::detail::do_cast(p); - std::cout << "do cast l: " << l << std::endl; - l = std::ldexp(l, -shift); // divide by 2^shift - u = boost::multiprecision::detail::do_cast(q); - std::cout << "do cast u: " << u << std::endl; - u = std::ldexp(u, -shift); // divide by 2^shift + double i = static_cast(rat); + double s = i; - if (change_sign) { - const double t = l; - l = -u; - u = -t; - } - - std::cout << "l: " << l << std::endl; - std::cout << "u: " << u << std::endl; - - // exit(EXIT_SUCCESS); - return std::make_pair(l, u); - } + const double inf = std::numeric_limits::infinity(); + CGAL_assertion(i != inf && s != inf); + const int cmp = rat.compare(i); + if (cmp > 0) { + s = nextafter(s, +inf); + CGAL_assertion(rat.compare(s) < 0); + } + else if (cmp < 0) { + i = nextafter(i, -inf); + CGAL_assertion(rat.compare(i) > 0); + } - std::pair get_interval_using_cpp_rational_stable( const Type& x ) const { + Type lb(i), ub(s); + CGAL_assertion(lb <= ub); + CGAL_assertion(lb <= x); + CGAL_assertion(ub >= x); - // std::cout << "n: " << x.numerator() << std::endl; - // std::cout << "d: " << x.denominator() << std::endl; - - const double inf = std::numeric_limits::infinity(); - const double xn = x.num.template convert_to(); - const double xd = x.den.template convert_to(); - if (xn == inf || xd == inf) { - - // decltype(x.num) q, r; - // boost::multiprecision::divide_qr(x.num, x.den, q, r); - - // std::cout << "type: " << boost::typeindex::type_id() << std::endl; - - // std::cout << "x num: " << x.num << std::endl; - // std::cout << "x den: " << x.den << std::endl; - - // std::cout << "q: " << q << std::endl; - // std::cout << "r: " << r << std::endl; - - #if false // rough bounds - - // We do not have here a tight bound! - // TODO: Use a binary search or limbs to find a tighter bound! - // For REG tests this assertion fails! - // Are they real bounds? When q = 0, we can be arbitrarily far away - // from the lower and upper bound. - CGAL_assertion(CGAL::abs(x.num) < CGAL::abs(x.den)); - if (x.num > 0 && x.den > 0) { - return std::make_pair( 0.0, 1.0); - } else if (x.num < 0 && x.den < 0) { - return std::make_pair( 0.0, 1.0); - } else { - return std::make_pair(-1.0, 0.0); - } - - #else // tight bounds using cpp_rational - - // TODO: Is it fast enough? Seems so because this conversion happens - // only a few times during the run, at least for NEF. - boost::multiprecision::cpp_rational rat; - CGAL_assertion(x.den != 0); - if (x.den < 0) { // we do it due to the bug in boost - rat = boost::multiprecision::cpp_rational(-x.num, -x.den); - } else { - rat = boost::multiprecision::cpp_rational( x.num, x.den); - } - - double i = static_cast(rat); - // double i; - // decltype(x) xx = x; - // const std::integral_constant tag; - // boost::multiprecision::detail::generic_convert_rational_to_float_imp(i, xx.num, xx.den, tag); - double s = i; - - const double inf = std::numeric_limits::infinity(); - CGAL_assertion(i != inf && s != inf); - const int cmp = rat.compare(i); - if (cmp > 0) { - s = nextafter(s, +inf); - CGAL_assertion(rat.compare(s) < 0); - } - else if (cmp < 0) { - i = nextafter(i, -inf); - CGAL_assertion(rat.compare(i) > 0); - } - - // std::cout << "new inf1: " << i << std::endl; - // std::cout << "new sup1: " << s << std::endl; - - return std::make_pair(i, s); - - #endif - - // Interval_nt<> quot = - // Interval_nt<>(CGAL_NTS to_interval(q)) + - // Interval_nt<>(CGAL_NTS to_interval(Type(r, x.den))); - - // Interval_nt<> quot = - // Interval_nt<>(CGAL_NTS to_interval(q)) + - // Interval_nt<>(CGAL_NTS to_interval(r)) / - // Interval_nt<>(CGAL_NTS to_interval(x.den)); - - // std::cout << "new inf1: " << quot.inf() << std::endl; - // std::cout << "new sup1: " << quot.sup() << std::endl; - - // return std::make_pair(quot.inf(), quot.sup()); + return std::make_pair(i, s); } else { @@ -1188,8 +895,10 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > Interval_nt<>(CGAL_NTS to_interval(x.num)) / Interval_nt<>(CGAL_NTS to_interval(x.den)); - // std::cout << "new inf2: " << quot.inf() << std::endl; - // std::cout << "new sup2: " << quot.sup() << std::endl; + Type lb(quot.inf()), ub(quot.sup()); + CGAL_assertion(lb <= ub); + CGAL_assertion(lb <= x); + CGAL_assertion(ub >= x); return std::make_pair(quot.inf(), quot.sup()); } @@ -1197,10 +906,6 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > std::pair operator()( const Type& x ) const { - // std::cout << "xx: " << x << std::endl; - // std::cout << "xn: " << x.num << std::endl; - // std::cout << "xd: " << x.den << std::endl; - #if defined(CGAL_USE_CPP_INT) && true #if true // tight bounds optimized @@ -1213,30 +918,21 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // TODO: Both versions do not fully work with NEF, leading to NEF assertions, // however they both pass for REG and all test cases. Type xx = x; - const bool work_in_progress = false; // TODO: compare both below with the stable cpp_rational-based implementation // and see which configurations fail for NEF data. // Seems to be less precise and we rarely end up with an interval [d,d] // even for numbers, which are exactly representable as double. - // if (work_in_progress) { - // return get_interval_as_gmpzf_work_in_progress(xx); // might be non stable - // } else { - // return get_interval_as_gmpzf(xx); - // } + // return get_interval_as_gmpzf(xx); // Works slightly better than the first one. - if (work_in_progress) { - return get_interval_as_boost_work_in_progress(xx); // might be non stable - } else { - return get_interval_as_boost(xx); - } + return get_interval_as_boost(xx); #else // cpp_rational based tight bounds // These are slower but stable bounds, pass all tests and benches. - return get_interval_using_cpp_rational_stable(x); + return get_interval_using_cpp_rational(x); #endif @@ -1245,6 +941,12 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const Interval_nt<> quot = Interval_nt<>(CGAL_NTS to_interval(x.numerator())) / Interval_nt<>(CGAL_NTS to_interval(x.denominator())); + + Type lb(quot.inf()), ub(quot.sup()); + CGAL_assertion(lb <= ub); + CGAL_assertion(lb <= x); + CGAL_assertion(ub >= x); + return std::make_pair(quot.inf(), quot.sup()); #endif From c78bc98e764d95ed5219be3986189fe78a61632f Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 7 Sep 2021 16:33:42 +0200 Subject: [PATCH 035/127] more comments in boost implementation --- Number_types/include/CGAL/Quotient.h | 96 +++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 8 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index c2a08795af0f..fff46a53057b 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -782,10 +782,33 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > return std::make_pair(l, u); } + // TODO: The main question: does this implementation returns p and q, which + // are exactly representable on the double grid or we should still apply nextafter + // in order to get it and set correct rounding mode before calling do_cast? + // Now, it seems like our l and u are simply closest doubles rather than points + // on the double grid. std::pair get_interval_as_boost( Type& x ) const { + const Type input = x; + std::cout << "input: " << input << std::endl; + double l = 0.0, u = 0.0; if (x.num == 0) { // return [0.0, 0.0] + + Type lb(l), ub(u); + + std::cout << "x: " << x << std::endl; + std::cout << "l: " << l << std::endl; + std::cout << "u: " << u << std::endl; + + std::cout << "lb: " << lb << std::endl; + std::cout << "ub: " << ub << std::endl; + std::cout << std::endl; + + CGAL_assertion(lb <= ub); + CGAL_assertion(lb <= input); + CGAL_assertion(ub >= input); + return std::make_pair(l, u); } CGAL_assertion(x.num != 0); @@ -806,29 +829,48 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(x.num > 0 && x.den > 0); const int num_dbl_digits = std::numeric_limits::digits; - const int shift = num_dbl_digits + (msb(x.den) - msb(x.num)); + const int shift = num_dbl_digits + msb(x.den) - msb(x.num); if (shift > 0) { + std::cout << "num shift" << std::endl; x.num <<= shift; } else if (shift < 0) { + std::cout << "den shift" << std::endl; x.den <<= boost::multiprecision::detail::unsigned_abs(shift); } CGAL_assertion(int(msb(x.den) - msb(x.num)) == -53); decltype(x.num) p, q, r; + std::cout << "x: " << x << std::endl; boost::multiprecision::divide_qr(x.num, x.den, q, r); + std::cout << "q before: " << q << std::endl; + std::cout << "r before: " << r << std::endl; + + const int q_bits = msb(q); + std::cout << "q bits: " << q_bits << std::endl; + std::cout << "q digs: " << num_dbl_digits << std::endl; + if (r != 0) { - const int q_bits = msb(q); if (q_bits == num_dbl_digits + 1) { - q <<= 1; + std::cout << "case1" << std::endl; + // TODO: Should we add this shift to ldexp later? Probably not. + q <<= 1; // TODO: Is it left of right shift? p = q; ++q; } else { + std::cout << "case2" << std::endl; p = q; ++q; } } else { - p = q; + if (q_bits == num_dbl_digits + 1) { + std::cout << "case3" << std::endl; + q <<= 1; // TODO: Is it left of right shift? + p = q; + } else { + std::cout << "case4" << std::endl; + p = q; + } } l = boost::multiprecision::detail::do_cast(p); @@ -842,16 +884,28 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > u = -t; } - Type lb(l), ub(u); + Type lb(l); + Type ub(u); + + std::cout << "x: " << x << std::endl; + std::cout << "l: " << l << std::endl; + std::cout << "u: " << u << std::endl; + + std::cout << "lb: " << lb << std::endl; + std::cout << "ub: " << ub << std::endl; + std::cout << std::endl; + CGAL_assertion(lb <= ub); - CGAL_assertion(lb <= x); - CGAL_assertion(ub >= x); + CGAL_assertion(lb <= input); + CGAL_assertion(ub >= input); return std::make_pair(l, u); } std::pair get_interval_using_cpp_rational( const Type& x ) const { + std::cout << "input: " << x << std::endl; + const double inf = std::numeric_limits::infinity(); const double xn = x.num.template convert_to(); const double xd = x.den.template convert_to(); @@ -883,6 +937,16 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } Type lb(i), ub(s); + + std::cout << "inf case" << std::endl; + std::cout << "x: " << x << std::endl; + std::cout << "l: " << i << std::endl; + std::cout << "u: " << s << std::endl; + + std::cout << "lb: " << lb << std::endl; + std::cout << "ub: " << ub << std::endl; + std::cout << std::endl; + CGAL_assertion(lb <= ub); CGAL_assertion(lb <= x); CGAL_assertion(ub >= x); @@ -895,7 +959,18 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > Interval_nt<>(CGAL_NTS to_interval(x.num)) / Interval_nt<>(CGAL_NTS to_interval(x.den)); - Type lb(quot.inf()), ub(quot.sup()); + Type lb(quot.inf()); + Type ub(quot.sup()); + + std::cout << "std case" << std::endl; + std::cout << "x: " << x << std::endl; + std::cout << "l: " << quot.inf() << std::endl; + std::cout << "u: " << quot.sup() << std::endl; + + std::cout << "lb: " << lb << std::endl; + std::cout << "ub: " << ub << std::endl; + std::cout << std::endl; + CGAL_assertion(lb <= ub); CGAL_assertion(lb <= x); CGAL_assertion(ub >= x); @@ -947,6 +1022,11 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(lb <= x); CGAL_assertion(ub >= x); + // std::cout << "x: " << x << std::endl; + // std::cout << "l: " << quot.inf() << std::endl; + // std::cout << "u: " << quot.sup() << std::endl; + // std::cout << std::endl; + return std::make_pair(quot.inf(), quot.sup()); #endif From 900c68828d1a9af89496af8dd2438952067b52f1 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 7 Sep 2021 18:08:22 +0200 Subject: [PATCH 036/127] some small improvements --- Number_types/include/CGAL/Quotient.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index fff46a53057b..a6486f949db7 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -754,8 +754,20 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(x.num > 0 && x.den > 0); Protect_FPU_rounding P(CGAL_FE_TONEAREST); - const auto n = get_interval_exp(x.num); - const auto d = get_interval_exp(x.den); + auto n = get_interval_exp(x.num); + auto d = get_interval_exp(x.den); + + const int e = static_cast(n.second - d.second); + if (CGAL::abs(double(n.second) - double(d.second)) >= (1<<30)*2.0) { + CGAL_assertion_msg(false, "TODO: Check this case!"); + if (e < 0) { + n.second = INT_MIN; + d.second = INT_MAX; + } else if (e > 0) { + n.second = INT_MAX; + d.second = INT_MIN; + } + } CGAL_assertion_msg( CGAL::abs(double(n.second) - double(d.second)) < (1<<30)*2.0, @@ -764,8 +776,6 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const Interval_nt<> num(n.first); const Interval_nt<> den(d.first); const Interval_nt<> div = num / den; - - const int e = static_cast(n.second - d.second); std::tie(l, u) = ldexp(div, e).pair(); if (change_sign) { From f3e1b996cb14ad6b9c78b580d471e3ebc04614b8 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 8 Sep 2021 17:10:54 +0200 Subject: [PATCH 037/127] updated version of to_interval --- Number_types/include/CGAL/Quotient.h | 132 ++++++++++++++++++--------- 1 file changed, 90 insertions(+), 42 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index a6486f949db7..ccde557fa21c 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -800,20 +800,22 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > std::pair get_interval_as_boost( Type& x ) const { const Type input = x; - std::cout << "input: " << input << std::endl; + // std::cout << "input: " << input << std::endl; double l = 0.0, u = 0.0; if (x.num == 0) { // return [0.0, 0.0] Type lb(l), ub(u); - std::cout << "x: " << x << std::endl; - std::cout << "l: " << l << std::endl; - std::cout << "u: " << u << std::endl; + // std::cout << "x: " << x << std::endl; + // std::cout << "l: " << l << std::endl; + // std::cout << "u: " << u << std::endl; - std::cout << "lb: " << lb << std::endl; - std::cout << "ub: " << ub << std::endl; - std::cout << std::endl; + // std::cout << "lb: " << lb << std::endl; + // std::cout << "ub: " << ub << std::endl; + + // std::cout << "EARLY QUIT" << std::endl; + // std::cout << std::endl; CGAL_assertion(lb <= ub); CGAL_assertion(lb <= input); @@ -838,54 +840,100 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } CGAL_assertion(x.num > 0 && x.den > 0); - const int num_dbl_digits = std::numeric_limits::digits; - const int shift = num_dbl_digits + msb(x.den) - msb(x.num); + const int num_dbl_digits = std::numeric_limits::digits - 1; + const int msb_diff = int(msb(x.num) - msb(x.den)); + int shift = num_dbl_digits - msb_diff; + + // std::cout << "digs: " << num_dbl_digits << std::endl; + // std::cout << "diff: " << msb_diff << std::endl; + + // if (shift == 0) { + // CGAL_assertion_msg(false, "TODO: ZERO SHIFT!"); + // } + // std::cout << "shift: " << shift << std::endl; + if (shift > 0) { - std::cout << "num shift" << std::endl; + CGAL_assertion(msb_diff < num_dbl_digits); + // std::cout << "num shift: " << shift << std::endl; x.num <<= shift; + // CGAL_assertion_msg(false, "TODO: NUMERATOR CASE!"); } else if (shift < 0) { - std::cout << "den shift" << std::endl; + CGAL_assertion(msb_diff > num_dbl_digits); + // std::cout << "den shift: " << shift << std::endl; x.den <<= boost::multiprecision::detail::unsigned_abs(shift); + // CGAL_assertion_msg(false, "TODO: DENOMINATOR CASE!"); } - CGAL_assertion(int(msb(x.den) - msb(x.num)) == -53); + CGAL_assertion(int(msb(x.num) - msb(x.den)) == num_dbl_digits); decltype(x.num) p, q, r; - std::cout << "x: " << x << std::endl; + // std::cout << "x: " << x << std::endl; boost::multiprecision::divide_qr(x.num, x.den, q, r); - std::cout << "q before: " << q << std::endl; - std::cout << "r before: " << r << std::endl; + // std::vector v; + // export_bits(q, std::back_inserter(v), 1); + // std::cout << "binary: "; + // for (const unsigned char bit : v) { + // std::cout << static_cast(bit); + // } + // std::cout << std::endl; + + // std::cout << "q before: " << q << std::endl; + // std::cout << "r before: " << r << std::endl; const int q_bits = msb(q); - std::cout << "q bits: " << q_bits << std::endl; - std::cout << "q digs: " << num_dbl_digits << std::endl; - - if (r != 0) { - if (q_bits == num_dbl_digits + 1) { - std::cout << "case1" << std::endl; - // TODO: Should we add this shift to ldexp later? Probably not. - q <<= 1; // TODO: Is it left of right shift? - p = q; - ++q; - } else { - std::cout << "case2" << std::endl; - p = q; - ++q; - } + // std::cout << "n bits: " << int(msb(x.num)) << std::endl; + // std::cout << "d bits: " << int(msb(x.den)) << std::endl; + // std::cout << "q bits: " << q_bits << std::endl; + // std::cout << "q digs: " << num_dbl_digits << std::endl; + + if (q_bits == num_dbl_digits - 1) { + + // It seems to be identical to CASE-2. + // std::cout << "CASE-1-3" << std::endl; + CGAL_assertion(r != 0); + p = q; + ++q; + + // q >>= 1; + // p = q; + // ++q; + // --shift; + + // r <<= 1; p = q; + // const int cmp = r.compare(x.den); + // if (cmp > 0) { + // std::cout << "subcase 1" << std::endl; + // ++q; + // } else if ((cmp == 0) && (q & 1u)) { + // std::cout << "subcase 2" << std::endl; + // ++q; + // } else { + // std::cout << "subcase 3" << std::endl; + // } + + // CGAL_assertion_msg(false, "TODO: CASE-13!"); + } else { - if (q_bits == num_dbl_digits + 1) { - std::cout << "case3" << std::endl; - q <<= 1; // TODO: Is it left of right shift? + + CGAL_assertion(q_bits == num_dbl_digits); + if (r != 0) { + // std::cout << "CASE-2" << std::endl; p = q; + ++q; + // CGAL_assertion_msg(false, "TODO: CASE-2!"); } else { - std::cout << "case4" << std::endl; + // std::cout << "CASE-4" << std::endl; p = q; + // CGAL_assertion_msg(false, "TODO: CASE-4!"); } } - l = boost::multiprecision::detail::do_cast(p); + // std::cout << "p: " << p << std::endl; + // std::cout << "q: " << q << std::endl; + + l = static_cast(p); l = std::ldexp(l, -shift); - u = boost::multiprecision::detail::do_cast(q); + u = static_cast(q); u = std::ldexp(u, -shift); if (change_sign) { @@ -897,13 +945,13 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > Type lb(l); Type ub(u); - std::cout << "x: " << x << std::endl; - std::cout << "l: " << l << std::endl; - std::cout << "u: " << u << std::endl; + // std::cout << "x: " << x << std::endl; + // std::cout << "l: " << l << std::endl; + // std::cout << "u: " << u << std::endl; - std::cout << "lb: " << lb << std::endl; - std::cout << "ub: " << ub << std::endl; - std::cout << std::endl; + // std::cout << "lb: " << lb << std::endl; + // std::cout << "ub: " << ub << std::endl; + // std::cout << std::endl; CGAL_assertion(lb <= ub); CGAL_assertion(lb <= input); From dfa098504a6c0b242e5d14db9074ff4df646049a Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 9 Sep 2021 12:09:45 +0200 Subject: [PATCH 038/127] fixed both boost and gmpzf implementation --- Number_types/include/CGAL/Quotient.h | 250 ++++++--------------------- 1 file changed, 56 insertions(+), 194 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index ccde557fa21c..baede3c523a5 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -712,7 +712,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(x >= 0); const unsigned n = msb(x); - const unsigned num_dbl_digits = std::numeric_limits::digits; + const unsigned num_dbl_digits = std::numeric_limits::digits - 1; if (n > num_dbl_digits) { const unsigned d = n - num_dbl_digits; @@ -730,8 +730,9 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } } - std::pair get_interval_as_gmpzf( Type& x ) const { + std::pair get_interval_as_gmpzf( const Type& input ) const { + Type x = input; double l = 0.0, u = 0.0; if (x.num == 0) { // return [0.0, 0.0] return std::make_pair(l, u); @@ -753,74 +754,60 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } CGAL_assertion(x.num > 0 && x.den > 0); - Protect_FPU_rounding P(CGAL_FE_TONEAREST); auto n = get_interval_exp(x.num); auto d = get_interval_exp(x.den); - const int e = static_cast(n.second - d.second); - if (CGAL::abs(double(n.second) - double(d.second)) >= (1<<30)*2.0) { - CGAL_assertion_msg(false, "TODO: Check this case!"); - if (e < 0) { - n.second = INT_MIN; - d.second = INT_MAX; - } else if (e > 0) { - n.second = INT_MAX; - d.second = INT_MIN; - } - } - - CGAL_assertion_msg( - CGAL::abs(double(n.second) - double(d.second)) < (1<<30)*2.0, - "Exponent overflow in Quotient to_interval()!"); - const Interval_nt<> num(n.first); const Interval_nt<> den(d.first); const Interval_nt<> div = num / den; + const int e = static_cast(n.second - d.second); std::tie(l, u) = ldexp(div, e).pair(); + if (u == 0.0) { + u = std::numeric_limits::min(); + CGAL_assertion(l == 0.0); + } + if (change_sign) { const double t = l; l = -u; u = -t; } - Type lb(l), ub(u); + if (l == std::numeric_limits::infinity()) { + l = std::numeric_limits::max(); + CGAL_assertion(u == std::numeric_limits::infinity()); + } else if (u == -std::numeric_limits::infinity()) { + u = std::numeric_limits::lowest(); + CGAL_assertion(l == -std::numeric_limits::infinity()); + } + CGAL_assertion(are_correct_bounds(l, u, input)); + return std::make_pair(l, u); + } + + bool are_correct_bounds( const double l, const double u, const Type& x ) const { + + if ( + CGAL::abs(l) == std::numeric_limits::infinity() || + CGAL::abs(u) == std::numeric_limits::infinity()) { + return true; + } + CGAL_assertion(CGAL::abs(l) != std::numeric_limits::infinity()); + CGAL_assertion(CGAL::abs(u) != std::numeric_limits::infinity()); + + const Type lb(l), ub(u); CGAL_assertion(lb <= ub); CGAL_assertion(lb <= x); CGAL_assertion(ub >= x); - - return std::make_pair(l, u); + return lb <= ub && lb <= x && ub >= x; } - // TODO: The main question: does this implementation returns p and q, which - // are exactly representable on the double grid or we should still apply nextafter - // in order to get it and set correct rounding mode before calling do_cast? - // Now, it seems like our l and u are simply closest doubles rather than points - // on the double grid. - std::pair get_interval_as_boost( Type& x ) const { - - const Type input = x; - // std::cout << "input: " << input << std::endl; + std::pair get_interval_as_boost( const Type& input ) const { + Type x = input; // TODO: Can we avoid this copying? double l = 0.0, u = 0.0; if (x.num == 0) { // return [0.0, 0.0] - - Type lb(l), ub(u); - - // std::cout << "x: " << x << std::endl; - // std::cout << "l: " << l << std::endl; - // std::cout << "u: " << u << std::endl; - - // std::cout << "lb: " << lb << std::endl; - // std::cout << "ub: " << ub << std::endl; - - // std::cout << "EARLY QUIT" << std::endl; - // std::cout << std::endl; - - CGAL_assertion(lb <= ub); - CGAL_assertion(lb <= input); - CGAL_assertion(ub >= input); - + CGAL_assertion(are_correct_bounds(l, u, input)); return std::make_pair(l, u); } CGAL_assertion(x.num != 0); @@ -842,134 +829,64 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const int num_dbl_digits = std::numeric_limits::digits - 1; const int msb_diff = int(msb(x.num) - msb(x.den)); - int shift = num_dbl_digits - msb_diff; - - // std::cout << "digs: " << num_dbl_digits << std::endl; - // std::cout << "diff: " << msb_diff << std::endl; - - // if (shift == 0) { - // CGAL_assertion_msg(false, "TODO: ZERO SHIFT!"); - // } - // std::cout << "shift: " << shift << std::endl; + const int shift = num_dbl_digits - msb_diff; if (shift > 0) { CGAL_assertion(msb_diff < num_dbl_digits); - // std::cout << "num shift: " << shift << std::endl; x.num <<= shift; - // CGAL_assertion_msg(false, "TODO: NUMERATOR CASE!"); } else if (shift < 0) { CGAL_assertion(msb_diff > num_dbl_digits); - // std::cout << "den shift: " << shift << std::endl; x.den <<= boost::multiprecision::detail::unsigned_abs(shift); - // CGAL_assertion_msg(false, "TODO: DENOMINATOR CASE!"); } CGAL_assertion(int(msb(x.num) - msb(x.den)) == num_dbl_digits); decltype(x.num) p, q, r; - // std::cout << "x: " << x << std::endl; boost::multiprecision::divide_qr(x.num, x.den, q, r); - - // std::vector v; - // export_bits(q, std::back_inserter(v), 1); - // std::cout << "binary: "; - // for (const unsigned char bit : v) { - // std::cout << static_cast(bit); - // } - // std::cout << std::endl; - - // std::cout << "q before: " << q << std::endl; - // std::cout << "r before: " << r << std::endl; - const int q_bits = msb(q); - // std::cout << "n bits: " << int(msb(x.num)) << std::endl; - // std::cout << "d bits: " << int(msb(x.den)) << std::endl; - // std::cout << "q bits: " << q_bits << std::endl; - // std::cout << "q digs: " << num_dbl_digits << std::endl; - if (q_bits == num_dbl_digits - 1) { - - // It seems to be identical to CASE-2. - // std::cout << "CASE-1-3" << std::endl; - CGAL_assertion(r != 0); + CGAL_assertion(q_bits == num_dbl_digits || r != 0); + if (r != 0) { p = q; ++q; - - // q >>= 1; - // p = q; - // ++q; - // --shift; - - // r <<= 1; p = q; - // const int cmp = r.compare(x.den); - // if (cmp > 0) { - // std::cout << "subcase 1" << std::endl; - // ++q; - // } else if ((cmp == 0) && (q & 1u)) { - // std::cout << "subcase 2" << std::endl; - // ++q; - // } else { - // std::cout << "subcase 3" << std::endl; - // } - - // CGAL_assertion_msg(false, "TODO: CASE-13!"); - } else { - - CGAL_assertion(q_bits == num_dbl_digits); - if (r != 0) { - // std::cout << "CASE-2" << std::endl; - p = q; - ++q; - // CGAL_assertion_msg(false, "TODO: CASE-2!"); - } else { - // std::cout << "CASE-4" << std::endl; - p = q; - // CGAL_assertion_msg(false, "TODO: CASE-4!"); - } + p = q; } - // std::cout << "p: " << p << std::endl; - // std::cout << "q: " << q << std::endl; - l = static_cast(p); l = std::ldexp(l, -shift); u = static_cast(q); u = std::ldexp(u, -shift); + if (u == 0.0) { + u = std::numeric_limits::min(); + CGAL_assertion(l == 0.0); + } + if (change_sign) { const double t = l; l = -u; u = -t; } - Type lb(l); - Type ub(u); - - // std::cout << "x: " << x << std::endl; - // std::cout << "l: " << l << std::endl; - // std::cout << "u: " << u << std::endl; - - // std::cout << "lb: " << lb << std::endl; - // std::cout << "ub: " << ub << std::endl; - // std::cout << std::endl; - - CGAL_assertion(lb <= ub); - CGAL_assertion(lb <= input); - CGAL_assertion(ub >= input); - + if (l == std::numeric_limits::infinity()) { + l = std::numeric_limits::max(); + CGAL_assertion(u == std::numeric_limits::infinity()); + } else if (u == -std::numeric_limits::infinity()) { + u = std::numeric_limits::lowest(); + CGAL_assertion(l == -std::numeric_limits::infinity()); + } + CGAL_assertion(are_correct_bounds(l, u, input)); return std::make_pair(l, u); } std::pair get_interval_using_cpp_rational( const Type& x ) const { - std::cout << "input: " << x << std::endl; - const double inf = std::numeric_limits::infinity(); const double xn = x.num.template convert_to(); const double xd = x.den.template convert_to(); if (xn == inf || xd == inf) { - // TODO: Is it fast enough? Seems so because this conversion happens + // Seems fast enough because this conversion happens // only a few times during the run, at least for NEF. boost::multiprecision::cpp_rational rat; CGAL_assertion(x.den != 0); @@ -993,22 +910,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > i = nextafter(i, -inf); CGAL_assertion(rat.compare(i) > 0); } - - Type lb(i), ub(s); - - std::cout << "inf case" << std::endl; - std::cout << "x: " << x << std::endl; - std::cout << "l: " << i << std::endl; - std::cout << "u: " << s << std::endl; - - std::cout << "lb: " << lb << std::endl; - std::cout << "ub: " << ub << std::endl; - std::cout << std::endl; - - CGAL_assertion(lb <= ub); - CGAL_assertion(lb <= x); - CGAL_assertion(ub >= x); - + CGAL_assertion(are_correct_bounds(i, s, x)); return std::make_pair(i, s); } else { @@ -1016,23 +918,6 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const Interval_nt<> quot = Interval_nt<>(CGAL_NTS to_interval(x.num)) / Interval_nt<>(CGAL_NTS to_interval(x.den)); - - Type lb(quot.inf()); - Type ub(quot.sup()); - - std::cout << "std case" << std::endl; - std::cout << "x: " << x << std::endl; - std::cout << "l: " << quot.inf() << std::endl; - std::cout << "u: " << quot.sup() << std::endl; - - std::cout << "lb: " << lb << std::endl; - std::cout << "ub: " << ub << std::endl; - std::cout << std::endl; - - CGAL_assertion(lb <= ub); - CGAL_assertion(lb <= x); - CGAL_assertion(ub >= x); - return std::make_pair(quot.inf(), quot.sup()); } } @@ -1043,24 +928,12 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > #if true // tight bounds optimized - // Make tight and fast bounds for x here. - // 1. Gmpzf.h - line 156 and Gmpzf_type.h - line 412. - // 2. generic_interconvert.hpp - line 305. - - // TODO: Can we avoid this copying by getting x without const? - // TODO: Both versions do not fully work with NEF, leading to NEF assertions, - // however they both pass for REG and all test cases. - Type xx = x; - - // TODO: compare both below with the stable cpp_rational-based implementation - // and see which configurations fail for NEF data. - // Seems to be less precise and we rarely end up with an interval [d,d] // even for numbers, which are exactly representable as double. - // return get_interval_as_gmpzf(xx); + return get_interval_as_gmpzf(x); // Works slightly better than the first one. - return get_interval_as_boost(xx); + // return get_interval_as_boost(x); #else // cpp_rational based tight bounds @@ -1074,17 +947,6 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const Interval_nt<> quot = Interval_nt<>(CGAL_NTS to_interval(x.numerator())) / Interval_nt<>(CGAL_NTS to_interval(x.denominator())); - - Type lb(quot.inf()), ub(quot.sup()); - CGAL_assertion(lb <= ub); - CGAL_assertion(lb <= x); - CGAL_assertion(ub >= x); - - // std::cout << "x: " << x << std::endl; - // std::cout << "l: " << quot.inf() << std::endl; - // std::cout << "u: " << quot.sup() << std::endl; - // std::cout << std::endl; - return std::make_pair(quot.inf(), quot.sup()); #endif From 0e92e236d70636bfadfc175a2862983f347be1c0 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 9 Sep 2021 13:12:37 +0200 Subject: [PATCH 039/127] cleanup --- Number_types/include/CGAL/Quotient.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index baede3c523a5..d2165db263fa 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -930,10 +930,10 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // Seems to be less precise and we rarely end up with an interval [d,d] // even for numbers, which are exactly representable as double. - return get_interval_as_gmpzf(x); + // return get_interval_as_gmpzf(x); // Works slightly better than the first one. - // return get_interval_as_boost(x); + return get_interval_as_boost(x); #else // cpp_rational based tight bounds From 732d642cbe83c8cdf537609afd5f90eb230ace37 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 9 Sep 2021 13:15:35 +0200 Subject: [PATCH 040/127] removed useless cout --- Number_types/include/CGAL/MP_Float.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Number_types/include/CGAL/MP_Float.h b/Number_types/include/CGAL/MP_Float.h index 620e756a7667..68cfdecde448 100644 --- a/Number_types/include/CGAL/MP_Float.h +++ b/Number_types/include/CGAL/MP_Float.h @@ -777,9 +777,6 @@ inline void simplify_quotient(MP_Float & numerator, MP_Float & denominator) { - // return; - // std::cout << "a: " << numerator << std::endl; - // std::cout << "b: " << denominator << std::endl; // Currently only simplifies the two exponents. #if 0 // This better version causes problems as the I/O is changed for @@ -796,16 +793,12 @@ simplify_quotient(MP_Float & numerator, MP_Float & denominator) numerator.exp -= denominator.exp; denominator.exp = 0; const MP_Float g = gcd(numerator, denominator); - // std::cout << "r: " << g << std::endl; numerator = integral_division(numerator, g); denominator = integral_division(denominator, g); } numerator.exp -= denominator.exp; denominator.exp = 0; #endif - // std::cout << "new a: " << numerator << std::endl; - // std::cout << "new b: " << denominator << std::endl; - // std::cout << std::endl; } inline void simplify_root_of_2(MP_Float &/*a*/, MP_Float &/*b*/, MP_Float&/*c*/) { From c445dcf64b9273c675ea134d6f5ce2be19d28f86 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 9 Sep 2021 13:39:57 +0200 Subject: [PATCH 041/127] using cpp_int as default --- Number_types/include/CGAL/Quotient.h | 10 ++++++---- .../include/CGAL/internal/Exact_type_selector.h | 10 +++++----- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index d2165db263fa..4d330a7ddc8e 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -944,10 +944,12 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > #else // master version - const Interval_nt<> quot = - Interval_nt<>(CGAL_NTS to_interval(x.numerator())) / - Interval_nt<>(CGAL_NTS to_interval(x.denominator())); - return std::make_pair(quot.inf(), quot.sup()); + return get_interval_as_boost(x); + + // const Interval_nt<> quot = + // Interval_nt<>(CGAL_NTS to_interval(x.numerator())) / + // Interval_nt<>(CGAL_NTS to_interval(x.denominator())); + // return std::make_pair(quot.inf(), quot.sup()); #endif } diff --git a/Number_types/include/CGAL/internal/Exact_type_selector.h b/Number_types/include/CGAL/internal/Exact_type_selector.h index ad668818b11c..901e3bcde10f 100644 --- a/Number_types/include/CGAL/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/internal/Exact_type_selector.h @@ -55,12 +55,12 @@ namespace CGAL { namespace internal { template < typename > struct Exact_field_selector #ifdef CGAL_USE_GMPXX -{ typedef mpq_class Type; }; +{ typedef Quotient Type; }; #elif defined(CGAL_USE_GMP) # if defined(CGAL_USE_BOOST_MP) -{ typedef boost::multiprecision::mpq_rational Type; }; +{ typedef Quotient Type; }; # else -{ typedef Gmpq Type; }; +{ typedef Quotient Type; }; # endif #elif defined(CGAL_USE_LEDA) { typedef leda_rational Type; }; @@ -70,10 +70,10 @@ struct Exact_field_selector #if defined(CGAL_USE_CPP_INT) { typedef Quotient Type; }; #else -{ typedef BOOST_cpp_arithmetic_kernel::Rational Type; }; +{ typedef Quotient Type; }; # endif #else -{ typedef Quotient Type; }; +{ typedef Quotient Type; }; #endif // By default, a field is a safe choice of ring. From fccdcabb3f1863d97cb1fd9133447220c621303a Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 9 Sep 2021 13:54:25 +0200 Subject: [PATCH 042/127] added back ets --- .../CGAL/internal/Exact_type_selector.h | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 Number_types/include/CGAL/internal/Exact_type_selector.h diff --git a/Number_types/include/CGAL/internal/Exact_type_selector.h b/Number_types/include/CGAL/internal/Exact_type_selector.h new file mode 100644 index 000000000000..901e3bcde10f --- /dev/null +++ b/Number_types/include/CGAL/internal/Exact_type_selector.h @@ -0,0 +1,188 @@ +// Copyright (c) 2004 +// Utrecht University (The Netherlands), +// ETH Zurich (Switzerland), +// INRIA Sophia-Antipolis (France), +// Max-Planck-Institute Saarbruecken (Germany), +// and Tel-Aviv University (Israel). All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Sylvain Pion + +#ifndef CGAL_INTERNAL_EXACT_TYPE_SELECTOR_H +#define CGAL_INTERNAL_EXACT_TYPE_SELECTOR_H + +// This is an undocumented private helper for Filtered_kernel. + +#include +#include +#include +#include + +#include +#ifdef CGAL_USE_GMP +# include +# include +# include +# include +#endif +#ifdef CGAL_USE_GMPXX +# include +#endif +#ifdef CGAL_USE_LEDA +# include +# include +# include +#endif +#ifdef CGAL_USE_CORE +// # include +namespace CORE { +class Expr; +} +#endif + +namespace CGAL { namespace internal { + +// Two classes which tell the prefered "exact number types" corresponding to a type. + +// The default template chooses mpq_class, Gmpq, leda_rational, or Quotient. +// It should support the built-in types. +template < typename > +struct Exact_field_selector +#ifdef CGAL_USE_GMPXX +{ typedef Quotient Type; }; +#elif defined(CGAL_USE_GMP) +# if defined(CGAL_USE_BOOST_MP) +{ typedef Quotient Type; }; +# else +{ typedef Quotient Type; }; +# endif +#elif defined(CGAL_USE_LEDA) +{ typedef leda_rational Type; }; +#elif defined(CGAL_USE_BOOST_MP) +// See the discussion in https://github.com/CGAL/cgal/pull/3614 +// This is disabled for now because cpp_rational is even slower than Quotient. Quotient will be a good candidate after some polishing. +#if defined(CGAL_USE_CPP_INT) +{ typedef Quotient Type; }; +#else +{ typedef Quotient Type; }; +# endif +#else +{ typedef Quotient Type; }; +#endif + +// By default, a field is a safe choice of ring. +template < typename T > +struct Exact_ring_selector : Exact_field_selector < T > { }; + +template <> +struct Exact_ring_selector +#ifdef CGAL_HAS_MPZF +{ typedef Mpzf Type; }; +#elif defined(CGAL_HAS_THREADS) || !defined(CGAL_USE_GMP) +{ typedef MP_Float Type; }; +#else +{ typedef Gmpzf Type; }; +#endif + +template <> +struct Exact_ring_selector : Exact_ring_selector { }; + +template <> +struct Exact_field_selector +{ typedef Quotient Type; }; + +template <> +struct Exact_ring_selector +{ typedef MP_Float Type; }; + +template <> +struct Exact_field_selector > +{ typedef Quotient Type; }; + +// And we specialize for the following types : +#ifdef CGAL_USE_GMP +template <> +struct Exact_field_selector +{ typedef Gmpq Type; }; + +template <> +struct Exact_ring_selector +{ typedef Gmpz Type; }; + +template <> +struct Exact_ring_selector +{ typedef Gmpzf Type; }; + +template <> +struct Exact_field_selector +{ typedef Gmpq Type; }; +#endif + +#ifdef CGAL_USE_GMPXX +template <> +struct Exact_field_selector< ::mpz_class> +{ typedef ::mpq_class Type; }; + +template <> +struct Exact_ring_selector< ::mpz_class> +{ typedef ::mpz_class Type; }; + +template <> +struct Exact_field_selector< ::mpq_class> +{ typedef ::mpq_class Type; }; +#endif + +#ifdef CGAL_USE_LEDA +template <> +struct Exact_field_selector +{ typedef leda_rational Type; }; + +template <> +struct Exact_ring_selector +{ typedef leda_integer Type; }; + +template <> +struct Exact_field_selector +{ typedef leda_rational Type; }; + +template <> +struct Exact_field_selector +{ typedef leda_real Type; }; +#endif + +#ifdef CGAL_USE_CORE +template <> +struct Exact_field_selector +{ typedef CORE::Expr Type; }; +#endif + +template < typename ET > +struct Exact_field_selector > +: Exact_field_selector +{ + // We have a choice here : + // - using ET gets rid of the DAG computation as well as redoing the interval + // - using Lazy_exact_nt might use sharper intervals. + // typedef ET Type; + // typedef Lazy_exact_nt Type; +}; +template < typename ET > +struct Exact_ring_selector > +: Exact_ring_selector +{}; + +#ifndef CGAL_NO_DEPRECATED_CODE +// Added for backward compatibility +template < typename ET > +struct Exact_type_selector : Exact_field_selector< ET > {}; +#endif + +} } // namespace CGAL::internal + +#endif // CGAL_INTERNAL_EXACT_TYPE_SELECTOR_H From 5d129a3a3688d39f73f6bf2702933bc6bbe61871 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 9 Sep 2021 14:33:38 +0200 Subject: [PATCH 043/127] fixed integer type --- Number_types/include/CGAL/Exact_integer.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Number_types/include/CGAL/Exact_integer.h b/Number_types/include/CGAL/Exact_integer.h index f6c8ff858359..c2d6192fe32e 100644 --- a/Number_types/include/CGAL/Exact_integer.h +++ b/Number_types/include/CGAL/Exact_integer.h @@ -52,13 +52,13 @@ typedef unspecified_type Exact_integer; #if CGAL_USE_GMPXX -typedef mpz_class Exact_integer; +typedef boost::multiprecision::cpp_int Exact_integer; #elif CGAL_USE_GMP # ifdef CGAL_USE_BOOST_MP -typedef boost::multiprecision::mpz_int Exact_integer; +typedef boost::multiprecision::cpp_int Exact_integer; # else -typedef Gmpz Exact_integer; +typedef boost::multiprecision::cpp_int Exact_integer; # endif #elif CGAL_USE_LEDA @@ -67,7 +67,7 @@ typedef leda_integer Exact_integer; #elif CGAL_USE_CORE -typedef CORE::BigInt Exact_integer; +typedef boost::multiprecision::cpp_int Exact_integer; #elif defined CGAL_USE_BOOST_MP From 6ca6b3ae41d0cf51a2f141cad46952c686a885b4 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 9 Sep 2021 16:09:27 +0200 Subject: [PATCH 044/127] using int64_t and other small improvements --- Number_types/include/CGAL/Quotient.h | 115 ++++++++++++--------------- 1 file changed, 51 insertions(+), 64 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 4d330a7ddc8e..f97e534df456 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -708,33 +708,55 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { public: - std::pair< std::pair, long > get_interval_exp( NT& x ) const { + bool are_correct_bounds( const double l, const double u, const Type& x ) const { + + if ( + CGAL::abs(l) == std::numeric_limits::infinity() || + CGAL::abs(u) == std::numeric_limits::infinity() || + CGAL::abs(l) == 0.0 || CGAL::abs(u) == 0.0) { + return true; + } + CGAL_assertion(CGAL::abs(l) != std::numeric_limits::infinity()); + CGAL_assertion(CGAL::abs(u) != std::numeric_limits::infinity()); + CGAL_assertion(CGAL::abs(l) != 0.0); + CGAL_assertion(CGAL::abs(u) != 0.0); + + const Type lb(l), ub(u); + CGAL_assertion(lb <= ub); + CGAL_assertion(lb <= x); + CGAL_assertion(ub >= x); + return lb <= ub && lb <= x && ub >= x; + } + + std::pair< std::pair, int64_t > get_interval_exp( NT& x ) const { CGAL_assertion(x >= 0); - const unsigned n = msb(x); - const unsigned num_dbl_digits = std::numeric_limits::digits - 1; + const int64_t n = static_cast(msb(x)); + const int64_t num_dbl_digits = std::numeric_limits::digits - 1; if (n > num_dbl_digits) { - const unsigned d = n - num_dbl_digits; + const int64_t d = n - num_dbl_digits; x = x >> d; + const NT y = x + 1; - const double l = boost::multiprecision::detail::do_cast(x); - const double u = boost::multiprecision::detail::do_cast(x + 1); + const double l = static_cast(x); + const double u = static_cast(y); return std::make_pair( std::make_pair(l, u), d ); } else { - const double l = boost::multiprecision::detail::do_cast(x); + const double l = static_cast(x); const double u = l; return std::make_pair( std::make_pair(l, u), 0 ); } } - std::pair get_interval_as_gmpzf( const Type& input ) const { + std::pair get_interval_as_gmpzf( Type x ) const { - Type x = input; + CGAL_assertion_code(const Type input = x); double l = 0.0, u = 0.0; if (x.num == 0) { // return [0.0, 0.0] + CGAL_assertion(are_correct_bounds(l, u, input)); return std::make_pair(l, u); } CGAL_assertion(x.num != 0); @@ -754,57 +776,28 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } CGAL_assertion(x.num > 0 && x.den > 0); - auto n = get_interval_exp(x.num); - auto d = get_interval_exp(x.den); + const auto n = get_interval_exp(x.num); + const auto d = get_interval_exp(x.den); const Interval_nt<> num(n.first); const Interval_nt<> den(d.first); const Interval_nt<> div = num / den; - const int e = static_cast(n.second - d.second); + const int64_t e = n.second - d.second; std::tie(l, u) = ldexp(div, e).pair(); - if (u == 0.0) { - u = std::numeric_limits::min(); - CGAL_assertion(l == 0.0); - } - if (change_sign) { const double t = l; l = -u; u = -t; } - if (l == std::numeric_limits::infinity()) { - l = std::numeric_limits::max(); - CGAL_assertion(u == std::numeric_limits::infinity()); - } else if (u == -std::numeric_limits::infinity()) { - u = std::numeric_limits::lowest(); - CGAL_assertion(l == -std::numeric_limits::infinity()); - } CGAL_assertion(are_correct_bounds(l, u, input)); return std::make_pair(l, u); } - bool are_correct_bounds( const double l, const double u, const Type& x ) const { - - if ( - CGAL::abs(l) == std::numeric_limits::infinity() || - CGAL::abs(u) == std::numeric_limits::infinity()) { - return true; - } - CGAL_assertion(CGAL::abs(l) != std::numeric_limits::infinity()); - CGAL_assertion(CGAL::abs(u) != std::numeric_limits::infinity()); + std::pair get_interval_as_boost( Type x ) const { - const Type lb(l), ub(u); - CGAL_assertion(lb <= ub); - CGAL_assertion(lb <= x); - CGAL_assertion(ub >= x); - return lb <= ub && lb <= x && ub >= x; - } - - std::pair get_interval_as_boost( const Type& input ) const { - - Type x = input; // TODO: Can we avoid this copying? + CGAL_assertion_code(const Type input = x); double l = 0.0, u = 0.0; if (x.num == 0) { // return [0.0, 0.0] CGAL_assertion(are_correct_bounds(l, u, input)); @@ -827,9 +820,11 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } CGAL_assertion(x.num > 0 && x.den > 0); - const int num_dbl_digits = std::numeric_limits::digits - 1; - const int msb_diff = int(msb(x.num) - msb(x.den)); - const int shift = num_dbl_digits - msb_diff; + const int64_t num_dbl_digits = std::numeric_limits::digits - 1; + const int64_t msb_num = static_cast(msb(x.num)); + const int64_t msb_den = static_cast(msb(x.den)); + const int64_t msb_diff = msb_num - msb_den; + const int64_t shift = num_dbl_digits - msb_diff; if (shift > 0) { CGAL_assertion(msb_diff < num_dbl_digits); @@ -838,11 +833,12 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(msb_diff > num_dbl_digits); x.den <<= boost::multiprecision::detail::unsigned_abs(shift); } - CGAL_assertion(int(msb(x.num) - msb(x.den)) == num_dbl_digits); + CGAL_assertion(num_dbl_digits == + static_cast(msb(x.num)) - static_cast(msb(x.den))); decltype(x.num) p, q, r; boost::multiprecision::divide_qr(x.num, x.den, q, r); - const int q_bits = msb(q); + const int64_t q_bits = static_cast(msb(q)); CGAL_assertion(q_bits == num_dbl_digits || r != 0); if (r != 0) { @@ -852,15 +848,11 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > p = q; } - l = static_cast(p); - l = std::ldexp(l, -shift); - u = static_cast(q); - u = std::ldexp(u, -shift); - - if (u == 0.0) { - u = std::numeric_limits::min(); - CGAL_assertion(l == 0.0); - } + CGAL_assertion(p >= 0 && q >= 0); + const uint64_t pp = static_cast(p); + const uint64_t qq = static_cast(q); + const Interval_nt<> intv(pp, qq); + std::tie(l, u) = ldexp(intv, -shift).pair(); if (change_sign) { const double t = l; @@ -868,13 +860,6 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > u = -t; } - if (l == std::numeric_limits::infinity()) { - l = std::numeric_limits::max(); - CGAL_assertion(u == std::numeric_limits::infinity()); - } else if (u == -std::numeric_limits::infinity()) { - u = std::numeric_limits::lowest(); - CGAL_assertion(l == -std::numeric_limits::infinity()); - } CGAL_assertion(are_correct_bounds(l, u, input)); return std::make_pair(l, u); } @@ -944,6 +929,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > #else // master version + // TODO: Remove it from here! + // Put back the correct Exact_type_selector and Exact_integer as well! return get_interval_as_boost(x); // const Interval_nt<> quot = From 3f2e4b2a9b4b9aecad6089b778c33da500c4a82d Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 9 Sep 2021 16:17:51 +0200 Subject: [PATCH 045/127] better get_interval_exp --- Number_types/include/CGAL/Quotient.h | 32 ++++++++++++---------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index f97e534df456..d880dc77987f 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -728,27 +728,25 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > return lb <= ub && lb <= x && ub >= x; } - std::pair< std::pair, int64_t > get_interval_exp( NT& x ) const { + std::pair< Interval_nt<>, int64_t > get_interval_exp( NT& x ) const { CGAL_assertion(x >= 0); + int64_t d = 0; + double l = 0.0, u = 0.0; const int64_t n = static_cast(msb(x)); const int64_t num_dbl_digits = std::numeric_limits::digits - 1; - if (n > num_dbl_digits) { - const int64_t d = n - num_dbl_digits; + if (n > num_dbl_digits) { + d = n - num_dbl_digits; x = x >> d; const NT y = x + 1; - - const double l = static_cast(x); - const double u = static_cast(y); - return std::make_pair( std::make_pair(l, u), d ); - + l = static_cast(x); + u = static_cast(y); } else { - - const double l = static_cast(x); - const double u = l; - return std::make_pair( std::make_pair(l, u), 0 ); + l = static_cast(x); + u = l; } + return std::make_pair( Interval_nt<>(l, u), d ); } std::pair get_interval_as_gmpzf( Type x ) const { @@ -776,13 +774,11 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } CGAL_assertion(x.num > 0 && x.den > 0); - const auto n = get_interval_exp(x.num); - const auto d = get_interval_exp(x.den); + const auto num = get_interval_exp(x.num); + const auto den = get_interval_exp(x.den); - const Interval_nt<> num(n.first); - const Interval_nt<> den(d.first); - const Interval_nt<> div = num / den; - const int64_t e = n.second - d.second; + const Interval_nt<> div = num.first / den.first; + const int64_t e = num.second - den.second; std::tie(l, u) = ldexp(div, e).pair(); if (change_sign) { From 05c1d07f96352e545d2ff899f0d1aa1ee10f1caf Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 9 Sep 2021 16:59:43 +0200 Subject: [PATCH 046/127] andreas review --- Number_types/include/CGAL/Quotient.h | 60 ++++++++++++++-------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index d880dc77987f..e340c0b44b4d 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -706,6 +706,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > class To_interval : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { + const NT zero = 0; public: bool are_correct_bounds( const double l, const double u, const Type& x ) const { @@ -730,7 +731,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > std::pair< Interval_nt<>, int64_t > get_interval_exp( NT& x ) const { - CGAL_assertion(x >= 0); + CGAL_assertion(x >= zero); int64_t d = 0; double l = 0.0, u = 0.0; const int64_t n = static_cast(msb(x)); @@ -753,26 +754,26 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion_code(const Type input = x); double l = 0.0, u = 0.0; - if (x.num == 0) { // return [0.0, 0.0] + if (x.num == zero) { // return [0.0, 0.0] CGAL_assertion(are_correct_bounds(l, u, input)); return std::make_pair(l, u); } - CGAL_assertion(x.num != 0); - CGAL_assertion(x.den != 0); + CGAL_assertion(x.num != zero); + CGAL_assertion(x.den != zero); // Handle signs. bool change_sign = false; - if (x.num < 0 && x.den < 0) { + if (x.num < zero && x.den < zero) { x.num = -x.num; x.den = -x.den; - } else if (x.num < 0 && x.den > 0) { + } else if (x.num < zero && x.den > zero) { change_sign = true; x.num = -x.num; - } else if (x.num > 0 && x.den < 0) { + } else if (x.num > zero && x.den < zero) { change_sign = true; x.den = -x.den; } - CGAL_assertion(x.num > 0 && x.den > 0); + CGAL_assertion(x.num > zero && x.den > zero); const auto num = get_interval_exp(x.num); const auto den = get_interval_exp(x.den); @@ -795,26 +796,26 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion_code(const Type input = x); double l = 0.0, u = 0.0; - if (x.num == 0) { // return [0.0, 0.0] + if (x.num == zero) { // return [0.0, 0.0] CGAL_assertion(are_correct_bounds(l, u, input)); return std::make_pair(l, u); } - CGAL_assertion(x.num != 0); - CGAL_assertion(x.den != 0); + CGAL_assertion(x.num != zero); + CGAL_assertion(x.den != zero); // Handle signs. bool change_sign = false; - if (x.num < 0 && x.den < 0) { + if (x.num < zero && x.den < zero) { x.num = -x.num; x.den = -x.den; - } else if (x.num < 0 && x.den > 0) { + } else if (x.num < zero && x.den > zero) { change_sign = true; x.num = -x.num; - } else if (x.num > 0 && x.den < 0) { + } else if (x.num > zero && x.den < zero) { change_sign = true; x.den = -x.den; } - CGAL_assertion(x.num > 0 && x.den > 0); + CGAL_assertion(x.num > zero && x.den > zero); const int64_t num_dbl_digits = std::numeric_limits::digits - 1; const int64_t msb_num = static_cast(msb(x.num)); @@ -832,24 +833,26 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(num_dbl_digits == static_cast(msb(x.num)) - static_cast(msb(x.den))); - decltype(x.num) p, q, r; + NT q, r; boost::multiprecision::divide_qr(x.num, x.den, q, r); const int64_t q_bits = static_cast(msb(q)); + CGAL_assertion(q_bits == num_dbl_digits || r != zero /* when q_bit = num_dbl_digits - 1 */ ); - CGAL_assertion(q_bits == num_dbl_digits || r != 0); - if (r != 0) { - p = q; + if (r != zero) { + const NT p = q; ++q; + CGAL_assertion(p >= zero && q > p); + const uint64_t pp = static_cast(p); + const uint64_t qq = static_cast(q); + const Interval_nt<> intv(pp, qq); + std::tie(l, u) = ldexp(intv, -shift).pair(); } else { - p = q; + CGAL_assertion(q >= zero); + const uint64_t qq = static_cast(q); + const Interval_nt<> intv(qq, qq); + std::tie(l, u) = ldexp(intv, -shift).pair(); } - CGAL_assertion(p >= 0 && q >= 0); - const uint64_t pp = static_cast(p); - const uint64_t qq = static_cast(q); - const Interval_nt<> intv(pp, qq); - std::tie(l, u) = ldexp(intv, -shift).pair(); - if (change_sign) { const double t = l; l = -u; @@ -870,8 +873,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // Seems fast enough because this conversion happens // only a few times during the run, at least for NEF. boost::multiprecision::cpp_rational rat; - CGAL_assertion(x.den != 0); - if (x.den < 0) { + CGAL_assertion(x.den != zero); + if (x.den < zero) { rat = boost::multiprecision::cpp_rational(-x.num, -x.den); } else { rat = boost::multiprecision::cpp_rational( x.num, x.den); @@ -926,7 +929,6 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > #else // master version // TODO: Remove it from here! - // Put back the correct Exact_type_selector and Exact_integer as well! return get_interval_as_boost(x); // const Interval_nt<> quot = From f2b9a9b685fb37fb53b26c607238a0aaff32218d Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 9 Sep 2021 17:18:33 +0200 Subject: [PATCH 047/127] using is_zero, is_positive, is_negative --- Number_types/include/CGAL/Quotient.h | 56 ++++++++++++++-------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index e340c0b44b4d..1aaaff85e8c4 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -706,7 +706,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > class To_interval : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { - const NT zero = 0; + public: bool are_correct_bounds( const double l, const double u, const Type& x ) const { @@ -731,7 +731,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > std::pair< Interval_nt<>, int64_t > get_interval_exp( NT& x ) const { - CGAL_assertion(x >= zero); + CGAL_assertion((CGAL::is_zero(x) || CGAL::is_positive(x))); int64_t d = 0; double l = 0.0, u = 0.0; const int64_t n = static_cast(msb(x)); @@ -754,26 +754,26 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion_code(const Type input = x); double l = 0.0, u = 0.0; - if (x.num == zero) { // return [0.0, 0.0] + if (CGAL::is_zero(x.num)) { // return [0.0, 0.0] CGAL_assertion(are_correct_bounds(l, u, input)); return std::make_pair(l, u); } - CGAL_assertion(x.num != zero); - CGAL_assertion(x.den != zero); + CGAL_assertion(!CGAL::is_zero(x.num)); + CGAL_assertion(!CGAL::is_zero(x.den)); // Handle signs. bool change_sign = false; - if (x.num < zero && x.den < zero) { + if (CGAL::is_negative(x.num) && CGAL::is_negative(x.den)) { x.num = -x.num; x.den = -x.den; - } else if (x.num < zero && x.den > zero) { + } else if (CGAL::is_negative(x.num) && CGAL::is_positive(x.den)) { change_sign = true; x.num = -x.num; - } else if (x.num > zero && x.den < zero) { + } else if (CGAL::is_positive(x.num) && CGAL::is_negative(x.den)) { change_sign = true; x.den = -x.den; } - CGAL_assertion(x.num > zero && x.den > zero); + CGAL_assertion(CGAL::is_positive(x.num) && CGAL::is_positive(x.den)); const auto num = get_interval_exp(x.num); const auto den = get_interval_exp(x.den); @@ -796,26 +796,26 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion_code(const Type input = x); double l = 0.0, u = 0.0; - if (x.num == zero) { // return [0.0, 0.0] + if (CGAL::is_zero(x.num)) { // return [0.0, 0.0] CGAL_assertion(are_correct_bounds(l, u, input)); return std::make_pair(l, u); } - CGAL_assertion(x.num != zero); - CGAL_assertion(x.den != zero); + CGAL_assertion(!CGAL::is_zero(x.num)); + CGAL_assertion(!CGAL::is_zero(x.den)); // Handle signs. bool change_sign = false; - if (x.num < zero && x.den < zero) { + if (CGAL::is_negative(x.num) && CGAL::is_negative(x.den)) { x.num = -x.num; x.den = -x.den; - } else if (x.num < zero && x.den > zero) { + } else if (CGAL::is_negative(x.num) && CGAL::is_positive(x.den)) { change_sign = true; x.num = -x.num; - } else if (x.num > zero && x.den < zero) { + } else if (CGAL::is_positive(x.num) && CGAL::is_negative(x.den)) { change_sign = true; x.den = -x.den; } - CGAL_assertion(x.num > zero && x.den > zero); + CGAL_assertion(CGAL::is_positive(x.num) && CGAL::is_positive(x.den)); const int64_t num_dbl_digits = std::numeric_limits::digits - 1; const int64_t msb_num = static_cast(msb(x.num)); @@ -823,10 +823,10 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const int64_t msb_diff = msb_num - msb_den; const int64_t shift = num_dbl_digits - msb_diff; - if (shift > 0) { + if (CGAL::is_positive(shift)) { CGAL_assertion(msb_diff < num_dbl_digits); x.num <<= shift; - } else if (shift < 0) { + } else if (CGAL::is_negative(shift)) { CGAL_assertion(msb_diff > num_dbl_digits); x.den <<= boost::multiprecision::detail::unsigned_abs(shift); } @@ -836,18 +836,18 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > NT q, r; boost::multiprecision::divide_qr(x.num, x.den, q, r); const int64_t q_bits = static_cast(msb(q)); - CGAL_assertion(q_bits == num_dbl_digits || r != zero /* when q_bit = num_dbl_digits - 1 */ ); + CGAL_assertion(q_bits == num_dbl_digits || !CGAL::is_zero(r) /* when q_bit = num_dbl_digits - 1 */ ); - if (r != zero) { + if (!CGAL::is_zero(r)) { const NT p = q; ++q; - CGAL_assertion(p >= zero && q > p); + CGAL_assertion((CGAL::is_zero(p) || CGAL::is_positive(p)) && CGAL::is_positive(q - p)); const uint64_t pp = static_cast(p); const uint64_t qq = static_cast(q); const Interval_nt<> intv(pp, qq); std::tie(l, u) = ldexp(intv, -shift).pair(); } else { - CGAL_assertion(q >= zero); + CGAL_assertion((CGAL::is_zero(q) || CGAL::is_positive(q))); const uint64_t qq = static_cast(q); const Interval_nt<> intv(qq, qq); std::tie(l, u) = ldexp(intv, -shift).pair(); @@ -873,8 +873,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // Seems fast enough because this conversion happens // only a few times during the run, at least for NEF. boost::multiprecision::cpp_rational rat; - CGAL_assertion(x.den != zero); - if (x.den < zero) { + CGAL_assertion(!CGAL::is_zero(x.den)); + if (CGAL::is_negative(x.den)) { rat = boost::multiprecision::cpp_rational(-x.num, -x.den); } else { rat = boost::multiprecision::cpp_rational( x.num, x.den); @@ -886,13 +886,13 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const double inf = std::numeric_limits::infinity(); CGAL_assertion(i != inf && s != inf); const int cmp = rat.compare(i); - if (cmp > 0) { + if (CGAL::is_positive(cmp)) { s = nextafter(s, +inf); - CGAL_assertion(rat.compare(s) < 0); + CGAL_assertion(CGAL::is_negative(rat.compare(s))); } - else if (cmp < 0) { + else if (CGAL::is_negative(cmp)) { i = nextafter(i, -inf); - CGAL_assertion(rat.compare(i) > 0); + CGAL_assertion(CGAL::is_positive(rat.compare(i))); } CGAL_assertion(are_correct_bounds(i, s, x)); return std::make_pair(i, s); From 91d8ff7603e2f740671d707e4f153a101dac8d92 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 9 Sep 2021 17:32:44 +0200 Subject: [PATCH 048/127] optimized some computations --- Number_types/include/CGAL/Quotient.h | 47 +++++++++++++++------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 1aaaff85e8c4..0fd0d407378d 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -714,7 +714,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > if ( CGAL::abs(l) == std::numeric_limits::infinity() || CGAL::abs(u) == std::numeric_limits::infinity() || - CGAL::abs(l) == 0.0 || CGAL::abs(u) == 0.0) { + CGAL::abs(l) == 0.0 || + CGAL::abs(u) == 0.0) { return true; } CGAL_assertion(CGAL::abs(l) != std::numeric_limits::infinity()); @@ -731,13 +732,13 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > std::pair< Interval_nt<>, int64_t > get_interval_exp( NT& x ) const { - CGAL_assertion((CGAL::is_zero(x) || CGAL::is_positive(x))); + CGAL_assertion(x >= 0); int64_t d = 0; double l = 0.0, u = 0.0; const int64_t n = static_cast(msb(x)); const int64_t num_dbl_digits = std::numeric_limits::digits - 1; - if (n > num_dbl_digits) { + if (CGAL::is_positive(n - num_dbl_digits)) { d = n - num_dbl_digits; x = x >> d; const NT y = x + 1; @@ -758,22 +759,24 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(are_correct_bounds(l, u, input)); return std::make_pair(l, u); } - CGAL_assertion(!CGAL::is_zero(x.num)); - CGAL_assertion(!CGAL::is_zero(x.den)); + CGAL_assertion(x.num != 0); + CGAL_assertion(x.den != 0); // Handle signs. bool change_sign = false; - if (CGAL::is_negative(x.num) && CGAL::is_negative(x.den)) { + const bool is_pos_num = CGAL::is_positive(x.num); + const bool is_pos_den = CGAL::is_positive(x.den); + if (!is_pos_num && !is_pos_den) { x.num = -x.num; x.den = -x.den; - } else if (CGAL::is_negative(x.num) && CGAL::is_positive(x.den)) { + } else if (!is_pos_num && is_pos_den) { change_sign = true; x.num = -x.num; - } else if (CGAL::is_positive(x.num) && CGAL::is_negative(x.den)) { + } else if (is_pos_num && !is_pos_den) { change_sign = true; x.den = -x.den; } - CGAL_assertion(CGAL::is_positive(x.num) && CGAL::is_positive(x.den)); + CGAL_assertion(x.num > 0 && x.den > 0); const auto num = get_interval_exp(x.num); const auto den = get_interval_exp(x.den); @@ -800,22 +803,24 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(are_correct_bounds(l, u, input)); return std::make_pair(l, u); } - CGAL_assertion(!CGAL::is_zero(x.num)); - CGAL_assertion(!CGAL::is_zero(x.den)); + CGAL_assertion(x.num != 0); + CGAL_assertion(x.den != 0); // Handle signs. bool change_sign = false; - if (CGAL::is_negative(x.num) && CGAL::is_negative(x.den)) { + const bool is_pos_num = CGAL::is_positive(x.num); + const bool is_pos_den = CGAL::is_positive(x.den); + if (!is_pos_num && !is_pos_den) { x.num = -x.num; x.den = -x.den; - } else if (CGAL::is_negative(x.num) && CGAL::is_positive(x.den)) { + } else if (!is_pos_num && is_pos_den) { change_sign = true; x.num = -x.num; - } else if (CGAL::is_positive(x.num) && CGAL::is_negative(x.den)) { + } else if (is_pos_num && !is_pos_den) { change_sign = true; x.den = -x.den; } - CGAL_assertion(CGAL::is_positive(x.num) && CGAL::is_positive(x.den)); + CGAL_assertion(x.num > 0 && x.den > 0); const int64_t num_dbl_digits = std::numeric_limits::digits - 1; const int64_t msb_num = static_cast(msb(x.num)); @@ -836,18 +841,18 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > NT q, r; boost::multiprecision::divide_qr(x.num, x.den, q, r); const int64_t q_bits = static_cast(msb(q)); - CGAL_assertion(q_bits == num_dbl_digits || !CGAL::is_zero(r) /* when q_bit = num_dbl_digits - 1 */ ); + CGAL_assertion(q_bits == num_dbl_digits || r != 0 /* when q_bit = num_dbl_digits - 1 */ ); if (!CGAL::is_zero(r)) { const NT p = q; ++q; - CGAL_assertion((CGAL::is_zero(p) || CGAL::is_positive(p)) && CGAL::is_positive(q - p)); + CGAL_assertion(p >= 0 && q > p); const uint64_t pp = static_cast(p); const uint64_t qq = static_cast(q); const Interval_nt<> intv(pp, qq); std::tie(l, u) = ldexp(intv, -shift).pair(); } else { - CGAL_assertion((CGAL::is_zero(q) || CGAL::is_positive(q))); + CGAL_assertion(q > 0); const uint64_t qq = static_cast(q); const Interval_nt<> intv(qq, qq); std::tie(l, u) = ldexp(intv, -shift).pair(); @@ -873,7 +878,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // Seems fast enough because this conversion happens // only a few times during the run, at least for NEF. boost::multiprecision::cpp_rational rat; - CGAL_assertion(!CGAL::is_zero(x.den)); + CGAL_assertion(x.den != 0); if (CGAL::is_negative(x.den)) { rat = boost::multiprecision::cpp_rational(-x.num, -x.den); } else { @@ -888,11 +893,11 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const int cmp = rat.compare(i); if (CGAL::is_positive(cmp)) { s = nextafter(s, +inf); - CGAL_assertion(CGAL::is_negative(rat.compare(s))); + CGAL_assertion(rat.compare(s) < 0); } else if (CGAL::is_negative(cmp)) { i = nextafter(i, -inf); - CGAL_assertion(CGAL::is_positive(rat.compare(i))); + CGAL_assertion(rat.compare(i) > 0); } CGAL_assertion(are_correct_bounds(i, s, x)); return std::make_pair(i, s); From 85bb624ae302185766265ff1dfa6b3bd5dce9853 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 9 Sep 2021 18:14:18 +0200 Subject: [PATCH 049/127] undo cppint in gcd --- Number_types/include/CGAL/Quotient.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 0fd0d407378d..89cbe0951fec 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -51,7 +51,7 @@ simplify_quotient(NT & a, NT & b) { // TODO: // - move it to the boost_mp.h // - can we use gcd only sometimes to save time? -#if defined(CGAL_USE_CPP_INT) && true +// #if defined(CGAL_USE_CPP_INT) && true const NT r = boost::multiprecision::gcd(a, b); // std::cout << "r: " << r << std::endl; @@ -63,7 +63,7 @@ simplify_quotient(NT & a, NT & b) { // std::cout << "new b: " << b << std::endl; // std::cout << std::endl; -#endif +// #endif } From 8b6fd0cb19e624d75ebb71178ccfb22030a85aee Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 9 Sep 2021 18:14:52 +0100 Subject: [PATCH 050/127] More gcd calls in operator + --- Number_types/include/CGAL/Quotient.h | 79 +++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 89cbe0951fec..247ffc223080 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -215,14 +215,91 @@ Quotient::normalize() template CGAL_MEDIUM_INLINE Quotient& -Quotient::operator+= (const Quotient& r) +Quotient::operator+= (const Quotient& b) { +#if 0 + num = num * r.den + r.num * den; den *= r.den; simplify_quotient(num, den); return *this; + +#else + + // taken from https://github.com/boostorg/multiprecision/blob/rational_adaptor_standalone/include/boost/multiprecision/rational_adaptor.hpp#L486 + // This has the BSL, but this code won't survive + typedef NT Backend; + + NT result_num, result_denom; + Backend gcd, t1, t2, t3, t4; + // + // Begin by getting the gcd of the 2 denominators: + // + gcd = boost::multiprecision::gcd(denominator(), b.denominator()); + // + // Do we have gcd > 1: + // + if (! gcd == 1) + { + // + // Scale the denominators by gcd, and put the results in t1 and t2: + // + t1 = CGAL::integral_division( b.denominator(), gcd); + t2 = CGAL::integral_division( denominator(), gcd); + // + // multiply the numerators by the scale denominators and put the results in t3, t4: + // + t3 = numerator() * t1; + t4 = b.numerator() * t2; + // + // Add them up: + // + t3 += t4; + // + // Get the gcd of gcd and our numerator (t3): + // + t4 = boost::multiprecision::gcd(t3, gcd); + if (t4 == 1) + { + result_num = t3; + result_denom = t1 * denominator(); + } + else + { + // + // Uncommon case where gcd is not 1, divide the numerator + // and the denominator terms by the new gcd. Note we perform division + // on the existing gcd value as this is the smallest of the 3 denominator + // terms we'll be multiplying together, so there's a good chance it's a + // single limb value already: + // + result_num= CGAL::integral_division(t3, t4); + t3 = CGAL::integral_division( gcd, t4); + t4 = t1 * t2; + result_denom = t4 * t3; + } + } + else + { + // + // Most common case (approx 60%) where gcd is one: + // + t1 = numerator() * b.denominator(); + t2 = denominator() *b.numerator(); + + result_num = t1 + t2; + + result_denom = denominator() * b.denominator(); + + } + + *this = Quotient(result_num,result_denom); + return *this; +#endif + } + template CGAL_MEDIUM_INLINE Quotient& From 34ff14ee90bc4ae36caee6e63dc8172b8eb6ad92 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 10 Sep 2021 10:03:01 +0200 Subject: [PATCH 051/127] fixed errors related to pos/neg calls --- Number_types/include/CGAL/Quotient.h | 47 +++++++++++++--------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 89cbe0951fec..1a3ffecf5180 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -51,7 +51,7 @@ simplify_quotient(NT & a, NT & b) { // TODO: // - move it to the boost_mp.h // - can we use gcd only sometimes to save time? -// #if defined(CGAL_USE_CPP_INT) && true +#if defined(CGAL_USE_CPP_INT) || true const NT r = boost::multiprecision::gcd(a, b); // std::cout << "r: " << r << std::endl; @@ -63,7 +63,7 @@ simplify_quotient(NT & a, NT & b) { // std::cout << "new b: " << b << std::endl; // std::cout << std::endl; -// #endif +#endif } @@ -738,7 +738,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const int64_t n = static_cast(msb(x)); const int64_t num_dbl_digits = std::numeric_limits::digits - 1; - if (CGAL::is_positive(n - num_dbl_digits)) { + if (n > num_dbl_digits) { d = n - num_dbl_digits; x = x >> d; const NT y = x + 1; @@ -764,15 +764,15 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // Handle signs. bool change_sign = false; - const bool is_pos_num = CGAL::is_positive(x.num); - const bool is_pos_den = CGAL::is_positive(x.den); - if (!is_pos_num && !is_pos_den) { + const bool is_num_pos = CGAL::is_positive(x.num); + const bool is_den_pos = CGAL::is_positive(x.den); + if (!is_num_pos && !is_den_pos) { x.num = -x.num; x.den = -x.den; - } else if (!is_pos_num && is_pos_den) { + } else if (!is_num_pos && is_den_pos) { change_sign = true; x.num = -x.num; - } else if (is_pos_num && !is_pos_den) { + } else if (is_num_pos && !is_den_pos) { change_sign = true; x.den = -x.den; } @@ -808,15 +808,15 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // Handle signs. bool change_sign = false; - const bool is_pos_num = CGAL::is_positive(x.num); - const bool is_pos_den = CGAL::is_positive(x.den); - if (!is_pos_num && !is_pos_den) { + const bool is_num_pos = CGAL::is_positive(x.num); + const bool is_den_pos = CGAL::is_positive(x.den); + if (!is_num_pos && !is_den_pos) { x.num = -x.num; x.den = -x.den; - } else if (!is_pos_num && is_pos_den) { + } else if (!is_num_pos && is_den_pos) { change_sign = true; x.num = -x.num; - } else if (is_pos_num && !is_pos_den) { + } else if (is_num_pos && !is_den_pos) { change_sign = true; x.den = -x.den; } @@ -828,10 +828,10 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const int64_t msb_diff = msb_num - msb_den; const int64_t shift = num_dbl_digits - msb_diff; - if (CGAL::is_positive(shift)) { + if (shift > 0) { CGAL_assertion(msb_diff < num_dbl_digits); x.num <<= shift; - } else if (CGAL::is_negative(shift)) { + } else if (shift < 0) { CGAL_assertion(msb_diff > num_dbl_digits); x.den <<= boost::multiprecision::detail::unsigned_abs(shift); } @@ -891,11 +891,11 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const double inf = std::numeric_limits::infinity(); CGAL_assertion(i != inf && s != inf); const int cmp = rat.compare(i); - if (CGAL::is_positive(cmp)) { + if (cmp > 0) { s = nextafter(s, +inf); CGAL_assertion(rat.compare(s) < 0); } - else if (CGAL::is_negative(cmp)) { + else if (cmp < 0) { i = nextafter(i, -inf); CGAL_assertion(rat.compare(i) > 0); } @@ -913,7 +913,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > std::pair operator()( const Type& x ) const { - #if defined(CGAL_USE_CPP_INT) && true + #if defined(CGAL_USE_CPP_INT) || true #if true // tight bounds optimized @@ -933,13 +933,10 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > #else // master version - // TODO: Remove it from here! - return get_interval_as_boost(x); - - // const Interval_nt<> quot = - // Interval_nt<>(CGAL_NTS to_interval(x.numerator())) / - // Interval_nt<>(CGAL_NTS to_interval(x.denominator())); - // return std::make_pair(quot.inf(), quot.sup()); + const Interval_nt<> quot = + Interval_nt<>(CGAL_NTS to_interval(x.numerator())) / + Interval_nt<>(CGAL_NTS to_interval(x.denominator())); + return std::make_pair(quot.inf(), quot.sup()); #endif } From 4cef3385bb257f7adf96ce4dfe77c3e61f03105e Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 10 Sep 2021 10:10:12 +0200 Subject: [PATCH 052/127] removed tabs --- Number_types/include/CGAL/Quotient.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 2e65cf958f81..505791a6edf6 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -218,12 +218,12 @@ Quotient& Quotient::operator+= (const Quotient& b) { #if 0 - + num = num * r.den + r.num * den; den *= r.den; simplify_quotient(num, den); return *this; - + #else // taken from https://github.com/boostorg/multiprecision/blob/rational_adaptor_standalone/include/boost/multiprecision/rational_adaptor.hpp#L486 @@ -273,7 +273,7 @@ Quotient::operator+= (const Quotient& b) // terms we'll be multiplying together, so there's a good chance it's a // single limb value already: // - result_num= CGAL::integral_division(t3, t4); + result_num= CGAL::integral_division(t3, t4); t3 = CGAL::integral_division( gcd, t4); t4 = t1 * t2; result_denom = t4 * t3; From 04081af582d4c898cf820ecb7a8cce58f45999d5 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 10 Sep 2021 10:28:05 +0200 Subject: [PATCH 053/127] adding +1 to msb --- Number_types/include/CGAL/Quotient.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 505791a6edf6..be4d6c5d12fe 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -812,8 +812,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(x >= 0); int64_t d = 0; double l = 0.0, u = 0.0; - const int64_t n = static_cast(msb(x)); - const int64_t num_dbl_digits = std::numeric_limits::digits - 1; + const int64_t n = static_cast(msb(x)) + 1; + const int64_t num_dbl_digits = std::numeric_limits::digits; if (n > num_dbl_digits) { d = n - num_dbl_digits; From 1a8b08c3a39c5249fd288bdf10ed5adea5c56cc2 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 10 Sep 2021 12:07:15 +0200 Subject: [PATCH 054/127] using assertion_code for q_bits, add cpp_int overload of simplify_quotient, better set default types for testsuite --- Number_types/include/CGAL/Exact_integer.h | 20 ++++++++++++++----- Number_types/include/CGAL/Quotient.h | 9 ++++++--- .../CGAL/internal/Exact_type_selector.h | 19 +++++++++++++----- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/Number_types/include/CGAL/Exact_integer.h b/Number_types/include/CGAL/Exact_integer.h index c2d6192fe32e..e844e05c9b89 100644 --- a/Number_types/include/CGAL/Exact_integer.h +++ b/Number_types/include/CGAL/Exact_integer.h @@ -50,15 +50,22 @@ typedef unspecified_type Exact_integer; #else // not DOXYGEN_RUNNING -#if CGAL_USE_GMPXX +#if true // test this type typedef boost::multiprecision::cpp_int Exact_integer; +#else // default types + +#if CGAL_USE_GMPXX + +typedef mpz_class Exact_integer; + #elif CGAL_USE_GMP + # ifdef CGAL_USE_BOOST_MP -typedef boost::multiprecision::cpp_int Exact_integer; +typedef boost::multiprecision::mpz_int Exact_integer; # else -typedef boost::multiprecision::cpp_int Exact_integer; +typedef Gmpz Exact_integer; # endif #elif CGAL_USE_LEDA @@ -67,13 +74,16 @@ typedef leda_integer Exact_integer; #elif CGAL_USE_CORE -typedef boost::multiprecision::cpp_int Exact_integer; +typedef CORE::BigInt Exact_integer; #elif defined CGAL_USE_BOOST_MP typedef boost::multiprecision::cpp_int Exact_integer; -#endif // CGAL_USE_CORE +#endif // CGAL_USE_BOOST_MP + +#endif // default types + #endif // not DOXYGEN_RUNNING } /* end namespace CGAL */ diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index be4d6c5d12fe..c9cf727da621 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -46,14 +46,17 @@ namespace CGAL { // This function is not documented as a number type requirement for now. template < typename NT > inline void -simplify_quotient(NT & a, NT & b) { +simplify_quotient(NT & a, NT & b) { } + +inline void +simplify_quotient(boost::multiprecision::cpp_int & a, boost::multiprecision::cpp_int & b) { // TODO: // - move it to the boost_mp.h // - can we use gcd only sometimes to save time? #if defined(CGAL_USE_CPP_INT) || true - const NT r = boost::multiprecision::gcd(a, b); + const boost::multiprecision::cpp_int r = boost::multiprecision::gcd(a, b); // std::cout << "r: " << r << std::endl; // std::cout << "a: " << a << std::endl; // std::cout << "b: " << b << std::endl; @@ -917,7 +920,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > NT q, r; boost::multiprecision::divide_qr(x.num, x.den, q, r); - const int64_t q_bits = static_cast(msb(q)); + CGAL_assertion_code(const int64_t q_bits = static_cast(msb(q))); CGAL_assertion(q_bits == num_dbl_digits || r != 0 /* when q_bit = num_dbl_digits - 1 */ ); if (!CGAL::is_zero(r)) { diff --git a/Number_types/include/CGAL/internal/Exact_type_selector.h b/Number_types/include/CGAL/internal/Exact_type_selector.h index 901e3bcde10f..fe70311b0fdb 100644 --- a/Number_types/include/CGAL/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/internal/Exact_type_selector.h @@ -54,13 +54,20 @@ namespace CGAL { namespace internal { // It should support the built-in types. template < typename > struct Exact_field_selector + +#if true // test this type + +{ typedef Quotient Type; } + +#else // default types + #ifdef CGAL_USE_GMPXX -{ typedef Quotient Type; }; +{ typedef mpq_class Type; }; #elif defined(CGAL_USE_GMP) # if defined(CGAL_USE_BOOST_MP) -{ typedef Quotient Type; }; +{ typedef boost::multiprecision::mpq_rational Type; }; # else -{ typedef Quotient Type; }; +{ typedef Gmpq Type; }; # endif #elif defined(CGAL_USE_LEDA) { typedef leda_rational Type; }; @@ -70,12 +77,14 @@ struct Exact_field_selector #if defined(CGAL_USE_CPP_INT) { typedef Quotient Type; }; #else -{ typedef Quotient Type; }; +{ typedef BOOST_cpp_arithmetic_kernel::Rational Type; }; # endif #else -{ typedef Quotient Type; }; +{ typedef Quotient Type; }; #endif +#endif // default types + // By default, a field is a safe choice of ring. template < typename T > struct Exact_ring_selector : Exact_field_selector < T > { }; From 577796f4a020ca64f3ea71981a89e94b483c62b1 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 10 Sep 2021 13:34:35 +0200 Subject: [PATCH 055/127] fixed wrong merge + better boost mp includes --- Number_types/include/CGAL/Exact_integer.h | 2 +- .../internal/Exact_type_selector.h | 19 +- Number_types/include/CGAL/Quotient.h | 21 +- Number_types/include/CGAL/boost_mp.h | 2 +- .../CGAL/internal/Exact_type_selector.h | 197 ------------------ 5 files changed, 26 insertions(+), 215 deletions(-) delete mode 100644 Number_types/include/CGAL/internal/Exact_type_selector.h diff --git a/Number_types/include/CGAL/Exact_integer.h b/Number_types/include/CGAL/Exact_integer.h index e844e05c9b89..bac165848fc1 100644 --- a/Number_types/include/CGAL/Exact_integer.h +++ b/Number_types/include/CGAL/Exact_integer.h @@ -50,7 +50,7 @@ typedef unspecified_type Exact_integer; #else // not DOXYGEN_RUNNING -#if true // test this type +#if true // test cpp_int typedef boost::multiprecision::cpp_int Exact_integer; diff --git a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h index 901e3bcde10f..730ca5361acb 100644 --- a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h @@ -54,13 +54,20 @@ namespace CGAL { namespace internal { // It should support the built-in types. template < typename > struct Exact_field_selector -#ifdef CGAL_USE_GMPXX + +#if true // test cpp_int + { typedef Quotient Type; }; + +#else // default types + +#ifdef CGAL_USE_GMPXX +{ typedef mpq_class Type; }; #elif defined(CGAL_USE_GMP) # if defined(CGAL_USE_BOOST_MP) -{ typedef Quotient Type; }; +{ typedef boost::multiprecision::mpq_rational Type; }; # else -{ typedef Quotient Type; }; +{ typedef Gmpq Type; }; # endif #elif defined(CGAL_USE_LEDA) { typedef leda_rational Type; }; @@ -70,12 +77,14 @@ struct Exact_field_selector #if defined(CGAL_USE_CPP_INT) { typedef Quotient Type; }; #else -{ typedef Quotient Type; }; +{ typedef BOOST_cpp_arithmetic_kernel::Rational Type; }; # endif #else -{ typedef Quotient Type; }; +{ typedef Quotient Type; }; #endif +#endif // default types + // By default, a field is a safe choice of ring. template < typename T > struct Exact_ring_selector : Exact_field_selector < T > { }; diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index c9cf727da621..3d0023c27cbd 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -31,9 +31,9 @@ #include #include +#include #include -#include #include namespace CGAL { @@ -48,14 +48,14 @@ template < typename NT > inline void simplify_quotient(NT & a, NT & b) { } +#if defined(CGAL_USE_CPP_INT) || true // test cpp_int + inline void simplify_quotient(boost::multiprecision::cpp_int & a, boost::multiprecision::cpp_int & b) { -// TODO: -// - move it to the boost_mp.h -// - can we use gcd only sometimes to save time? -#if defined(CGAL_USE_CPP_INT) || true - + // TODO: + // - move it to the boost_mp.h + // - can we use gcd only sometimes to save time? const boost::multiprecision::cpp_int r = boost::multiprecision::gcd(a, b); // std::cout << "r: " << r << std::endl; // std::cout << "a: " << a << std::endl; @@ -65,11 +65,10 @@ simplify_quotient(boost::multiprecision::cpp_int & a, boost::multiprecision::cpp b = b / r; // std::cout << "new b: " << b << std::endl; // std::cout << std::endl; - -#endif - } +#endif // CPP_INT + // This one should be replaced by some functor or tag. // Meanwhile, the class is specialized for Gmpz, mpz_class, leda_integer. template < typename NT > @@ -993,7 +992,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > std::pair operator()( const Type& x ) const { - #if defined(CGAL_USE_CPP_INT) || true + #if defined(CGAL_USE_CPP_INT) || true // test cpp_int #if true // tight bounds optimized @@ -1018,7 +1017,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > Interval_nt<>(CGAL_NTS to_interval(x.denominator())); return std::make_pair(quot.inf(), quot.sup()); - #endif + #endif // CPP_INT } }; diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index ff30b933c574..ab98f3fa7a1b 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -20,7 +20,7 @@ // MSVC had trouble with versions <= 1.69: // https://github.com/boostorg/multiprecision/issues/98 #if !defined CGAL_DO_NOT_USE_BOOST_MP && \ - (!defined _MSC_VER || BOOST_VERSION >= 107000) + (!defined _MSC_VER || BOOST_VERSION >= 107000) || true // test cpp_int #define CGAL_USE_BOOST_MP 1 #include // *ary_function diff --git a/Number_types/include/CGAL/internal/Exact_type_selector.h b/Number_types/include/CGAL/internal/Exact_type_selector.h deleted file mode 100644 index fe70311b0fdb..000000000000 --- a/Number_types/include/CGAL/internal/Exact_type_selector.h +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (c) 2004 -// Utrecht University (The Netherlands), -// ETH Zurich (Switzerland), -// INRIA Sophia-Antipolis (France), -// Max-Planck-Institute Saarbruecken (Germany), -// and Tel-Aviv University (Israel). All rights reserved. -// -// This file is part of CGAL (www.cgal.org) -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial -// -// -// Author(s) : Sylvain Pion - -#ifndef CGAL_INTERNAL_EXACT_TYPE_SELECTOR_H -#define CGAL_INTERNAL_EXACT_TYPE_SELECTOR_H - -// This is an undocumented private helper for Filtered_kernel. - -#include -#include -#include -#include - -#include -#ifdef CGAL_USE_GMP -# include -# include -# include -# include -#endif -#ifdef CGAL_USE_GMPXX -# include -#endif -#ifdef CGAL_USE_LEDA -# include -# include -# include -#endif -#ifdef CGAL_USE_CORE -// # include -namespace CORE { -class Expr; -} -#endif - -namespace CGAL { namespace internal { - -// Two classes which tell the prefered "exact number types" corresponding to a type. - -// The default template chooses mpq_class, Gmpq, leda_rational, or Quotient. -// It should support the built-in types. -template < typename > -struct Exact_field_selector - -#if true // test this type - -{ typedef Quotient Type; } - -#else // default types - -#ifdef CGAL_USE_GMPXX -{ typedef mpq_class Type; }; -#elif defined(CGAL_USE_GMP) -# if defined(CGAL_USE_BOOST_MP) -{ typedef boost::multiprecision::mpq_rational Type; }; -# else -{ typedef Gmpq Type; }; -# endif -#elif defined(CGAL_USE_LEDA) -{ typedef leda_rational Type; }; -#elif defined(CGAL_USE_BOOST_MP) -// See the discussion in https://github.com/CGAL/cgal/pull/3614 -// This is disabled for now because cpp_rational is even slower than Quotient. Quotient will be a good candidate after some polishing. -#if defined(CGAL_USE_CPP_INT) -{ typedef Quotient Type; }; -#else -{ typedef BOOST_cpp_arithmetic_kernel::Rational Type; }; -# endif -#else -{ typedef Quotient Type; }; -#endif - -#endif // default types - -// By default, a field is a safe choice of ring. -template < typename T > -struct Exact_ring_selector : Exact_field_selector < T > { }; - -template <> -struct Exact_ring_selector -#ifdef CGAL_HAS_MPZF -{ typedef Mpzf Type; }; -#elif defined(CGAL_HAS_THREADS) || !defined(CGAL_USE_GMP) -{ typedef MP_Float Type; }; -#else -{ typedef Gmpzf Type; }; -#endif - -template <> -struct Exact_ring_selector : Exact_ring_selector { }; - -template <> -struct Exact_field_selector -{ typedef Quotient Type; }; - -template <> -struct Exact_ring_selector -{ typedef MP_Float Type; }; - -template <> -struct Exact_field_selector > -{ typedef Quotient Type; }; - -// And we specialize for the following types : -#ifdef CGAL_USE_GMP -template <> -struct Exact_field_selector -{ typedef Gmpq Type; }; - -template <> -struct Exact_ring_selector -{ typedef Gmpz Type; }; - -template <> -struct Exact_ring_selector -{ typedef Gmpzf Type; }; - -template <> -struct Exact_field_selector -{ typedef Gmpq Type; }; -#endif - -#ifdef CGAL_USE_GMPXX -template <> -struct Exact_field_selector< ::mpz_class> -{ typedef ::mpq_class Type; }; - -template <> -struct Exact_ring_selector< ::mpz_class> -{ typedef ::mpz_class Type; }; - -template <> -struct Exact_field_selector< ::mpq_class> -{ typedef ::mpq_class Type; }; -#endif - -#ifdef CGAL_USE_LEDA -template <> -struct Exact_field_selector -{ typedef leda_rational Type; }; - -template <> -struct Exact_ring_selector -{ typedef leda_integer Type; }; - -template <> -struct Exact_field_selector -{ typedef leda_rational Type; }; - -template <> -struct Exact_field_selector -{ typedef leda_real Type; }; -#endif - -#ifdef CGAL_USE_CORE -template <> -struct Exact_field_selector -{ typedef CORE::Expr Type; }; -#endif - -template < typename ET > -struct Exact_field_selector > -: Exact_field_selector -{ - // We have a choice here : - // - using ET gets rid of the DAG computation as well as redoing the interval - // - using Lazy_exact_nt might use sharper intervals. - // typedef ET Type; - // typedef Lazy_exact_nt Type; -}; -template < typename ET > -struct Exact_ring_selector > -: Exact_ring_selector -{}; - -#ifndef CGAL_NO_DEPRECATED_CODE -// Added for backward compatibility -template < typename ET > -struct Exact_type_selector : Exact_field_selector< ET > {}; -#endif - -} } // namespace CGAL::internal - -#endif // CGAL_INTERNAL_EXACT_TYPE_SELECTOR_H From e456f01af51656a5792bae2e307552c3575e9b2d Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 10 Sep 2021 16:53:11 +0200 Subject: [PATCH 056/127] added boost devel + our to_interval compatible with boost rational adapter --- Number_types/include/CGAL/Exact_integer.h | 2 +- .../internal/Exact_type_selector.h | 2 +- Number_types/include/CGAL/Quotient.h | 23 ++-- Number_types/include/CGAL/boost_mp.h | 113 +++++++++++++++++- 4 files changed, 129 insertions(+), 11 deletions(-) diff --git a/Number_types/include/CGAL/Exact_integer.h b/Number_types/include/CGAL/Exact_integer.h index bac165848fc1..e1c7297d3af0 100644 --- a/Number_types/include/CGAL/Exact_integer.h +++ b/Number_types/include/CGAL/Exact_integer.h @@ -50,7 +50,7 @@ typedef unspecified_type Exact_integer; #else // not DOXYGEN_RUNNING -#if true // test cpp_int +#if false // test cpp_int typedef boost::multiprecision::cpp_int Exact_integer; diff --git a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h index 730ca5361acb..8d65b685c53d 100644 --- a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h @@ -55,7 +55,7 @@ namespace CGAL { namespace internal { template < typename > struct Exact_field_selector -#if true // test cpp_int +#if false // test cpp_int { typedef Quotient Type; }; diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 3d0023c27cbd..4ee943738b13 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -48,7 +48,7 @@ template < typename NT > inline void simplify_quotient(NT & a, NT & b) { } -#if defined(CGAL_USE_CPP_INT) || true // test cpp_int +#if defined(CGAL_USE_CPP_INT) || false // test cpp_int inline void simplify_quotient(boost::multiprecision::cpp_int & a, boost::multiprecision::cpp_int & b) { @@ -814,7 +814,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(x >= 0); int64_t d = 0; double l = 0.0, u = 0.0; - const int64_t n = static_cast(msb(x)) + 1; + const int64_t n = static_cast(boost::multiprecision::msb(x)) + 1; const int64_t num_dbl_digits = std::numeric_limits::digits; if (n > num_dbl_digits) { @@ -902,8 +902,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(x.num > 0 && x.den > 0); const int64_t num_dbl_digits = std::numeric_limits::digits - 1; - const int64_t msb_num = static_cast(msb(x.num)); - const int64_t msb_den = static_cast(msb(x.den)); + const int64_t msb_num = static_cast(boost::multiprecision::msb(x.num)); + const int64_t msb_den = static_cast(boost::multiprecision::msb(x.den)); const int64_t msb_diff = msb_num - msb_den; const int64_t shift = num_dbl_digits - msb_diff; @@ -915,12 +915,15 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > x.den <<= boost::multiprecision::detail::unsigned_abs(shift); } CGAL_assertion(num_dbl_digits == - static_cast(msb(x.num)) - static_cast(msb(x.den))); + static_cast(boost::multiprecision::msb(x.num)) - + static_cast(boost::multiprecision::msb(x.den))); NT q, r; boost::multiprecision::divide_qr(x.num, x.den, q, r); - CGAL_assertion_code(const int64_t q_bits = static_cast(msb(q))); - CGAL_assertion(q_bits == num_dbl_digits || r != 0 /* when q_bit = num_dbl_digits - 1 */ ); + CGAL_assertion_code(const int64_t q_bits = + static_cast(boost::multiprecision::msb(q))); + CGAL_assertion(q_bits == num_dbl_digits || + r != 0 /* when q_bit = num_dbl_digits - 1 */ ); if (!CGAL::is_zero(r)) { const NT p = q; @@ -992,7 +995,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > std::pair operator()( const Type& x ) const { - #if defined(CGAL_USE_CPP_INT) || true // test cpp_int + #if defined(CGAL_USE_CPP_INT) || false // test cpp_int #if true // tight bounds optimized @@ -1012,10 +1015,14 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > #else // master version + #if false const Interval_nt<> quot = Interval_nt<>(CGAL_NTS to_interval(x.numerator())) / Interval_nt<>(CGAL_NTS to_interval(x.denominator())); return std::make_pair(quot.inf(), quot.sup()); + #else // test boost devel + return std::make_pair(0.0, 0.0); + #endif #endif // CPP_INT } diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index ab98f3fa7a1b..303e0ef9ec4d 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -20,7 +20,7 @@ // MSVC had trouble with versions <= 1.69: // https://github.com/boostorg/multiprecision/issues/98 #if !defined CGAL_DO_NOT_USE_BOOST_MP && \ - (!defined _MSC_VER || BOOST_VERSION >= 107000) || true // test cpp_int + (!defined _MSC_VER || BOOST_VERSION >= 107000) || false // test cpp_int #define CGAL_USE_BOOST_MP 1 #include // *ary_function @@ -192,6 +192,115 @@ struct RET_boost_mp_base struct To_interval : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { + + #if true // test boost devel + + bool are_correct_bounds( const double l, const double u, const Type& x ) const { + + if ( + CGAL::abs(l) == std::numeric_limits::infinity() || + CGAL::abs(u) == std::numeric_limits::infinity() || + CGAL::abs(l) == 0.0 || + CGAL::abs(u) == 0.0) { + return true; + } + CGAL_assertion(CGAL::abs(l) != std::numeric_limits::infinity()); + CGAL_assertion(CGAL::abs(u) != std::numeric_limits::infinity()); + CGAL_assertion(CGAL::abs(l) != 0.0); + CGAL_assertion(CGAL::abs(u) != 0.0); + + const Type lb(l), ub(u); + CGAL_assertion(lb <= ub); + CGAL_assertion(lb <= x); + CGAL_assertion(ub >= x); + return lb <= ub && lb <= x && ub >= x; + } + + std::pair + operator()(const Type& x) const { + + // std::cout << boost::multiprecision::numerator(x) << std::endl; + // std::cout << boost::multiprecision::denominator(x) << std::endl; + + auto xnum = boost::multiprecision::numerator(x); + auto xden = boost::multiprecision::denominator(x); + + CGAL_assertion_code(const Type input = x); + double l = 0.0, u = 0.0; + if (CGAL::is_zero(xnum)) { // return [0.0, 0.0] + CGAL_assertion(are_correct_bounds(l, u, input)); + return std::make_pair(l, u); + } + CGAL_assertion(xnum != 0); + CGAL_assertion(xden != 0); + + // Handle signs. + bool change_sign = false; + const bool is_num_pos = CGAL::is_positive(xnum); + const bool is_den_pos = CGAL::is_positive(xden); + if (!is_num_pos && !is_den_pos) { + xnum = -xnum; + xden = -xden; + } else if (!is_num_pos && is_den_pos) { + change_sign = true; + xnum = -xnum; + } else if (is_num_pos && !is_den_pos) { + change_sign = true; + xden = -xden; + } + CGAL_assertion(xnum > 0 && xden > 0); + + const int64_t num_dbl_digits = std::numeric_limits::digits - 1; + const int64_t msb_num = static_cast(boost::multiprecision::msb(xnum)); + const int64_t msb_den = static_cast(boost::multiprecision::msb(xden)); + const int64_t msb_diff = msb_num - msb_den; + const int64_t shift = num_dbl_digits - msb_diff; + + if (shift > 0) { + CGAL_assertion(msb_diff < num_dbl_digits); + xnum <<= shift; + } else if (shift < 0) { + CGAL_assertion(msb_diff > num_dbl_digits); + xden <<= boost::multiprecision::detail::unsigned_abs(shift); + } + CGAL_assertion(num_dbl_digits == + static_cast(boost::multiprecision::msb(xnum)) - + static_cast(boost::multiprecision::msb(xden))); + + decltype(xnum) q, r; + boost::multiprecision::divide_qr(xnum, xden, q, r); + CGAL_assertion_code(const int64_t q_bits = + static_cast(boost::multiprecision::msb(q))); + CGAL_assertion(q_bits == num_dbl_digits || + r != 0 /* when q_bit = num_dbl_digits - 1 */ ); + + if (!CGAL::is_zero(r)) { + const decltype(q) p = q; + ++q; + CGAL_assertion(p >= 0 && q > p); + const uint64_t pp = static_cast(p); + const uint64_t qq = static_cast(q); + const Interval_nt<> intv(pp, qq); + std::tie(l, u) = ldexp(intv, -shift).pair(); + } else { + CGAL_assertion(q > 0); + const uint64_t qq = static_cast(q); + const Interval_nt<> intv(qq, qq); + std::tie(l, u) = ldexp(intv, -shift).pair(); + } + + if (change_sign) { + const double t = l; + l = -u; + u = -t; + } + + CGAL_assertion(are_correct_bounds(l, u, input)); + return std::make_pair(l, u); + } + + #else // default impl + std::pair operator()(const Type& x) const { @@ -240,6 +349,8 @@ struct RET_boost_mp_base } return std::pair (i, s); } + + #endif // default impl }; }; From 666d2f37e18b0a2dfc377488ae6d1084eeb627af Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 10 Sep 2021 18:49:23 +0200 Subject: [PATCH 057/127] using ifdefs cascade to choose different options, default is testme --- Number_types/include/CGAL/Exact_integer.h | 12 ++-- .../internal/Exact_type_selector.h | 12 ++-- Number_types/include/CGAL/Quotient.h | 62 +++++++++++++------ Number_types/include/CGAL/boost_mp.h | 27 +++----- 4 files changed, 63 insertions(+), 50 deletions(-) diff --git a/Number_types/include/CGAL/Exact_integer.h b/Number_types/include/CGAL/Exact_integer.h index e1c7297d3af0..3cc9e3cddafa 100644 --- a/Number_types/include/CGAL/Exact_integer.h +++ b/Number_types/include/CGAL/Exact_integer.h @@ -50,11 +50,7 @@ typedef unspecified_type Exact_integer; #else // not DOXYGEN_RUNNING -#if false // test cpp_int - -typedef boost::multiprecision::cpp_int Exact_integer; - -#else // default types +#if defined(CGAL_DO_NOT_RUN_TESTME) // default types #if CGAL_USE_GMPXX @@ -82,7 +78,11 @@ typedef boost::multiprecision::cpp_int Exact_integer; #endif // CGAL_USE_BOOST_MP -#endif // default types +#else // run testme + +typedef boost::multiprecision::cpp_int Exact_integer; + +#endif // run tesme #endif // not DOXYGEN_RUNNING diff --git a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h index 8d65b685c53d..0a491b1fe4cd 100644 --- a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h @@ -55,11 +55,7 @@ namespace CGAL { namespace internal { template < typename > struct Exact_field_selector -#if false // test cpp_int - -{ typedef Quotient Type; }; - -#else // default types +#if defined(CGAL_DO_NOT_RUN_TESTME) // default types #ifdef CGAL_USE_GMPXX { typedef mpq_class Type; }; @@ -83,7 +79,11 @@ struct Exact_field_selector { typedef Quotient Type; }; #endif -#endif // default types +#else // run testme + +{ typedef Quotient Type; }; + +#endif // run testme // By default, a field is a safe choice of ring. template < typename T > diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 4ee943738b13..cb6e67742cde 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -31,7 +31,10 @@ #include #include + +#if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) #include +#endif #include #include @@ -48,7 +51,7 @@ template < typename NT > inline void simplify_quotient(NT & a, NT & b) { } -#if defined(CGAL_USE_CPP_INT) || false // test cpp_int +#if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) inline void simplify_quotient(boost::multiprecision::cpp_int & a, boost::multiprecision::cpp_int & b) { @@ -214,12 +217,14 @@ Quotient::normalize() return *this; } +#if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) + template CGAL_MEDIUM_INLINE Quotient& Quotient::operator+= (const Quotient& b) { -#if 0 +#if false num = num * r.den + r.num * den; den *= r.den; @@ -301,6 +306,20 @@ Quotient::operator+= (const Quotient& b) } +#else // default impl + +template +CGAL_MEDIUM_INLINE +Quotient& +Quotient::operator+= (const Quotient& r) +{ + num = num * r.den + r.num * den; + den *= r.den; + simplify_quotient(num, den); + return *this; +} + +#endif // default impl template CGAL_MEDIUM_INLINE @@ -809,6 +828,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > return lb <= ub && lb <= x && ub >= x; } + #if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) + std::pair< Interval_nt<>, int64_t > get_interval_exp( NT& x ) const { CGAL_assertion(x >= 0); @@ -993,38 +1014,39 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } } - std::pair operator()( const Type& x ) const { - - #if defined(CGAL_USE_CPP_INT) || false // test cpp_int - - #if true // tight bounds optimized + #endif // CPP_INT - // Seems to be less precise and we rarely end up with an interval [d,d] - // even for numbers, which are exactly representable as double. - // return get_interval_as_gmpzf(x); + std::pair operator()( const Type& x ) const { - // Works slightly better than the first one. - return get_interval_as_boost(x); + #if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) - #else // cpp_rational based tight bounds + // Option 1. + // Seems to be less precise and we rarely end up with an interval [d,d] + // even for numbers, which are exactly representable as double. + // They also pass all tests and benches. + // return get_interval_as_gmpzf(x); - // These are slower but stable bounds, pass all tests and benches. - return get_interval_using_cpp_rational(x); + // Option 2. + // Works slightly better than the first one. + // They also pass all tests and benches. + return get_interval_as_boost(x); - #endif + // Option 3. + // These are slower but stable bounds, pass all tests and benches. + // return get_interval_using_cpp_rational(x); #else // master version - #if false + #if defined(CGAL_USE_TO_INTERVAL_WITH_BOOST) + return std::make_pair(0.0, 0.0); + #else const Interval_nt<> quot = Interval_nt<>(CGAL_NTS to_interval(x.numerator())) / Interval_nt<>(CGAL_NTS to_interval(x.denominator())); return std::make_pair(quot.inf(), quot.sup()); - #else // test boost devel - return std::make_pair(0.0, 0.0); #endif - #endif // CPP_INT + #endif // master version } }; diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 303e0ef9ec4d..447d0348cc84 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -20,7 +20,7 @@ // MSVC had trouble with versions <= 1.69: // https://github.com/boostorg/multiprecision/issues/98 #if !defined CGAL_DO_NOT_USE_BOOST_MP && \ - (!defined _MSC_VER || BOOST_VERSION >= 107000) || false // test cpp_int + (!defined _MSC_VER || BOOST_VERSION >= 107000) || !defined(CGAL_DO_NOT_RUN_TESTME) #define CGAL_USE_BOOST_MP 1 #include // *ary_function @@ -193,7 +193,7 @@ struct RET_boost_mp_base struct To_interval : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { - #if true // test boost devel + #if defined(CGAL_USE_TO_INTERVAL_WITH_BOOST) // test boost devel bool are_correct_bounds( const double l, const double u, const Type& x ) const { @@ -312,22 +312,13 @@ struct RET_boost_mp_base // assume the conversion is within 1 ulp // adding IA::smallest() doesn't work because inf-e=inf, even rounded down. - #if defined(CGAL_USE_CPP_INT) && true // should always be true because it is a bug on CGAL/macOS - - // We must use to_nearest with cpp_int. - double i; - { - Protect_FPU_rounding P(CGAL_FE_TONEAREST); - i = x.template convert_to(); - } - double s = i; - - #else // master version - - double i = x.template convert_to(); - double s = i; - - #endif + // We must use to_nearest with cpp_int. + double i; + { + Protect_FPU_rounding P(CGAL_FE_TONEAREST); + i = x.template convert_to(); + } + double s = i; // std::cout << "x: " << x << std::endl; // std::cout << "i: " << i << std::endl; From 72906a2445d07c8e8d7312bc8ee5d96dfc2a0a26 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 13 Sep 2021 11:26:01 +0200 Subject: [PATCH 058/127] fixed some errors/warnings from testme --- Number_types/include/CGAL/Quotient.h | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index cb6e67742cde..cdda40cde1ed 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -34,6 +34,10 @@ #if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) #include +// TODO: The two below will be removed when we move simplify_quotient() to boost_mp, +// where it is supposed to be. +#include +#include #endif #include @@ -53,7 +57,11 @@ simplify_quotient(NT & a, NT & b) { } #if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) -inline void +// WARNINGS: +// https://cgal.geometryfactory.com/~cgaltest/test_suite/TESTRESULTS/CGAL-5.4-Ic-5937/Convex_decomposition_3/TestReport_cgaltest_Ubuntu-gcc7.gz +// https://cgal.geometryfactory.com/~cgaltest/test_suite/TESTRESULTS/CGAL-5.4-Ic-5937/Convex_decomposition_3/TestReport_cgaltest_arm64-apple_bigsur_clang1200-release-64bits.gz +// See boost includes above. Should make it work, I guess. +void simplify_quotient(boost::multiprecision::cpp_int & a, boost::multiprecision::cpp_int & b) { // TODO: @@ -222,9 +230,9 @@ Quotient::normalize() template CGAL_MEDIUM_INLINE Quotient& -Quotient::operator+= (const Quotient& b) +Quotient::operator+= (const Quotient& r) { -#if false +#if true num = num * r.den + r.num * den; den *= r.den; @@ -242,10 +250,14 @@ Quotient::operator+= (const Quotient& b) // // Begin by getting the gcd of the 2 denominators: // + // ERROR: no matching function for call to gcd! We skip this implementation for the moment! gcd = boost::multiprecision::gcd(denominator(), b.denominator()); // // Do we have gcd > 1: // + // WARNING: logical not is only applied to the left hand side of comparison and + // ERROR: no match for operator! + // We skip this implementation for the moment! if (! gcd == 1) { // @@ -265,6 +277,7 @@ Quotient::operator+= (const Quotient& b) // // Get the gcd of gcd and our numerator (t3): // + // ERROR: no matching function for call to gcd! We skip this implementation for the moment! t4 = boost::multiprecision::gcd(t3, gcd); if (t4 == 1) { @@ -946,18 +959,23 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(q_bits == num_dbl_digits || r != 0 /* when q_bit = num_dbl_digits - 1 */ ); + // WARNING: https://cgal.geometryfactory.com/~cgaltest/test_suite/TESTRESULTS/CGAL-5.4-Ic-5937/Combinatorial_map/TestReport_cgaltest_VS-19.gz + // Interval_nt is defined only for double, see impl. if (!CGAL::is_zero(r)) { const NT p = q; ++q; CGAL_assertion(p >= 0 && q > p); const uint64_t pp = static_cast(p); const uint64_t qq = static_cast(q); - const Interval_nt<> intv(pp, qq); + const double pp_dbl = static_cast(pp); + const double qq_dbl = static_cast(qq); + const Interval_nt<> intv(pp_dbl, qq_dbl); std::tie(l, u) = ldexp(intv, -shift).pair(); } else { CGAL_assertion(q > 0); const uint64_t qq = static_cast(q); - const Interval_nt<> intv(qq, qq); + const double qq_dbl = static_cast(qq); + const Interval_nt<> intv(qq_dbl, qq_dbl); std::tie(l, u) = ldexp(intv, -shift).pair(); } From 1e5f3615f51f4063382d84949dc433bfe5b1b933 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 13 Sep 2021 12:20:10 +0200 Subject: [PATCH 059/127] marc's review --- Number_types/include/CGAL/Quotient.h | 47 ++++++++++++++-------------- Number_types/include/CGAL/boost_mp.h | 30 ++++++++---------- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index cdda40cde1ed..8a8e9efdb7df 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -68,14 +68,8 @@ simplify_quotient(boost::multiprecision::cpp_int & a, boost::multiprecision::cpp // - move it to the boost_mp.h // - can we use gcd only sometimes to save time? const boost::multiprecision::cpp_int r = boost::multiprecision::gcd(a, b); - // std::cout << "r: " << r << std::endl; - // std::cout << "a: " << a << std::endl; - // std::cout << "b: " << b << std::endl; - a = a / r; - // std::cout << "new a: " << a << std::endl; - b = b / r; - // std::cout << "new b: " << b << std::endl; - // std::cout << std::endl; + a /= r; + b /= r; } #endif // CPP_INT @@ -835,7 +829,6 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(CGAL::abs(u) != 0.0); const Type lb(l), ub(u); - CGAL_assertion(lb <= ub); CGAL_assertion(lb <= x); CGAL_assertion(ub >= x); return lb <= ub && lb <= x && ub >= x; @@ -845,7 +838,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > std::pair< Interval_nt<>, int64_t > get_interval_exp( NT& x ) const { - CGAL_assertion(x >= 0); + CGAL_assertion(CGAL::is_positive(x)); int64_t d = 0; double l = 0.0, u = 0.0; const int64_t n = static_cast(boost::multiprecision::msb(x)) + 1; @@ -853,12 +846,16 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > if (n > num_dbl_digits) { d = n - num_dbl_digits; - x = x >> d; - const NT y = x + 1; - l = static_cast(x); - u = static_cast(y); + x >>= d; + const uint64_t xx = static_cast(x); + const uint64_t yy = xx + 1; + CGAL_assertion(xx > 0 && yy > xx); + l = static_cast(xx); + u = static_cast(yy); } else { - l = static_cast(x); + const uint64_t xx = static_cast(x); + CGAL_assertion(xx > 0); + l = static_cast(xx); u = l; } return std::make_pair( Interval_nt<>(l, u), d ); @@ -872,8 +869,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(are_correct_bounds(l, u, input)); return std::make_pair(l, u); } - CGAL_assertion(x.num != 0); - CGAL_assertion(x.den != 0); + CGAL_assertion(!CGAL::is_zero(x.num)); + CGAL_assertion(!CGAL::is_zero(x.den)); // Handle signs. bool change_sign = false; @@ -889,7 +886,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > change_sign = true; x.den = -x.den; } - CGAL_assertion(x.num > 0 && x.den > 0); + CGAL_assertion(CGAL::is_positive(x.num) && CGAL::is_positive(x.den)); const auto num = get_interval_exp(x.num); const auto den = get_interval_exp(x.den); @@ -916,8 +913,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(are_correct_bounds(l, u, input)); return std::make_pair(l, u); } - CGAL_assertion(x.num != 0); - CGAL_assertion(x.den != 0); + CGAL_assertion(!CGAL::is_zero(x.num)); + CGAL_assertion(!CGAL::is_zero(x.den)); // Handle signs. bool change_sign = false; @@ -933,7 +930,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > change_sign = true; x.den = -x.den; } - CGAL_assertion(x.num > 0 && x.den > 0); + CGAL_assertion(CGAL::is_positive(x.num) && CGAL::is_positive(x.den)); const int64_t num_dbl_digits = std::numeric_limits::digits - 1; const int64_t msb_num = static_cast(boost::multiprecision::msb(x.num)); @@ -960,20 +957,23 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > r != 0 /* when q_bit = num_dbl_digits - 1 */ ); // WARNING: https://cgal.geometryfactory.com/~cgaltest/test_suite/TESTRESULTS/CGAL-5.4-Ic-5937/Combinatorial_map/TestReport_cgaltest_VS-19.gz - // Interval_nt is defined only for double, see impl. + // Fixed: Interval_nt is defined only for double, see impl below. if (!CGAL::is_zero(r)) { const NT p = q; ++q; CGAL_assertion(p >= 0 && q > p); const uint64_t pp = static_cast(p); const uint64_t qq = static_cast(q); + CGAL_assertion(pp >= 0 && qq > pp); const double pp_dbl = static_cast(pp); const double qq_dbl = static_cast(qq); const Interval_nt<> intv(pp_dbl, qq_dbl); std::tie(l, u) = ldexp(intv, -shift).pair(); } else { + CGAL_assertion(CGAL::is_zero(r)); CGAL_assertion(q > 0); const uint64_t qq = static_cast(q); + CGAL_assertion(qq > 0); const double qq_dbl = static_cast(qq); const Interval_nt<> intv(qq_dbl, qq_dbl); std::tie(l, u) = ldexp(intv, -shift).pair(); @@ -999,10 +999,11 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // Seems fast enough because this conversion happens // only a few times during the run, at least for NEF. boost::multiprecision::cpp_rational rat; - CGAL_assertion(x.den != 0); + CGAL_assertion(!CGAL::is_zero(x.den)); if (CGAL::is_negative(x.den)) { rat = boost::multiprecision::cpp_rational(-x.num, -x.den); } else { + CGAL_assertion(CGAL::is_positive(x.den)); rat = boost::multiprecision::cpp_rational( x.num, x.den); } diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 447d0348cc84..d85457f6eab4 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -210,7 +210,6 @@ struct RET_boost_mp_base CGAL_assertion(CGAL::abs(u) != 0.0); const Type lb(l), ub(u); - CGAL_assertion(lb <= ub); CGAL_assertion(lb <= x); CGAL_assertion(ub >= x); return lb <= ub && lb <= x && ub >= x; @@ -219,9 +218,6 @@ struct RET_boost_mp_base std::pair operator()(const Type& x) const { - // std::cout << boost::multiprecision::numerator(x) << std::endl; - // std::cout << boost::multiprecision::denominator(x) << std::endl; - auto xnum = boost::multiprecision::numerator(x); auto xden = boost::multiprecision::denominator(x); @@ -231,8 +227,8 @@ struct RET_boost_mp_base CGAL_assertion(are_correct_bounds(l, u, input)); return std::make_pair(l, u); } - CGAL_assertion(xnum != 0); - CGAL_assertion(xden != 0); + CGAL_assertion(!CGAL::is_zero(xnum)); + CGAL_assertion(!CGAL::is_zero(xden)); // Handle signs. bool change_sign = false; @@ -248,7 +244,7 @@ struct RET_boost_mp_base change_sign = true; xden = -xden; } - CGAL_assertion(xnum > 0 && xden > 0); + CGAL_assertion(CGAL::is_positive(xnum) && CGAL::is_positive(xden)); const int64_t num_dbl_digits = std::numeric_limits::digits - 1; const int64_t msb_num = static_cast(boost::multiprecision::msb(xnum)); @@ -274,18 +270,26 @@ struct RET_boost_mp_base CGAL_assertion(q_bits == num_dbl_digits || r != 0 /* when q_bit = num_dbl_digits - 1 */ ); + // WARNING: https://cgal.geometryfactory.com/~cgaltest/test_suite/TESTRESULTS/CGAL-5.4-Ic-5937/Combinatorial_map/TestReport_cgaltest_VS-19.gz + // Fixed: Interval_nt is defined only for double, see impl below. if (!CGAL::is_zero(r)) { const decltype(q) p = q; ++q; CGAL_assertion(p >= 0 && q > p); const uint64_t pp = static_cast(p); const uint64_t qq = static_cast(q); - const Interval_nt<> intv(pp, qq); + CGAL_assertion(pp >= 0 && qq > pp); + const double pp_dbl = static_cast(pp); + const double qq_dbl = static_cast(qq); + const Interval_nt<> intv(pp_dbl, qq_dbl); std::tie(l, u) = ldexp(intv, -shift).pair(); } else { + CGAL_assertion(CGAL::is_zero(r)); CGAL_assertion(q > 0); const uint64_t qq = static_cast(q); - const Interval_nt<> intv(qq, qq); + CGAL_assertion(qq > 0); + const double qq_dbl = static_cast(qq); + const Interval_nt<> intv(qq_dbl, qq_dbl); std::tie(l, u) = ldexp(intv, -shift).pair(); } @@ -304,10 +308,6 @@ struct RET_boost_mp_base std::pair operator()(const Type& x) const { - // std::cout << "- before test minimal nextafter ... " << std::endl; - // test_minimal_nextafter(); - // std::cout << "- after test minimal nextafter ... " << std::endl; - // See if https://github.com/boostorg/multiprecision/issues/108 suggests anything better // assume the conversion is within 1 ulp // adding IA::smallest() doesn't work because inf-e=inf, even rounded down. @@ -320,10 +320,6 @@ struct RET_boost_mp_base } double s = i; - // std::cout << "x: " << x << std::endl; - // std::cout << "i: " << i << std::endl; - // std::cout << "s: " << s << std::endl; - const double inf = std::numeric_limits::infinity(); CGAL_assertion(i != inf && s != inf); From c879a827eb65ea611005e166f57baf9a04becfed Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 13 Sep 2021 14:18:37 +0200 Subject: [PATCH 060/127] compare impl 1/2/3 of to_interval --- Number_types/include/CGAL/Quotient.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 8a8e9efdb7df..a9e3c4a37971 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -1042,16 +1042,18 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // Option 1. // Seems to be less precise and we rarely end up with an interval [d,d] // even for numbers, which are exactly representable as double. - // They also pass all tests and benches. + // Otherwise, it is quite similar to the results of the option 3. // return get_interval_as_gmpzf(x); // Option 2. // Works slightly better than the first one. - // They also pass all tests and benches. + // It always returns a correct interval, but it is sometimes less tight + // than the one from the option 3. return get_interval_as_boost(x); // Option 3. - // These are slower but stable bounds, pass all tests and benches. + // This seems to give the tightest intervals, but it does not handle inf + // for the moment. // return get_interval_using_cpp_rational(x); #else // master version From 2f2e20aba74b32340b7840a95356c0ce1d73f18e Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 13 Sep 2021 14:29:40 +0200 Subject: [PATCH 061/127] fixed duplicate symbol error --- Number_types/include/CGAL/Quotient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index a9e3c4a37971..2393caa59a39 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -61,7 +61,7 @@ simplify_quotient(NT & a, NT & b) { } // https://cgal.geometryfactory.com/~cgaltest/test_suite/TESTRESULTS/CGAL-5.4-Ic-5937/Convex_decomposition_3/TestReport_cgaltest_Ubuntu-gcc7.gz // https://cgal.geometryfactory.com/~cgaltest/test_suite/TESTRESULTS/CGAL-5.4-Ic-5937/Convex_decomposition_3/TestReport_cgaltest_arm64-apple_bigsur_clang1200-release-64bits.gz // See boost includes above. Should make it work, I guess. -void +inline void simplify_quotient(boost::multiprecision::cpp_int & a, boost::multiprecision::cpp_int & b) { // TODO: From 73d850dde11f4c9c67bdf63d75f1e31464f2f63f Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 13 Sep 2021 17:15:26 +0200 Subject: [PATCH 062/127] optimized impl 3 of to_interval --- Number_types/include/CGAL/Quotient.h | 85 +++++++++++++++------------- Number_types/include/CGAL/boost_mp.h | 8 +-- 2 files changed, 49 insertions(+), 44 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 2393caa59a39..80b334ef373c 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -989,48 +989,54 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > return std::make_pair(l, u); } + std::pair interval_from_cpp_rational( const Type& x ) const { + + // Seems fast enough because this conversion happens + // only a few times during the run, at least for NEF. + boost::multiprecision::cpp_rational rat; + CGAL_assertion(!CGAL::is_zero(x.den)); + if (CGAL::is_negative(x.den)) { + rat = boost::multiprecision::cpp_rational(-x.num, -x.den); + } else { + CGAL_assertion(CGAL::is_positive(x.den)); + rat = boost::multiprecision::cpp_rational( x.num, x.den); + } + + double l, u; + std::tie(l, u) = to_interval(rat); + const double inf = std::numeric_limits::infinity(); + + if (l == +inf) { + l = std::numeric_limits::max(); + CGAL_assertion(u == +inf); + } else if (u == -inf) { + u = std::numeric_limits::lowest(); + CGAL_assertion(l == -inf); + } + + CGAL_assertion(are_correct_bounds(l, u, x)); + return std::make_pair(l, u); + } + std::pair get_interval_using_cpp_rational( const Type& x ) const { const double inf = std::numeric_limits::infinity(); - const double xn = x.num.template convert_to(); - const double xd = x.den.template convert_to(); - if (xn == inf || xd == inf) { - - // Seems fast enough because this conversion happens - // only a few times during the run, at least for NEF. - boost::multiprecision::cpp_rational rat; - CGAL_assertion(!CGAL::is_zero(x.den)); - if (CGAL::is_negative(x.den)) { - rat = boost::multiprecision::cpp_rational(-x.num, -x.den); - } else { - CGAL_assertion(CGAL::is_positive(x.den)); - rat = boost::multiprecision::cpp_rational( x.num, x.den); - } - - double i = static_cast(rat); - double s = i; - - const double inf = std::numeric_limits::infinity(); - CGAL_assertion(i != inf && s != inf); - const int cmp = rat.compare(i); - if (cmp > 0) { - s = nextafter(s, +inf); - CGAL_assertion(rat.compare(s) < 0); - } - else if (cmp < 0) { - i = nextafter(i, -inf); - CGAL_assertion(rat.compare(i) > 0); - } - CGAL_assertion(are_correct_bounds(i, s, x)); - return std::make_pair(i, s); - } else { + const Interval_nt<> xn = Interval_nt<>(CGAL_NTS to_interval(x.num)); + if (CGAL::abs(xn.inf()) == inf || CGAL::abs(xn.sup()) == inf) { + return interval_from_cpp_rational(x); + } + CGAL_assertion(CGAL::abs(xn.inf()) != inf && CGAL::abs(xn.sup()) != inf); - const Interval_nt<> quot = - Interval_nt<>(CGAL_NTS to_interval(x.num)) / - Interval_nt<>(CGAL_NTS to_interval(x.den)); - return std::make_pair(quot.inf(), quot.sup()); + const Interval_nt<> xd = Interval_nt<>(CGAL_NTS to_interval(x.den)); + if (CGAL::abs(xd.inf()) == inf || CGAL::abs(xd.sup()) == inf) { + return interval_from_cpp_rational(x); } + CGAL_assertion(CGAL::abs(xd.inf()) != inf && CGAL::abs(xd.sup()) != inf); + + const Interval_nt<> quot = xn / xd; + CGAL_assertion(are_correct_bounds(quot.inf(), quot.sup(), x)); + return std::make_pair(quot.inf(), quot.sup()); } #endif // CPP_INT @@ -1049,12 +1055,11 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // Works slightly better than the first one. // It always returns a correct interval, but it is sometimes less tight // than the one from the option 3. - return get_interval_as_boost(x); + // return get_interval_as_boost(x); // Option 3. - // This seems to give the tightest intervals, but it does not handle inf - // for the moment. - // return get_interval_using_cpp_rational(x); + // This seems to give the tightest intervals. + return get_interval_using_cpp_rational(x); #else // master version diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index d85457f6eab4..4868f8b5c7f0 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -314,13 +314,13 @@ struct RET_boost_mp_base // We must use to_nearest with cpp_int. double i; + const double inf = std::numeric_limits::infinity(); { Protect_FPU_rounding P(CGAL_FE_TONEAREST); - i = x.template convert_to(); + i = static_cast(x); + if (CGAL::abs(i) == inf) return std::make_pair(i, i); } double s = i; - - const double inf = std::numeric_limits::infinity(); CGAL_assertion(i != inf && s != inf); // Throws uncaught exception: Cannot convert a non-finite number to an integer. @@ -334,7 +334,7 @@ struct RET_boost_mp_base i = nextafter(i, -inf); CGAL_assertion(x.compare(i) > 0); } - return std::pair (i, s); + return std::pair(i, s); } #endif // default impl From c4bfbb4a780a983cd9d0c721508cff35506638e1 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 14 Sep 2021 10:16:39 +0200 Subject: [PATCH 063/127] cleanup --- Number_types/include/CGAL/Quotient.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 80b334ef373c..e534b25538cf 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -1055,11 +1055,11 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // Works slightly better than the first one. // It always returns a correct interval, but it is sometimes less tight // than the one from the option 3. - // return get_interval_as_boost(x); + return get_interval_as_boost(x); // Option 3. // This seems to give the tightest intervals. - return get_interval_using_cpp_rational(x); + // return get_interval_using_cpp_rational(x); #else // master version From dfb12965af7f34974f51d1e768d08d54b3a1bf21 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 14 Sep 2021 14:49:05 +0200 Subject: [PATCH 064/127] removed wrong assertion --- Number_types/include/CGAL/Quotient.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index e534b25538cf..a790219070c5 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -953,8 +953,6 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > boost::multiprecision::divide_qr(x.num, x.den, q, r); CGAL_assertion_code(const int64_t q_bits = static_cast(boost::multiprecision::msb(q))); - CGAL_assertion(q_bits == num_dbl_digits || - r != 0 /* when q_bit = num_dbl_digits - 1 */ ); // WARNING: https://cgal.geometryfactory.com/~cgaltest/test_suite/TESTRESULTS/CGAL-5.4-Ic-5937/Combinatorial_map/TestReport_cgaltest_VS-19.gz // Fixed: Interval_nt is defined only for double, see impl below. From c893f6ab484ca2a3d3485e1a37d50648820ad465 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 15 Sep 2021 10:51:44 +0200 Subject: [PATCH 065/127] add tightness check --- Number_types/include/CGAL/Quotient.h | 59 +++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index a790219070c5..6c36d04dc49d 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -831,7 +831,12 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const Type lb(l), ub(u); CGAL_assertion(lb <= x); CGAL_assertion(ub >= x); - return lb <= ub && lb <= x && ub >= x; + const bool are_bounds_respected = (lb <= x && x <= ub); + + const double inf = std::numeric_limits::infinity(); + CGAL_assertion(u == l || u == std::nextafter(l, +inf)); + bool are_bounds_tight = (u == l || u == std::nextafter(l, +inf)); + return are_bounds_respected && are_bounds_tight; } #if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) @@ -938,6 +943,14 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const int64_t msb_diff = msb_num - msb_den; const int64_t shift = num_dbl_digits - msb_diff; + // std::cout << "msb num: " << msb_num << std::endl; + // std::cout << "msb den: " << msb_den << std::endl; + // std::cout << "msb diff: " << msb_diff << std::endl; + // std::cout << "shift: " << shift << std::endl; + + // std::cout << "x num: " << x.num << std::endl; + // std::cout << "x den: " << x.den << std::endl; + if (shift > 0) { CGAL_assertion(msb_diff < num_dbl_digits); x.num <<= shift; @@ -954,8 +967,40 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion_code(const int64_t q_bits = static_cast(boost::multiprecision::msb(q))); + // std::cout << "x num shift: " << x.num << std::endl; + // std::cout << "x den shift: " << x.den << std::endl; + + // std::cout << "q: " << q << std::endl; + // std::cout << "r: " << r << std::endl; + // WARNING: https://cgal.geometryfactory.com/~cgaltest/test_suite/TESTRESULTS/CGAL-5.4-Ic-5937/Combinatorial_map/TestReport_cgaltest_VS-19.gz // Fixed: Interval_nt is defined only for double, see impl below. + // if (q_bits == num_dbl_digits - 1) { + // if (!CGAL::is_zero(r)) { + // q <<= 1; + // const NT p = q; + // ++q; + // ++shift; + // const uint64_t pp = static_cast(p); + // const uint64_t qq = static_cast(q); + // CGAL_assertion(pp >= 0 && qq > pp); + // const double pp_dbl = static_cast(pp); + // const double qq_dbl = static_cast(qq); + + // // std::cout << "msb p: " << msb(p) << std::endl; + // // std::cout << "msb q: " << msb(q) << std::endl; + + // // std::cout << "pp_dbl: " << pp_dbl << std::endl; + // // std::cout << "qq_dbl: " << qq_dbl << std::endl; + + // const Interval_nt<> intv(pp_dbl, qq_dbl); + // std::tie(l, u) = ldexp(intv, -shift).pair(); + + // } else { + + // } + // } else { + if (!CGAL::is_zero(r)) { const NT p = q; ++q; @@ -965,6 +1010,13 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(pp >= 0 && qq > pp); const double pp_dbl = static_cast(pp); const double qq_dbl = static_cast(qq); + + // std::cout << "msb p: " << msb(p) << std::endl; + // std::cout << "msb q: " << msb(q) << std::endl; + + // std::cout << "pp_dbl: " << pp_dbl << std::endl; + // std::cout << "qq_dbl: " << qq_dbl << std::endl; + const Interval_nt<> intv(pp_dbl, qq_dbl); std::tie(l, u) = ldexp(intv, -shift).pair(); } else { @@ -976,6 +1028,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const Interval_nt<> intv(qq_dbl, qq_dbl); std::tie(l, u) = ldexp(intv, -shift).pair(); } + // } if (change_sign) { const double t = l; @@ -983,6 +1036,10 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > u = -t; } + // std::cout << "l: " << l << std::endl; + // std::cout << "u: " << u << std::endl; + // std::cout << "nextafter: " << nextafter(l, +std::numeric_limits::infinity()) << std::endl; + CGAL_assertion(are_correct_bounds(l, u, input)); return std::make_pair(l, u); } From 4bb8beeaa03f44041b61e32b69b480ad40bb3b11 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 15 Sep 2021 11:37:05 +0200 Subject: [PATCH 066/127] added case with 51 bits to boost to_interval --- Number_types/include/CGAL/Quotient.h | 162 ++++++++++++++------------- 1 file changed, 87 insertions(+), 75 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 6c36d04dc49d..bb0a2b8d89c4 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -910,6 +910,43 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > return std::make_pair(l, u); } + std::pair get_1ulp_interval( const int64_t shift, const NT& p ) const { + + std::cout << "- 1ulp interval: " << std::endl; + + CGAL_assertion(p >= 0); + const uint64_t pp = static_cast(p); + const uint64_t qq = static_cast(pp + 1); + + CGAL_assertion(pp >= 0); + CGAL_assertion(qq > pp); + const double pp_dbl = static_cast(pp); + const double qq_dbl = static_cast(qq); + + std::cout << "pp_dbl: " << pp_dbl << std::endl; + std::cout << "qq_dbl: " << qq_dbl << std::endl; + + const Interval_nt<> intv(pp_dbl, qq_dbl); + return ldexp(intv, -shift).pair(); + } + + std::pair get_0ulp_interval( const int64_t shift, const NT& p ) const { + + std::cout << "- 0ulp interval: " << std::endl; + + CGAL_assertion(p >= 0); + const uint64_t pp = static_cast(p); + + CGAL_assertion(pp >= 0); + const double pp_dbl = static_cast(pp); + + std::cout << "pp_dbl: " << pp_dbl << std::endl; + std::cout << "qq_dbl: " << pp_dbl << std::endl; + + const Interval_nt<> intv(pp_dbl, pp_dbl); + return ldexp(intv, -shift).pair(); + } + std::pair get_interval_as_boost( Type x ) const { CGAL_assertion_code(const Type input = x); @@ -941,15 +978,15 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const int64_t msb_num = static_cast(boost::multiprecision::msb(x.num)); const int64_t msb_den = static_cast(boost::multiprecision::msb(x.den)); const int64_t msb_diff = msb_num - msb_den; - const int64_t shift = num_dbl_digits - msb_diff; + int64_t shift = num_dbl_digits - msb_diff; - // std::cout << "msb num: " << msb_num << std::endl; - // std::cout << "msb den: " << msb_den << std::endl; - // std::cout << "msb diff: " << msb_diff << std::endl; - // std::cout << "shift: " << shift << std::endl; + std::cout << "msb num: " << msb_num << std::endl; + std::cout << "msb den: " << msb_den << std::endl; + std::cout << "msb diff: " << msb_diff << std::endl; + std::cout << " shift: " << shift << std::endl; - // std::cout << "x num: " << x.num << std::endl; - // std::cout << "x den: " << x.den << std::endl; + std::cout << "x num: " << x.num << std::endl; + std::cout << "x den: " << x.den << std::endl; if (shift > 0) { CGAL_assertion(msb_diff < num_dbl_digits); @@ -962,73 +999,46 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > static_cast(boost::multiprecision::msb(x.num)) - static_cast(boost::multiprecision::msb(x.den))); - NT q, r; - boost::multiprecision::divide_qr(x.num, x.den, q, r); - CGAL_assertion_code(const int64_t q_bits = - static_cast(boost::multiprecision::msb(q))); - - // std::cout << "x num shift: " << x.num << std::endl; - // std::cout << "x den shift: " << x.den << std::endl; - - // std::cout << "q: " << q << std::endl; - // std::cout << "r: " << r << std::endl; - - // WARNING: https://cgal.geometryfactory.com/~cgaltest/test_suite/TESTRESULTS/CGAL-5.4-Ic-5937/Combinatorial_map/TestReport_cgaltest_VS-19.gz - // Fixed: Interval_nt is defined only for double, see impl below. - // if (q_bits == num_dbl_digits - 1) { - // if (!CGAL::is_zero(r)) { - // q <<= 1; - // const NT p = q; - // ++q; - // ++shift; - // const uint64_t pp = static_cast(p); - // const uint64_t qq = static_cast(q); - // CGAL_assertion(pp >= 0 && qq > pp); - // const double pp_dbl = static_cast(pp); - // const double qq_dbl = static_cast(qq); - - // // std::cout << "msb p: " << msb(p) << std::endl; - // // std::cout << "msb q: " << msb(q) << std::endl; - - // // std::cout << "pp_dbl: " << pp_dbl << std::endl; - // // std::cout << "qq_dbl: " << qq_dbl << std::endl; - - // const Interval_nt<> intv(pp_dbl, qq_dbl); - // std::tie(l, u) = ldexp(intv, -shift).pair(); - - // } else { - - // } - // } else { - - if (!CGAL::is_zero(r)) { - const NT p = q; - ++q; - CGAL_assertion(p >= 0 && q > p); - const uint64_t pp = static_cast(p); - const uint64_t qq = static_cast(q); - CGAL_assertion(pp >= 0 && qq > pp); - const double pp_dbl = static_cast(pp); - const double qq_dbl = static_cast(qq); - - // std::cout << "msb p: " << msb(p) << std::endl; - // std::cout << "msb q: " << msb(q) << std::endl; - - // std::cout << "pp_dbl: " << pp_dbl << std::endl; - // std::cout << "qq_dbl: " << qq_dbl << std::endl; - - const Interval_nt<> intv(pp_dbl, qq_dbl); - std::tie(l, u) = ldexp(intv, -shift).pair(); + NT p, r; + boost::multiprecision::divide_qr(x.num, x.den, p, r); + CGAL_assertion_code(const int64_t p_bits = + static_cast(boost::multiprecision::msb(p))); + + std::cout << "x num shifted: " << x.num << std::endl; + std::cout << "x den shifted: " << x.den << std::endl; + + std::cout << "p bits: " << boost::multiprecision::msb(p) << std::endl; + + std::cout << "p: " << p << std::endl; + std::cout << "r: " << r << std::endl; + + if (r == 0) { + std::cout << "- case r = 0" << std::endl; + std::tie(l, u) = get_0ulp_interval(shift, p); } else { - CGAL_assertion(CGAL::is_zero(r)); - CGAL_assertion(q > 0); - const uint64_t qq = static_cast(q); - CGAL_assertion(qq > 0); - const double qq_dbl = static_cast(qq); - const Interval_nt<> intv(qq_dbl, qq_dbl); - std::tie(l, u) = ldexp(intv, -shift).pair(); + if (p_bits == num_dbl_digits - 1) { + + std::cout << "- case r > 0 && p_bits = 51" << std::endl; + r <<= 1; + const int cmp = r.compare(x.den); + if (cmp > 0) { + + p <<= 1; + ++shift; + ++p; + std::tie(l, u) = get_1ulp_interval(shift, p); + + } else if ( ((cmp == 0) && (p & 1u))) { + CGAL_assertion_msg(false, "TODO: THIS CASE1!"); + } else { + CGAL_assertion_msg(false, "TODO: THIS CASE2!"); + } + + } else { + std::cout << "- case r > 0 && p_bits = 52" << std::endl; + std::tie(l, u) = get_1ulp_interval(shift, p); + } } - // } if (change_sign) { const double t = l; @@ -1036,9 +1046,11 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > u = -t; } - // std::cout << "l: " << l << std::endl; - // std::cout << "u: " << u << std::endl; - // std::cout << "nextafter: " << nextafter(l, +std::numeric_limits::infinity()) << std::endl; + std::cout << " l: " << l << std::endl; + std::cout << " u: " << u << std::endl; + const double inf = std::numeric_limits::infinity(); + std::cout << "nextafter l: " << nextafter(l, +inf) << std::endl; + std::cout << std::endl; CGAL_assertion(are_correct_bounds(l, u, input)); return std::make_pair(l, u); From c53a1d23212a6f53a9eddd8ee49f598e7527f5b3 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 15 Sep 2021 12:43:36 +0200 Subject: [PATCH 067/127] fixed tightness in boost to_interval --- Number_types/include/CGAL/Interval_nt.h | 1 + Number_types/include/CGAL/Quotient.h | 73 +++++++++++++++---------- 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/Number_types/include/CGAL/Interval_nt.h b/Number_types/include/CGAL/Interval_nt.h index b981657d0fb0..fb5649225565 100644 --- a/Number_types/include/CGAL/Interval_nt.h +++ b/Number_types/include/CGAL/Interval_nt.h @@ -1017,6 +1017,7 @@ const Interval_nt & y){ // TODO : document, when we are OK with the interface. // - should it allow other number types for the exponent ? +// TODO: Can we use int64_t for e here? template < bool b > Interval_nt ldexp(const Interval_nt &i, int e) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index bb0a2b8d89c4..a820c6974327 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -814,17 +814,21 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > public: - bool are_correct_bounds( const double l, const double u, const Type& x ) const { + bool are_bounds_correct( const double l, const double u, const Type& x ) const { + + const double inf = std::numeric_limits::infinity(); + CGAL_assertion(u == l || u == std::nextafter(l, +inf)); + const bool are_bounds_tight = (u == l || u == std::nextafter(l, +inf)); if ( - CGAL::abs(l) == std::numeric_limits::infinity() || - CGAL::abs(u) == std::numeric_limits::infinity() || + CGAL::abs(l) == inf || + CGAL::abs(u) == inf || CGAL::abs(l) == 0.0 || CGAL::abs(u) == 0.0) { - return true; + return are_bounds_tight; } - CGAL_assertion(CGAL::abs(l) != std::numeric_limits::infinity()); - CGAL_assertion(CGAL::abs(u) != std::numeric_limits::infinity()); + CGAL_assertion(CGAL::abs(l) != inf); + CGAL_assertion(CGAL::abs(u) != inf); CGAL_assertion(CGAL::abs(l) != 0.0); CGAL_assertion(CGAL::abs(u) != 0.0); @@ -833,10 +837,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(ub >= x); const bool are_bounds_respected = (lb <= x && x <= ub); - const double inf = std::numeric_limits::infinity(); - CGAL_assertion(u == l || u == std::nextafter(l, +inf)); - bool are_bounds_tight = (u == l || u == std::nextafter(l, +inf)); - return are_bounds_respected && are_bounds_tight; + return are_bounds_tight && are_bounds_respected; } #if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) @@ -871,7 +872,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion_code(const Type input = x); double l = 0.0, u = 0.0; if (CGAL::is_zero(x.num)) { // return [0.0, 0.0] - CGAL_assertion(are_correct_bounds(l, u, input)); + CGAL_assertion(are_bounds_correct(l, u, input)); return std::make_pair(l, u); } CGAL_assertion(!CGAL::is_zero(x.num)); @@ -906,45 +907,56 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > u = -t; } - CGAL_assertion(are_correct_bounds(l, u, input)); + CGAL_assertion(are_bounds_correct(l, u, input)); return std::make_pair(l, u); } - std::pair get_1ulp_interval( const int64_t shift, const NT& p ) const { + std::pair get_0ulp_interval( const int64_t shift, const NT& p ) const { - std::cout << "- 1ulp interval: " << std::endl; + std::cout << "- 0ulp interval: " << std::endl; CGAL_assertion(p >= 0); const uint64_t pp = static_cast(p); - const uint64_t qq = static_cast(pp + 1); CGAL_assertion(pp >= 0); - CGAL_assertion(qq > pp); const double pp_dbl = static_cast(pp); - const double qq_dbl = static_cast(qq); std::cout << "pp_dbl: " << pp_dbl << std::endl; - std::cout << "qq_dbl: " << qq_dbl << std::endl; + std::cout << "qq_dbl: " << pp_dbl << std::endl; - const Interval_nt<> intv(pp_dbl, qq_dbl); - return ldexp(intv, -shift).pair(); + const Interval_nt<> intv(pp_dbl, pp_dbl); + return ldexp(intv, -static_cast(shift)).pair(); } - std::pair get_0ulp_interval( const int64_t shift, const NT& p ) const { + std::pair get_1ulp_interval( const int64_t shift, const NT& p ) const { - std::cout << "- 0ulp interval: " << std::endl; + std::cout << "- 1ulp interval: " << std::endl; CGAL_assertion(p >= 0); const uint64_t pp = static_cast(p); + const uint64_t qq = static_cast(pp + 1); CGAL_assertion(pp >= 0); + CGAL_assertion(qq > pp); const double pp_dbl = static_cast(pp); + const double qq_dbl = static_cast(qq); std::cout << "pp_dbl: " << pp_dbl << std::endl; - std::cout << "qq_dbl: " << pp_dbl << std::endl; + std::cout << "qq_dbl: " << qq_dbl << std::endl; - const Interval_nt<> intv(pp_dbl, pp_dbl); - return ldexp(intv, -shift).pair(); + std::cout << "pp_dbl ldexp: " << std::ldexp(pp_dbl, -shift) << std::endl; + std::cout << "qq_dbl ldexp: " << std::ldexp(qq_dbl, -shift) << std::endl; + + const Interval_nt<> intv(pp_dbl, qq_dbl); + const auto res = ldexp(intv, -static_cast(shift)).pair(); + + // TODO: For some reason, ldexp returns 2.752961027411077506e-308 + // instead of denorm_min! + if (res.first == 0.0) { + CGAL_assertion(res.second != 0.0); + return std::make_pair(0.0, CGAL_IA_MIN_DOUBLE); + } + return res; } std::pair get_interval_as_boost( Type x ) const { @@ -952,7 +964,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion_code(const Type input = x); double l = 0.0, u = 0.0; if (CGAL::is_zero(x.num)) { // return [0.0, 0.0] - CGAL_assertion(are_correct_bounds(l, u, input)); + CGAL_assertion(are_bounds_correct(l, u, input)); return std::make_pair(l, u); } CGAL_assertion(!CGAL::is_zero(x.num)); @@ -1024,11 +1036,12 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > if (cmp > 0) { p <<= 1; + std::cout << "p bits shifted: " << boost::multiprecision::msb(p) << std::endl; ++shift; ++p; std::tie(l, u) = get_1ulp_interval(shift, p); - } else if ( ((cmp == 0) && (p & 1u))) { + } else if ( ((cmp == 0) && (p & 1u)) ) { CGAL_assertion_msg(false, "TODO: THIS CASE1!"); } else { CGAL_assertion_msg(false, "TODO: THIS CASE2!"); @@ -1052,7 +1065,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > std::cout << "nextafter l: " << nextafter(l, +inf) << std::endl; std::cout << std::endl; - CGAL_assertion(are_correct_bounds(l, u, input)); + CGAL_assertion(are_bounds_correct(l, u, input)); return std::make_pair(l, u); } @@ -1081,7 +1094,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(l == -inf); } - CGAL_assertion(are_correct_bounds(l, u, x)); + CGAL_assertion(are_bounds_correct(l, u, x)); return std::make_pair(l, u); } @@ -1102,7 +1115,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(CGAL::abs(xd.inf()) != inf && CGAL::abs(xd.sup()) != inf); const Interval_nt<> quot = xn / xd; - CGAL_assertion(are_correct_bounds(quot.inf(), quot.sup(), x)); + CGAL_assertion(are_bounds_correct(quot.inf(), quot.sup(), x)); return std::make_pair(quot.inf(), quot.sup()); } From 4d4f5cd67f90cb3e74e3a7239bed813f7cede737 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 15 Sep 2021 13:44:44 +0200 Subject: [PATCH 068/127] more test cases --- Number_types/include/CGAL/Quotient.h | 69 ++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 15 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index a820c6974327..c8b6fb3f98fe 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -817,6 +817,11 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > bool are_bounds_correct( const double l, const double u, const Type& x ) const { const double inf = std::numeric_limits::infinity(); + std::cout << " l: " << l << std::endl; + std::cout << " u: " << u << std::endl; + std::cout << "nextafter l: " << nextafter(l, +inf) << std::endl; + std::cout << std::endl; + CGAL_assertion(u == l || u == std::nextafter(l, +inf)); const bool are_bounds_tight = (u == l || u == std::nextafter(l, +inf)); @@ -1028,27 +1033,67 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > std::cout << "- case r = 0" << std::endl; std::tie(l, u) = get_0ulp_interval(shift, p); } else { - if (p_bits == num_dbl_digits - 1) { - - std::cout << "- case r > 0 && p_bits = 51" << std::endl; + std::cout << "- case r > 0" << std::endl; + + if (p_bits == num_dbl_digits - 1) { // we did not reach full precision + + // x.num <<= 1; + // boost::multiprecision::divide_qr(x.num, x.den, p, r); + // std::cout << "p bits shifted: " << boost::multiprecision::msb(p) << std::endl; + // std::cout << "p: " << p << std::endl; + // std::cout << "r: " << r << std::endl; + // std::tie(l, u) = get_1ulp_interval(shift+1, p); + + // CGAL_assertion(r < x.den); + // if (shift > 0) { + // std::cout << "- case p_bits = 51 && shift > 0" << std::endl; + // // CGAL_assertion_msg(false, "TODO: SHIFT > 0!"); + + // p <<= 1; + // r <<= 1; + // ++shift; + // } else { + // std::cout << "- case p_bits = 51 && shift < 0" << std::endl; + // // CGAL_assertion_msg(false, "TODO: SHIFT < 0!"); + + // CGAL_assertion(shift < 0); + // p <<= 1; + // r <<= 1; + // ++shift; + // } + + p <<= 1; r <<= 1; + ++shift; + std::cout << "p_bits shifted: " << boost::multiprecision::msb(p) << std::endl; + const int cmp = r.compare(x.den); if (cmp > 0) { - p <<= 1; - std::cout << "p bits shifted: " << boost::multiprecision::msb(p) << std::endl; - ++shift; + std::cout << "subcase 1" << std::endl; + // CGAL_assertion_msg(false, "TODO: SUBCASE1!"); + ++p; std::tie(l, u) = get_1ulp_interval(shift, p); } else if ( ((cmp == 0) && (p & 1u)) ) { - CGAL_assertion_msg(false, "TODO: THIS CASE1!"); + + std::cout << "subcase 2" << std::endl; + CGAL_assertion_msg(false, "TODO: SUBCASE2!"); + + ++p; + std::tie(l, u) = get_1ulp_interval(shift, p); + } else { - CGAL_assertion_msg(false, "TODO: THIS CASE2!"); + + std::cout << "subcase 3" << std::endl; + // CGAL_assertion_msg(false, "TODO: SUBCASE3!"); + + std::tie(l, u) = get_1ulp_interval(shift, p); } } else { - std::cout << "- case r > 0 && p_bits = 52" << std::endl; + std::cout << "- case p_bits = 52" << std::endl; std::tie(l, u) = get_1ulp_interval(shift, p); } } @@ -1059,12 +1104,6 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > u = -t; } - std::cout << " l: " << l << std::endl; - std::cout << " u: " << u << std::endl; - const double inf = std::numeric_limits::infinity(); - std::cout << "nextafter l: " << nextafter(l, +inf) << std::endl; - std::cout << std::endl; - CGAL_assertion(are_bounds_correct(l, u, input)); return std::make_pair(l, u); } From 77491875ebe3eb09719d9bf38b67d885399c5753 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 15 Sep 2021 14:06:07 +0200 Subject: [PATCH 069/127] checking cpp_rational impl + no verbose --- Number_types/include/CGAL/Quotient.h | 62 ++++++++++++++-------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index c8b6fb3f98fe..b2c59c9b73b0 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -817,10 +817,10 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > bool are_bounds_correct( const double l, const double u, const Type& x ) const { const double inf = std::numeric_limits::infinity(); - std::cout << " l: " << l << std::endl; - std::cout << " u: " << u << std::endl; - std::cout << "nextafter l: " << nextafter(l, +inf) << std::endl; - std::cout << std::endl; + // std::cout << " l: " << l << std::endl; + // std::cout << " u: " << u << std::endl; + // std::cout << "nextafter l: " << nextafter(l, +inf) << std::endl; + // std::cout << std::endl; CGAL_assertion(u == l || u == std::nextafter(l, +inf)); const bool are_bounds_tight = (u == l || u == std::nextafter(l, +inf)); @@ -918,7 +918,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > std::pair get_0ulp_interval( const int64_t shift, const NT& p ) const { - std::cout << "- 0ulp interval: " << std::endl; + // std::cout << "- 0ulp interval: " << std::endl; CGAL_assertion(p >= 0); const uint64_t pp = static_cast(p); @@ -926,8 +926,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(pp >= 0); const double pp_dbl = static_cast(pp); - std::cout << "pp_dbl: " << pp_dbl << std::endl; - std::cout << "qq_dbl: " << pp_dbl << std::endl; + // std::cout << "pp_dbl: " << pp_dbl << std::endl; + // std::cout << "qq_dbl: " << pp_dbl << std::endl; const Interval_nt<> intv(pp_dbl, pp_dbl); return ldexp(intv, -static_cast(shift)).pair(); @@ -935,7 +935,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > std::pair get_1ulp_interval( const int64_t shift, const NT& p ) const { - std::cout << "- 1ulp interval: " << std::endl; + // std::cout << "- 1ulp interval: " << std::endl; CGAL_assertion(p >= 0); const uint64_t pp = static_cast(p); @@ -946,11 +946,11 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const double pp_dbl = static_cast(pp); const double qq_dbl = static_cast(qq); - std::cout << "pp_dbl: " << pp_dbl << std::endl; - std::cout << "qq_dbl: " << qq_dbl << std::endl; + // std::cout << "pp_dbl: " << pp_dbl << std::endl; + // std::cout << "qq_dbl: " << qq_dbl << std::endl; - std::cout << "pp_dbl ldexp: " << std::ldexp(pp_dbl, -shift) << std::endl; - std::cout << "qq_dbl ldexp: " << std::ldexp(qq_dbl, -shift) << std::endl; + // std::cout << "pp_dbl ldexp: " << std::ldexp(pp_dbl, -shift) << std::endl; + // std::cout << "qq_dbl ldexp: " << std::ldexp(qq_dbl, -shift) << std::endl; const Interval_nt<> intv(pp_dbl, qq_dbl); const auto res = ldexp(intv, -static_cast(shift)).pair(); @@ -997,13 +997,13 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const int64_t msb_diff = msb_num - msb_den; int64_t shift = num_dbl_digits - msb_diff; - std::cout << "msb num: " << msb_num << std::endl; - std::cout << "msb den: " << msb_den << std::endl; - std::cout << "msb diff: " << msb_diff << std::endl; - std::cout << " shift: " << shift << std::endl; + // std::cout << "msb num: " << msb_num << std::endl; + // std::cout << "msb den: " << msb_den << std::endl; + // std::cout << "msb diff: " << msb_diff << std::endl; + // std::cout << " shift: " << shift << std::endl; - std::cout << "x num: " << x.num << std::endl; - std::cout << "x den: " << x.den << std::endl; + // std::cout << "x num: " << x.num << std::endl; + // std::cout << "x den: " << x.den << std::endl; if (shift > 0) { CGAL_assertion(msb_diff < num_dbl_digits); @@ -1021,20 +1021,21 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion_code(const int64_t p_bits = static_cast(boost::multiprecision::msb(p))); - std::cout << "x num shifted: " << x.num << std::endl; - std::cout << "x den shifted: " << x.den << std::endl; + // std::cout << "x num shifted: " << x.num << std::endl; + // std::cout << "x den shifted: " << x.den << std::endl; - std::cout << "p bits: " << boost::multiprecision::msb(p) << std::endl; + // std::cout << "p bits: " << boost::multiprecision::msb(p) << std::endl; - std::cout << "p: " << p << std::endl; - std::cout << "r: " << r << std::endl; + // std::cout << "p: " << p << std::endl; + // std::cout << "r: " << r << std::endl; if (r == 0) { - std::cout << "- case r = 0" << std::endl; + // std::cout << "- case r = 0" << std::endl; std::tie(l, u) = get_0ulp_interval(shift, p); } else { - std::cout << "- case r > 0" << std::endl; + // std::cout << "- case r > 0" << std::endl; + CGAL_assertion(r < x.den); if (p_bits == num_dbl_digits - 1) { // we did not reach full precision // x.num <<= 1; @@ -1044,7 +1045,6 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // std::cout << "r: " << r << std::endl; // std::tie(l, u) = get_1ulp_interval(shift+1, p); - // CGAL_assertion(r < x.den); // if (shift > 0) { // std::cout << "- case p_bits = 51 && shift > 0" << std::endl; // // CGAL_assertion_msg(false, "TODO: SHIFT > 0!"); @@ -1065,12 +1065,12 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > p <<= 1; r <<= 1; ++shift; - std::cout << "p_bits shifted: " << boost::multiprecision::msb(p) << std::endl; + // std::cout << "p_bits shifted: " << boost::multiprecision::msb(p) << std::endl; const int cmp = r.compare(x.den); if (cmp > 0) { - std::cout << "subcase 1" << std::endl; + // std::cout << "subcase 1" << std::endl; // CGAL_assertion_msg(false, "TODO: SUBCASE1!"); ++p; @@ -1078,7 +1078,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } else if ( ((cmp == 0) && (p & 1u)) ) { - std::cout << "subcase 2" << std::endl; + // std::cout << "subcase 2" << std::endl; CGAL_assertion_msg(false, "TODO: SUBCASE2!"); ++p; @@ -1086,14 +1086,14 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } else { - std::cout << "subcase 3" << std::endl; + // std::cout << "subcase 3" << std::endl; // CGAL_assertion_msg(false, "TODO: SUBCASE3!"); std::tie(l, u) = get_1ulp_interval(shift, p); } } else { - std::cout << "- case p_bits = 52" << std::endl; + // std::cout << "- case p_bits = 52" << std::endl; std::tie(l, u) = get_1ulp_interval(shift, p); } } From 5f95d7288d87d7ebdc39683ef1c6a44d9ddce076 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 15 Sep 2021 15:38:23 +0200 Subject: [PATCH 070/127] more asserts --- Number_types/include/CGAL/Quotient.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index b2c59c9b73b0..6d70499656fb 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -1035,6 +1035,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } else { // std::cout << "- case r > 0" << std::endl; + CGAL_assertion(r > 0); CGAL_assertion(r < x.den); if (p_bits == num_dbl_digits - 1) { // we did not reach full precision @@ -1067,6 +1068,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > ++shift; // std::cout << "p_bits shifted: " << boost::multiprecision::msb(p) << std::endl; + CGAL_assertion(r > 0); const int cmp = r.compare(x.den); if (cmp > 0) { @@ -1076,7 +1078,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > ++p; std::tie(l, u) = get_1ulp_interval(shift, p); - } else if ( ((cmp == 0) && (p & 1u)) ) { + } else if ( (cmp == 0) && (p & 1u) ) { // std::cout << "subcase 2" << std::endl; CGAL_assertion_msg(false, "TODO: SUBCASE2!"); From 285bff39ec54b2f0fdd94cdb8baa0232eb401257 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 15 Sep 2021 16:55:13 +0200 Subject: [PATCH 071/127] test checking cmp = 0 --- Number_types/include/CGAL/Quotient.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 6d70499656fb..277537fd3099 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -1029,6 +1029,14 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // std::cout << "p: " << p << std::endl; // std::cout << "r: " << r << std::endl; + // std::vector b; + // export_bits(p, std::back_inserter(b), 1); + // std::cout << "binary: "; + // for (const unsigned char bit : b) { + // std::cout << static_cast(bit); + // } + // std::cout << std::endl; + if (r == 0) { // std::cout << "- case r = 0" << std::endl; std::tie(l, u) = get_0ulp_interval(shift, p); @@ -1070,6 +1078,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(r > 0); const int cmp = r.compare(x.den); + // std::cout << "cmp: " << cmp << std::endl; + // std::cout << "p & 1u: " << (p & 1u) << std::endl; if (cmp > 0) { // std::cout << "subcase 1" << std::endl; @@ -1081,7 +1091,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } else if ( (cmp == 0) && (p & 1u) ) { // std::cout << "subcase 2" << std::endl; - CGAL_assertion_msg(false, "TODO: SUBCASE2!"); + // CGAL_assertion_msg(false, "TODO: SUBCASE2!"); ++p; std::tie(l, u) = get_1ulp_interval(shift, p); From 46013ce7068b6a05f37104f41c8a14ded3107e82 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 15 Sep 2021 17:03:38 +0200 Subject: [PATCH 072/127] make p_bits available in release --- Number_types/include/CGAL/Quotient.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 277537fd3099..ed84d6e9e1c8 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -1018,13 +1018,12 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > NT p, r; boost::multiprecision::divide_qr(x.num, x.den, p, r); - CGAL_assertion_code(const int64_t p_bits = - static_cast(boost::multiprecision::msb(p))); + const int64_t p_bits = static_cast(boost::multiprecision::msb(p)); // std::cout << "x num shifted: " << x.num << std::endl; // std::cout << "x den shifted: " << x.den << std::endl; - // std::cout << "p bits: " << boost::multiprecision::msb(p) << std::endl; + // std::cout << "p bits: " << p_bits << std::endl; // std::cout << "p: " << p << std::endl; // std::cout << "r: " << r << std::endl; From 5e3def8e7a65860a9b1e86ec8d87623384e1bfea Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 16 Sep 2021 14:49:40 +0200 Subject: [PATCH 073/127] sebastien review --- Number_types/include/CGAL/Quotient.h | 44 +++++++++++++++++++--------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index ed84d6e9e1c8..12fd7a2d719e 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -916,6 +916,20 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > return std::make_pair(l, u); } + // TODO: This is a temporary implementation and should be replaced + // by the default one. + Interval_nt + my_ldexp(const Interval_nt &i, const int e) const { + + CGAL_assertion(i.inf() > 0.0); + CGAL_assertion(i.sup() > 0.0); + const double scale = std::ldexp(1.0, e); + return Interval_nt ( + CGAL_NTS is_finite(scale) ? + scale * i.inf() : CGAL_IA_MAX_DOUBLE, + scale == 0 ? CGAL_IA_MIN_DOUBLE : scale * i.sup()); + } + std::pair get_0ulp_interval( const int64_t shift, const NT& p ) const { // std::cout << "- 0ulp interval: " << std::endl; @@ -929,8 +943,9 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // std::cout << "pp_dbl: " << pp_dbl << std::endl; // std::cout << "qq_dbl: " << pp_dbl << std::endl; - const Interval_nt<> intv(pp_dbl, pp_dbl); - return ldexp(intv, -static_cast(shift)).pair(); + // TODO: Should we use false? + const Interval_nt intv(pp_dbl, pp_dbl); + return my_ldexp(intv, -static_cast(shift)).pair(); } std::pair get_1ulp_interval( const int64_t shift, const NT& p ) const { @@ -952,20 +967,22 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // std::cout << "pp_dbl ldexp: " << std::ldexp(pp_dbl, -shift) << std::endl; // std::cout << "qq_dbl ldexp: " << std::ldexp(qq_dbl, -shift) << std::endl; - const Interval_nt<> intv(pp_dbl, qq_dbl); - const auto res = ldexp(intv, -static_cast(shift)).pair(); + const Interval_nt intv(pp_dbl, qq_dbl); + /* const auto res = */ + return my_ldexp(intv, -static_cast(shift)).pair(); // TODO: For some reason, ldexp returns 2.752961027411077506e-308 // instead of denorm_min! - if (res.first == 0.0) { - CGAL_assertion(res.second != 0.0); - return std::make_pair(0.0, CGAL_IA_MIN_DOUBLE); - } - return res; + // if (res.first == 0.0) { + // CGAL_assertion(res.second != 0.0); + // return std::make_pair(0.0, CGAL_IA_MIN_DOUBLE); + // } + // return res; } std::pair get_interval_as_boost( Type x ) const { + CGAL_assertion(!CGAL::is_zero(x.den)); CGAL_assertion_code(const Type input = x); double l = 0.0, u = 0.0; if (CGAL::is_zero(x.num)) { // return [0.0, 0.0] @@ -973,7 +990,6 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > return std::make_pair(l, u); } CGAL_assertion(!CGAL::is_zero(x.num)); - CGAL_assertion(!CGAL::is_zero(x.den)); // Handle signs. bool change_sign = false; @@ -1007,10 +1023,10 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > if (shift > 0) { CGAL_assertion(msb_diff < num_dbl_digits); - x.num <<= shift; + x.num <<= +shift; } else if (shift < 0) { CGAL_assertion(msb_diff > num_dbl_digits); - x.den <<= boost::multiprecision::detail::unsigned_abs(shift); + x.den <<= -shift; } CGAL_assertion(num_dbl_digits == static_cast(boost::multiprecision::msb(x.num)) - @@ -1087,13 +1103,13 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > ++p; std::tie(l, u) = get_1ulp_interval(shift, p); - } else if ( (cmp == 0) && (p & 1u) ) { + } else if ( (cmp == 0) /* && (p & 1u) */ ) { // std::cout << "subcase 2" << std::endl; // CGAL_assertion_msg(false, "TODO: SUBCASE2!"); ++p; - std::tie(l, u) = get_1ulp_interval(shift, p); + std::tie(l, u) = get_0ulp_interval(shift, p); } else { From 9cb92c8cf4d3229622ffcda5ac3148732f238f5a Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 16 Sep 2021 16:09:31 +0200 Subject: [PATCH 074/127] fixed warnings from testme --- Number_types/include/CGAL/Quotient.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 12fd7a2d719e..472b31abd939 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -53,7 +53,7 @@ namespace CGAL { // This function is not documented as a number type requirement for now. template < typename NT > inline void -simplify_quotient(NT & a, NT & b) { } +simplify_quotient(NT & , NT & ) { } #if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) @@ -1153,7 +1153,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const double inf = std::numeric_limits::infinity(); if (l == +inf) { - l = std::numeric_limits::max(); + l = (std::numeric_limits::max)(); CGAL_assertion(u == +inf); } else if (u == -inf) { u = std::numeric_limits::lowest(); From 4673f976ab871207b25569d14faa90a898e5389d Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 16 Sep 2021 17:02:50 +0200 Subject: [PATCH 075/127] use different default type --- .../internal/Exact_type_selector.h | 3 +- Number_types/include/CGAL/Quotient.h | 16 +-- Number_types/include/CGAL/boost_mp.h | 127 ++++++++++++------ 3 files changed, 94 insertions(+), 52 deletions(-) diff --git a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h index 0a491b1fe4cd..98224edf517a 100644 --- a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h @@ -81,7 +81,8 @@ struct Exact_field_selector #else // run testme -{ typedef Quotient Type; }; +// { typedef Quotient Type; }; +{ typedef BOOST_cpp_arithmetic_kernel::Rational Type; }; #endif // run testme diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 472b31abd939..e7ed667a0b4b 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -57,10 +57,6 @@ simplify_quotient(NT & , NT & ) { } #if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) -// WARNINGS: -// https://cgal.geometryfactory.com/~cgaltest/test_suite/TESTRESULTS/CGAL-5.4-Ic-5937/Convex_decomposition_3/TestReport_cgaltest_Ubuntu-gcc7.gz -// https://cgal.geometryfactory.com/~cgaltest/test_suite/TESTRESULTS/CGAL-5.4-Ic-5937/Convex_decomposition_3/TestReport_cgaltest_arm64-apple_bigsur_clang1200-release-64bits.gz -// See boost includes above. Should make it work, I guess. inline void simplify_quotient(boost::multiprecision::cpp_int & a, boost::multiprecision::cpp_int & b) { @@ -919,15 +915,15 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > // TODO: This is a temporary implementation and should be replaced // by the default one. Interval_nt - my_ldexp(const Interval_nt &i, const int e) const { + my_ldexp( const Interval_nt& intv, const int e ) const { - CGAL_assertion(i.inf() > 0.0); - CGAL_assertion(i.sup() > 0.0); + CGAL_assertion(intv.inf() > 0.0); + CGAL_assertion(intv.sup() > 0.0); const double scale = std::ldexp(1.0, e); return Interval_nt ( CGAL_NTS is_finite(scale) ? - scale * i.inf() : CGAL_IA_MAX_DOUBLE, - scale == 0 ? CGAL_IA_MIN_DOUBLE : scale * i.sup()); + scale * intv.inf() : CGAL_IA_MAX_DOUBLE, + scale == 0.0 ? CGAL_IA_MIN_DOUBLE : scale * intv.sup()); } std::pair get_0ulp_interval( const int64_t shift, const NT& p ) const { @@ -1210,7 +1206,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > #else // master version #if defined(CGAL_USE_TO_INTERVAL_WITH_BOOST) - return std::make_pair(0.0, 0.0); + return std::make_pair(static_cast(x.num), static_cast(x.den)); #else const Interval_nt<> quot = Interval_nt<>(CGAL_NTS to_interval(x.numerator())) / diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 4868f8b5c7f0..87bc22775afd 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -193,26 +193,69 @@ struct RET_boost_mp_base struct To_interval : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { - #if defined(CGAL_USE_TO_INTERVAL_WITH_BOOST) // test boost devel + // #if defined(CGAL_USE_TO_INTERVAL_WITH_BOOST) // test boost devel - use when the default is Quotient + #if !defined(CGAL_DO_NOT_RUN_TESTME) || defined(CGAL_USE_TO_INTERVAL_WITH_BOOST) // test boost devel - use when the default is cpp_rational - bool are_correct_bounds( const double l, const double u, const Type& x ) const { + bool are_bounds_correct( const double l, const double u, const Type& x ) const { + + const double inf = std::numeric_limits::infinity(); + CGAL_assertion(u == l || u == std::nextafter(l, +inf)); + const bool are_bounds_tight = (u == l || u == std::nextafter(l, +inf)); if ( - CGAL::abs(l) == std::numeric_limits::infinity() || - CGAL::abs(u) == std::numeric_limits::infinity() || + CGAL::abs(l) == inf || + CGAL::abs(u) == inf || CGAL::abs(l) == 0.0 || CGAL::abs(u) == 0.0) { - return true; + return are_bounds_tight; } - CGAL_assertion(CGAL::abs(l) != std::numeric_limits::infinity()); - CGAL_assertion(CGAL::abs(u) != std::numeric_limits::infinity()); + CGAL_assertion(CGAL::abs(l) != inf); + CGAL_assertion(CGAL::abs(u) != inf); CGAL_assertion(CGAL::abs(l) != 0.0); CGAL_assertion(CGAL::abs(u) != 0.0); const Type lb(l), ub(u); CGAL_assertion(lb <= x); CGAL_assertion(ub >= x); - return lb <= ub && lb <= x && ub >= x; + const bool are_bounds_respected = (lb <= x && x <= ub); + return are_bounds_tight && are_bounds_respected; + } + + Interval_nt + my_ldexp( const Interval_nt& intv, const int e ) const { + + CGAL_assertion(intv.inf() > 0.0); + CGAL_assertion(intv.sup() > 0.0); + const double scale = std::ldexp(1.0, e); + return Interval_nt ( + CGAL_NTS is_finite(scale) ? + scale * intv.inf() : CGAL_IA_MAX_DOUBLE, + scale == 0.0 ? CGAL_IA_MIN_DOUBLE : scale * intv.sup()); + } + + template + std::pair get_0ulp_interval( const int64_t shift, const ET& p ) const { + + CGAL_assertion(p >= 0); + const uint64_t pp = static_cast(p); + CGAL_assertion(pp >= 0); + const double pp_dbl = static_cast(pp); + const Interval_nt intv(pp_dbl, pp_dbl); + return my_ldexp(intv, -static_cast(shift)).pair(); + } + + template + std::pair get_1ulp_interval( const int64_t shift, const ET& p ) const { + + CGAL_assertion(p >= 0); + const uint64_t pp = static_cast(p); + const uint64_t qq = static_cast(pp + 1); + CGAL_assertion(pp >= 0); + CGAL_assertion(qq > pp); + const double pp_dbl = static_cast(pp); + const double qq_dbl = static_cast(qq); + const Interval_nt intv(pp_dbl, qq_dbl); + return my_ldexp(intv, -static_cast(shift)).pair(); } std::pair @@ -221,14 +264,14 @@ struct RET_boost_mp_base auto xnum = boost::multiprecision::numerator(x); auto xden = boost::multiprecision::denominator(x); + CGAL_assertion(!CGAL::is_zero(xden)); CGAL_assertion_code(const Type input = x); double l = 0.0, u = 0.0; if (CGAL::is_zero(xnum)) { // return [0.0, 0.0] - CGAL_assertion(are_correct_bounds(l, u, input)); + CGAL_assertion(are_bounds_correct(l, u, input)); return std::make_pair(l, u); } CGAL_assertion(!CGAL::is_zero(xnum)); - CGAL_assertion(!CGAL::is_zero(xden)); // Handle signs. bool change_sign = false; @@ -250,47 +293,49 @@ struct RET_boost_mp_base const int64_t msb_num = static_cast(boost::multiprecision::msb(xnum)); const int64_t msb_den = static_cast(boost::multiprecision::msb(xden)); const int64_t msb_diff = msb_num - msb_den; - const int64_t shift = num_dbl_digits - msb_diff; + int64_t shift = num_dbl_digits - msb_diff; if (shift > 0) { CGAL_assertion(msb_diff < num_dbl_digits); - xnum <<= shift; + xnum <<= +shift; } else if (shift < 0) { CGAL_assertion(msb_diff > num_dbl_digits); - xden <<= boost::multiprecision::detail::unsigned_abs(shift); + xden <<= -shift; } CGAL_assertion(num_dbl_digits == static_cast(boost::multiprecision::msb(xnum)) - static_cast(boost::multiprecision::msb(xden))); - decltype(xnum) q, r; - boost::multiprecision::divide_qr(xnum, xden, q, r); - CGAL_assertion_code(const int64_t q_bits = - static_cast(boost::multiprecision::msb(q))); - CGAL_assertion(q_bits == num_dbl_digits || - r != 0 /* when q_bit = num_dbl_digits - 1 */ ); - - // WARNING: https://cgal.geometryfactory.com/~cgaltest/test_suite/TESTRESULTS/CGAL-5.4-Ic-5937/Combinatorial_map/TestReport_cgaltest_VS-19.gz - // Fixed: Interval_nt is defined only for double, see impl below. - if (!CGAL::is_zero(r)) { - const decltype(q) p = q; - ++q; - CGAL_assertion(p >= 0 && q > p); - const uint64_t pp = static_cast(p); - const uint64_t qq = static_cast(q); - CGAL_assertion(pp >= 0 && qq > pp); - const double pp_dbl = static_cast(pp); - const double qq_dbl = static_cast(qq); - const Interval_nt<> intv(pp_dbl, qq_dbl); - std::tie(l, u) = ldexp(intv, -shift).pair(); + decltype(xnum) p, r; + boost::multiprecision::divide_qr(xnum, xden, p, r); + const int64_t p_bits = static_cast(boost::multiprecision::msb(p)); + + if (r == 0) { + std::tie(l, u) = get_0ulp_interval(shift, p); } else { - CGAL_assertion(CGAL::is_zero(r)); - CGAL_assertion(q > 0); - const uint64_t qq = static_cast(q); - CGAL_assertion(qq > 0); - const double qq_dbl = static_cast(qq); - const Interval_nt<> intv(qq_dbl, qq_dbl); - std::tie(l, u) = ldexp(intv, -shift).pair(); + CGAL_assertion(r > 0); + CGAL_assertion(r < xden); + if (p_bits == num_dbl_digits - 1) { // we did not reach full precision + + p <<= 1; + r <<= 1; + ++shift; + + CGAL_assertion(r > 0); + const int cmp = r.compare(xden); + if (cmp > 0) { + ++p; + std::tie(l, u) = get_1ulp_interval(shift, p); + } else if (cmp == 0) { + ++p; + std::tie(l, u) = get_0ulp_interval(shift, p); + } else { + std::tie(l, u) = get_1ulp_interval(shift, p); + } + + } else { + std::tie(l, u) = get_1ulp_interval(shift, p); + } } if (change_sign) { @@ -299,7 +344,7 @@ struct RET_boost_mp_base u = -t; } - CGAL_assertion(are_correct_bounds(l, u, input)); + CGAL_assertion(are_bounds_correct(l, u, input)); return std::make_pair(l, u); } From 1b2a4a5303f5a3f31ee87d9caa8d97ce0595c350 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 16 Sep 2021 18:01:51 +0200 Subject: [PATCH 076/127] fixed demo --- Number_types/include/CGAL/Quotient.h | 2 +- Number_types/include/CGAL/number_type_basic.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index e7ed667a0b4b..2a60ed60f5cd 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -1145,7 +1145,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } double l, u; - std::tie(l, u) = to_interval(rat); + std::tie(l, u) = to_interval(rat); // TODO: fails if boost_mp is not included! const double inf = std::numeric_limits::infinity(); if (l == +inf) { diff --git a/Number_types/include/CGAL/number_type_basic.h b/Number_types/include/CGAL/number_type_basic.h index 8e0cb00f85a8..3b7e599881c3 100644 --- a/Number_types/include/CGAL/number_type_basic.h +++ b/Number_types/include/CGAL/number_type_basic.h @@ -62,7 +62,9 @@ #ifdef CGAL_USE_GMP #ifdef CGAL_USE_GMPXX +#if defined(CGAL_DO_NOT_RUN_TESTME) #include +#endif #endif // CGAL_USE_GMPXX #endif // CGAL_USE_GMP From 1bd62581932859813d3d4807b847720189ece0e1 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 17 Sep 2021 11:54:12 +0200 Subject: [PATCH 077/127] fixed wrong match between integer and rational types in boostmp --- Number_types/include/CGAL/Quotient.h | 10 ++- Number_types/include/CGAL/boost_mp.h | 90 ++++++++++++++++++- Number_types/include/CGAL/number_type_basic.h | 2 - 3 files changed, 95 insertions(+), 7 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 2a60ed60f5cd..bc966d1c0da9 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -810,6 +810,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > public: + #if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) + bool are_bounds_correct( const double l, const double u, const Type& x ) const { const double inf = std::numeric_limits::infinity(); @@ -841,8 +843,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > return are_bounds_tight && are_bounds_respected; } - #if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) - + /* std::pair< Interval_nt<>, int64_t > get_interval_exp( NT& x ) const { CGAL_assertion(CGAL::is_positive(x)); @@ -910,7 +911,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(are_bounds_correct(l, u, input)); return std::make_pair(l, u); - } + } */ // TODO: This is a temporary implementation and should be replaced // by the default one. @@ -1131,6 +1132,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > return std::make_pair(l, u); } + /* std::pair interval_from_cpp_rational( const Type& x ) const { // Seems fast enough because this conversion happens @@ -1179,7 +1181,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const Interval_nt<> quot = xn / xd; CGAL_assertion(are_bounds_correct(quot.inf(), quot.sup(), x)); return std::make_pair(quot.inf(), quot.sup()); - } + } */ #endif // CPP_INT diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 87bc22775afd..3d2f5531ca21 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -190,6 +190,94 @@ struct RET_boost_mp_base } }; + struct To_interval + : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { + + std::pair + operator()(const Type& x) const { + + // See if https://github.com/boostorg/multiprecision/issues/108 suggests anything better + // assume the conversion is within 1 ulp + // adding IA::smallest() doesn't work because inf-e=inf, even rounded down. + + // We must use to_nearest with cpp_int. + double i; + const double inf = std::numeric_limits::infinity(); + { + Protect_FPU_rounding P(CGAL_FE_TONEAREST); + i = static_cast(x); + if (CGAL::abs(i) == inf) return std::make_pair(i, i); + } + double s = i; + CGAL_assertion(i != inf && s != inf); + + // Throws uncaught exception: Cannot convert a non-finite number to an integer. + // We can catch it earlier by using the CGAL_assertion() one line above. + const int cmp = x.compare(i); + if (cmp > 0) { + s = nextafter(s, +inf); + CGAL_assertion(x.compare(s) < 0); + } + else if (cmp < 0) { + i = nextafter(i, -inf); + CGAL_assertion(x.compare(i) > 0); + } + return std::pair(i, s); + } + }; +}; + +template +struct RET_boost_mp_base_rational + : public INTERN_RET::Real_embeddable_traits_base< NT , CGAL::Tag_true > { + + typedef NT Type; + + struct Is_zero: public CGAL::cpp98::unary_function { + bool operator()( const Type& x) const { + return x.is_zero(); + } + }; + + struct Is_positive: public CGAL::cpp98::unary_function { + bool operator()( const Type& x) const { + return x.sign() > 0; + } + }; + + struct Is_negative: public CGAL::cpp98::unary_function { + bool operator()( const Type& x) const { + return x.sign() < 0; + } + }; + + struct Abs : public CGAL::cpp98::unary_function { + template + Type operator()(const T& x) const { + return boost::multiprecision::abs(x); + } + }; + + struct Sgn : public CGAL::cpp98::unary_function { + ::CGAL::Sign operator()(Type const& x) const { + return CGAL::sign(x.sign()); + } + }; + + struct Compare + : public CGAL::cpp98::binary_function { + Comparison_result operator()(const Type& x, const Type& y) const { + return CGAL::sign(x.compare(y)); + } + }; + + struct To_double + : public CGAL::cpp98::unary_function { + double operator()(const Type& x) const { + return x.template convert_to(); + } + }; + struct To_interval : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { @@ -395,7 +483,7 @@ struct RET_boost_mp struct RET_boost_mp > - : RET_boost_mp_base {}; + : RET_boost_mp_base_rational {}; #ifdef CGAL_USE_MPFR // Because of these full specializations, things get instantiated more eagerly. Make them artificially partial if necessary. diff --git a/Number_types/include/CGAL/number_type_basic.h b/Number_types/include/CGAL/number_type_basic.h index 3b7e599881c3..8e0cb00f85a8 100644 --- a/Number_types/include/CGAL/number_type_basic.h +++ b/Number_types/include/CGAL/number_type_basic.h @@ -62,9 +62,7 @@ #ifdef CGAL_USE_GMP #ifdef CGAL_USE_GMPXX -#if defined(CGAL_DO_NOT_RUN_TESTME) #include -#endif #endif // CGAL_USE_GMPXX #endif // CGAL_USE_GMP From ac15165209b785b12e06364388002dc45d0e645a Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 20 Sep 2021 12:39:38 +0200 Subject: [PATCH 078/127] using cpp_rational --- .../include/CGAL/Number_types/internal/Exact_type_selector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h index 98224edf517a..6a8e7569579e 100644 --- a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h @@ -82,7 +82,7 @@ struct Exact_field_selector #else // run testme // { typedef Quotient Type; }; -{ typedef BOOST_cpp_arithmetic_kernel::Rational Type; }; +{ typedef boost::multiprecision::cpp_rational Type; }; #endif // run testme From 5816d9576585394b6955707536008703ba95bd78 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 20 Sep 2021 13:10:07 +0200 Subject: [PATCH 079/127] cleanup --- Number_types/include/CGAL/Interval_nt.h | 1 - Number_types/include/CGAL/Quotient.h | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Number_types/include/CGAL/Interval_nt.h b/Number_types/include/CGAL/Interval_nt.h index fb5649225565..b981657d0fb0 100644 --- a/Number_types/include/CGAL/Interval_nt.h +++ b/Number_types/include/CGAL/Interval_nt.h @@ -1017,7 +1017,6 @@ const Interval_nt & y){ // TODO : document, when we are OK with the interface. // - should it allow other number types for the exponent ? -// TODO: Can we use int64_t for e here? template < bool b > Interval_nt ldexp(const Interval_nt &i, int e) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index bc966d1c0da9..4c80bd574e49 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -914,7 +914,8 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } */ // TODO: This is a temporary implementation and should be replaced - // by the default one. + // by the default one. Can we use int64_t for e here? - No, because we + // would not be able to run ldexp on it. Interval_nt my_ldexp( const Interval_nt& intv, const int e ) const { From eb2309f81efcfebd9b571a2c6eacbb09abc32ea7 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 20 Sep 2021 15:58:57 +0200 Subject: [PATCH 080/127] add overload of to_interval for quotient with cpp_int --- Number_types/include/CGAL/Quotient.h | 455 ++++++++------------------- Number_types/include/CGAL/boost_mp.h | 7 +- 2 files changed, 132 insertions(+), 330 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 4c80bd574e49..a474e4f0f654 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -31,17 +31,9 @@ #include #include - -#if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) #include -// TODO: The two below will be removed when we move simplify_quotient() to boost_mp, -// where it is supposed to be. -#include -#include -#endif #include -#include namespace CGAL { @@ -53,22 +45,17 @@ namespace CGAL { // This function is not documented as a number type requirement for now. template < typename NT > inline void -simplify_quotient(NT & , NT & ) { } - -#if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) - -inline void -simplify_quotient(boost::multiprecision::cpp_int & a, boost::multiprecision::cpp_int & b) { - - // TODO: - // - move it to the boost_mp.h - // - can we use gcd only sometimes to save time? - const boost::multiprecision::cpp_int r = boost::multiprecision::gcd(a, b); - a /= r; - b /= r; -} - -#endif // CPP_INT +simplify_quotient(NT & , NT & ) {} + +#ifdef CGAL_USE_BOOST_MP + template < > + inline void + simplify_quotient(boost::multiprecision::cpp_int & a, boost::multiprecision::cpp_int & b) { + const boost::multiprecision::cpp_int r = boost::multiprecision::gcd(a, b); + a /= r; + b /= r; + } +#endif // CGAL_USE_BOOST_MP // This one should be replaced by some functor or tag. // Meanwhile, the class is specialized for Gmpz, mpz_class, leda_integer. @@ -215,115 +202,17 @@ Quotient::normalize() return *this; } -#if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) - template CGAL_MEDIUM_INLINE Quotient& Quotient::operator+= (const Quotient& r) { -#if true - num = num * r.den + r.num * den; den *= r.den; simplify_quotient(num, den); return *this; - -#else - - // taken from https://github.com/boostorg/multiprecision/blob/rational_adaptor_standalone/include/boost/multiprecision/rational_adaptor.hpp#L486 - // This has the BSL, but this code won't survive - typedef NT Backend; - - NT result_num, result_denom; - Backend gcd, t1, t2, t3, t4; - // - // Begin by getting the gcd of the 2 denominators: - // - // ERROR: no matching function for call to gcd! We skip this implementation for the moment! - gcd = boost::multiprecision::gcd(denominator(), b.denominator()); - // - // Do we have gcd > 1: - // - // WARNING: logical not is only applied to the left hand side of comparison and - // ERROR: no match for operator! - // We skip this implementation for the moment! - if (! gcd == 1) - { - // - // Scale the denominators by gcd, and put the results in t1 and t2: - // - t1 = CGAL::integral_division( b.denominator(), gcd); - t2 = CGAL::integral_division( denominator(), gcd); - // - // multiply the numerators by the scale denominators and put the results in t3, t4: - // - t3 = numerator() * t1; - t4 = b.numerator() * t2; - // - // Add them up: - // - t3 += t4; - // - // Get the gcd of gcd and our numerator (t3): - // - // ERROR: no matching function for call to gcd! We skip this implementation for the moment! - t4 = boost::multiprecision::gcd(t3, gcd); - if (t4 == 1) - { - result_num = t3; - result_denom = t1 * denominator(); - } - else - { - // - // Uncommon case where gcd is not 1, divide the numerator - // and the denominator terms by the new gcd. Note we perform division - // on the existing gcd value as this is the smallest of the 3 denominator - // terms we'll be multiplying together, so there's a good chance it's a - // single limb value already: - // - result_num= CGAL::integral_division(t3, t4); - t3 = CGAL::integral_division( gcd, t4); - t4 = t1 * t2; - result_denom = t4 * t3; - } - } - else - { - // - // Most common case (approx 60%) where gcd is one: - // - t1 = numerator() * b.denominator(); - t2 = denominator() *b.numerator(); - - result_num = t1 + t2; - - result_denom = denominator() * b.denominator(); - - } - - *this = Quotient(result_num,result_denom); - return *this; -#endif - -} - -#else // default impl - -template -CGAL_MEDIUM_INLINE -Quotient& -Quotient::operator+= (const Quotient& r) -{ - num = num * r.den + r.num * den; - den *= r.den; - simplify_quotient(num, den); - return *this; } -#endif // default impl - template CGAL_MEDIUM_INLINE Quotient& @@ -805,21 +694,16 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } }; - class To_interval - : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { - + #if defined(CGAL_USE_BOOST_MP) + class To_interval_cpp_int + : public CGAL::cpp98::unary_function< Quotient, std::pair< double, double > > { public: - #if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) - - bool are_bounds_correct( const double l, const double u, const Type& x ) const { + bool are_bounds_correct( + const double l, const double u, + const Quotient& x ) const { const double inf = std::numeric_limits::infinity(); - // std::cout << " l: " << l << std::endl; - // std::cout << " u: " << u << std::endl; - // std::cout << "nextafter l: " << nextafter(l, +inf) << std::endl; - // std::cout << std::endl; - CGAL_assertion(u == l || u == std::nextafter(l, +inf)); const bool are_bounds_tight = (u == l || u == std::nextafter(l, +inf)); @@ -835,16 +719,22 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(CGAL::abs(l) != 0.0); CGAL_assertion(CGAL::abs(u) != 0.0); - const Type lb(l), ub(u); + const Quotient lb(l), ub(u); CGAL_assertion(lb <= x); CGAL_assertion(ub >= x); const bool are_bounds_respected = (lb <= x && x <= ub); - return are_bounds_tight && are_bounds_respected; } /* - std::pair< Interval_nt<>, int64_t > get_interval_exp( NT& x ) const { + // Option 1. + // Inspired by the one from the gmpzf type. + // Seems to be less precise and we rarely end up with an interval [d,d] + // even for numbers, which are exactly representable as double. + // Otherwise, it is quite similar to the results of the Option 3. + // It does not guarantee tight intervals! + std::pair< Interval_nt<>, int64_t > get_interval_exp( + boost::multiprecision::cpp_int& x ) const { CGAL_assertion(CGAL::is_positive(x)); int64_t d = 0; @@ -869,9 +759,10 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > return std::make_pair( Interval_nt<>(l, u), d ); } - std::pair get_interval_as_gmpzf( Type x ) const { + std::pair get_interval_as_gmpzf( + Quotient x ) const { - CGAL_assertion_code(const Type input = x); + CGAL_assertion_code(const Quotient input = x); double l = 0.0, u = 0.0; if (CGAL::is_zero(x.num)) { // return [0.0, 0.0] CGAL_assertion(are_bounds_correct(l, u, input)); @@ -913,9 +804,76 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > return std::make_pair(l, u); } */ - // TODO: This is a temporary implementation and should be replaced - // by the default one. Can we use int64_t for e here? - No, because we - // would not be able to run ldexp on it. + /* + // Option 3. + // This one requires a temporary conversion to cpp_rational and + // it does not guarantee tight intervals! It has intervals similar to the + // intervals produced by the Option 1. + std::pair interval_from_cpp_rational( + const Quotient& x ) const { + + // Seems fast enough because this conversion happens + // only a few times during the run, at least for NEF. + boost::multiprecision::cpp_rational rat; + CGAL_assertion(!CGAL::is_zero(x.den)); + if (CGAL::is_negative(x.den)) { + rat = boost::multiprecision::cpp_rational(-x.num, -x.den); + } else { + CGAL_assertion(CGAL::is_positive(x.den)); + rat = boost::multiprecision::cpp_rational( x.num, x.den); + } + + double l, u; + std::tie(l, u) = to_interval(rat); // fails if boost_mp is not included! + const double inf = std::numeric_limits::infinity(); + + if (l == +inf) { + l = (std::numeric_limits::max)(); + CGAL_assertion(u == +inf); + } else if (u == -inf) { + u = std::numeric_limits::lowest(); + CGAL_assertion(l == -inf); + } + + CGAL_assertion(are_bounds_correct(l, u, x)); + return std::make_pair(l, u); + } + + std::pair get_interval_using_cpp_rational( + const Quotient& x ) const { + + const double inf = std::numeric_limits::infinity(); + + const Interval_nt<> xn = Interval_nt<>(CGAL_NTS to_interval(x.num)); + if (CGAL::abs(xn.inf()) == inf || CGAL::abs(xn.sup()) == inf) { + return interval_from_cpp_rational(x); + } + CGAL_assertion(CGAL::abs(xn.inf()) != inf && CGAL::abs(xn.sup()) != inf); + + const Interval_nt<> xd = Interval_nt<>(CGAL_NTS to_interval(x.den)); + if (CGAL::abs(xd.inf()) == inf || CGAL::abs(xd.sup()) == inf) { + return interval_from_cpp_rational(x); + } + CGAL_assertion(CGAL::abs(xd.inf()) != inf && CGAL::abs(xd.sup()) != inf); + + const Interval_nt<> quot = xn / xd; + CGAL_assertion(are_bounds_correct(quot.inf(), quot.sup(), x)); + return std::make_pair(quot.inf(), quot.sup()); + } */ + + // TODO: This is a temporary implementation and + // should be replaced by the default one. The default one fails: + // For some reason, CGAL::ldexp on Interval_nt returns + // 2.752961027411077506e-308 instead of denorm_min! We can work it around: + + // See get_1ulp_interval() below: + // const auto res = CGAL::ldexp(intv, -static_cast(shift)).pair(); + // if (res.first == 0.0) { + // CGAL_assertion(res.second != 0.0); + // return std::make_pair(0.0, CGAL_IA_MIN_DOUBLE); + // } + // return res; + Interval_nt my_ldexp( const Interval_nt& intv, const int e ) const { @@ -925,63 +883,41 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > return Interval_nt ( CGAL_NTS is_finite(scale) ? scale * intv.inf() : CGAL_IA_MAX_DOUBLE, - scale == 0.0 ? CGAL_IA_MIN_DOUBLE : scale * intv.sup()); + scale == 0.0 ? CGAL_IA_MIN_DOUBLE : scale * intv.sup() ); } - std::pair get_0ulp_interval( const int64_t shift, const NT& p ) const { - - // std::cout << "- 0ulp interval: " << std::endl; + std::pair get_0ulp_interval( + const int64_t shift, + const boost::multiprecision::cpp_int& p ) const { CGAL_assertion(p >= 0); const uint64_t pp = static_cast(p); - CGAL_assertion(pp >= 0); const double pp_dbl = static_cast(pp); - - // std::cout << "pp_dbl: " << pp_dbl << std::endl; - // std::cout << "qq_dbl: " << pp_dbl << std::endl; - - // TODO: Should we use false? const Interval_nt intv(pp_dbl, pp_dbl); return my_ldexp(intv, -static_cast(shift)).pair(); } - std::pair get_1ulp_interval( const int64_t shift, const NT& p ) const { - - // std::cout << "- 1ulp interval: " << std::endl; + std::pair get_1ulp_interval( + const int64_t shift, + const boost::multiprecision::cpp_int& p ) const { CGAL_assertion(p >= 0); const uint64_t pp = static_cast(p); - const uint64_t qq = static_cast(pp + 1); - + const uint64_t qq = pp + 1; CGAL_assertion(pp >= 0); CGAL_assertion(qq > pp); const double pp_dbl = static_cast(pp); const double qq_dbl = static_cast(qq); - - // std::cout << "pp_dbl: " << pp_dbl << std::endl; - // std::cout << "qq_dbl: " << qq_dbl << std::endl; - - // std::cout << "pp_dbl ldexp: " << std::ldexp(pp_dbl, -shift) << std::endl; - // std::cout << "qq_dbl ldexp: " << std::ldexp(qq_dbl, -shift) << std::endl; - const Interval_nt intv(pp_dbl, qq_dbl); - /* const auto res = */ return my_ldexp(intv, -static_cast(shift)).pair(); - - // TODO: For some reason, ldexp returns 2.752961027411077506e-308 - // instead of denorm_min! - // if (res.first == 0.0) { - // CGAL_assertion(res.second != 0.0); - // return std::make_pair(0.0, CGAL_IA_MIN_DOUBLE); - // } - // return res; } - std::pair get_interval_as_boost( Type x ) const { + std::pair operator()( + Quotient x ) const { CGAL_assertion(!CGAL::is_zero(x.den)); - CGAL_assertion_code(const Type input = x); + CGAL_assertion_code(const Quotient input = x); double l = 0.0, u = 0.0; if (CGAL::is_zero(x.num)) { // return [0.0, 0.0] CGAL_assertion(are_bounds_correct(l, u, input)); @@ -1011,14 +947,6 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > const int64_t msb_diff = msb_num - msb_den; int64_t shift = num_dbl_digits - msb_diff; - // std::cout << "msb num: " << msb_num << std::endl; - // std::cout << "msb den: " << msb_den << std::endl; - // std::cout << "msb diff: " << msb_diff << std::endl; - // std::cout << " shift: " << shift << std::endl; - - // std::cout << "x num: " << x.num << std::endl; - // std::cout << "x den: " << x.den << std::endl; - if (shift > 0) { CGAL_assertion(msb_diff < num_dbl_digits); x.num <<= +shift; @@ -1030,95 +958,34 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > static_cast(boost::multiprecision::msb(x.num)) - static_cast(boost::multiprecision::msb(x.den))); - NT p, r; + boost::multiprecision::cpp_int p, r; boost::multiprecision::divide_qr(x.num, x.den, p, r); const int64_t p_bits = static_cast(boost::multiprecision::msb(p)); - // std::cout << "x num shifted: " << x.num << std::endl; - // std::cout << "x den shifted: " << x.den << std::endl; - - // std::cout << "p bits: " << p_bits << std::endl; - - // std::cout << "p: " << p << std::endl; - // std::cout << "r: " << r << std::endl; - - // std::vector b; - // export_bits(p, std::back_inserter(b), 1); - // std::cout << "binary: "; - // for (const unsigned char bit : b) { - // std::cout << static_cast(bit); - // } - // std::cout << std::endl; - if (r == 0) { - // std::cout << "- case r = 0" << std::endl; std::tie(l, u) = get_0ulp_interval(shift, p); } else { - // std::cout << "- case r > 0" << std::endl; - CGAL_assertion(r > 0); CGAL_assertion(r < x.den); if (p_bits == num_dbl_digits - 1) { // we did not reach full precision - // x.num <<= 1; - // boost::multiprecision::divide_qr(x.num, x.den, p, r); - // std::cout << "p bits shifted: " << boost::multiprecision::msb(p) << std::endl; - // std::cout << "p: " << p << std::endl; - // std::cout << "r: " << r << std::endl; - // std::tie(l, u) = get_1ulp_interval(shift+1, p); - - // if (shift > 0) { - // std::cout << "- case p_bits = 51 && shift > 0" << std::endl; - // // CGAL_assertion_msg(false, "TODO: SHIFT > 0!"); - - // p <<= 1; - // r <<= 1; - // ++shift; - // } else { - // std::cout << "- case p_bits = 51 && shift < 0" << std::endl; - // // CGAL_assertion_msg(false, "TODO: SHIFT < 0!"); - - // CGAL_assertion(shift < 0); - // p <<= 1; - // r <<= 1; - // ++shift; - // } - p <<= 1; r <<= 1; ++shift; - // std::cout << "p_bits shifted: " << boost::multiprecision::msb(p) << std::endl; CGAL_assertion(r > 0); const int cmp = r.compare(x.den); - // std::cout << "cmp: " << cmp << std::endl; - // std::cout << "p & 1u: " << (p & 1u) << std::endl; if (cmp > 0) { - - // std::cout << "subcase 1" << std::endl; - // CGAL_assertion_msg(false, "TODO: SUBCASE1!"); - ++p; std::tie(l, u) = get_1ulp_interval(shift, p); - - } else if ( (cmp == 0) /* && (p & 1u) */ ) { - - // std::cout << "subcase 2" << std::endl; - // CGAL_assertion_msg(false, "TODO: SUBCASE2!"); - + } else if (cmp == 0) { ++p; std::tie(l, u) = get_0ulp_interval(shift, p); - } else { - - // std::cout << "subcase 3" << std::endl; - // CGAL_assertion_msg(false, "TODO: SUBCASE3!"); - std::tie(l, u) = get_1ulp_interval(shift, p); } } else { - // std::cout << "- case p_bits = 52" << std::endl; std::tie(l, u) = get_1ulp_interval(shift, p); } } @@ -1132,95 +999,29 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > CGAL_assertion(are_bounds_correct(l, u, input)); return std::make_pair(l, u); } + }; + #endif // CGAL_USE_BOOST_MP - /* - std::pair interval_from_cpp_rational( const Type& x ) const { - - // Seems fast enough because this conversion happens - // only a few times during the run, at least for NEF. - boost::multiprecision::cpp_rational rat; - CGAL_assertion(!CGAL::is_zero(x.den)); - if (CGAL::is_negative(x.den)) { - rat = boost::multiprecision::cpp_rational(-x.num, -x.den); - } else { - CGAL_assertion(CGAL::is_positive(x.den)); - rat = boost::multiprecision::cpp_rational( x.num, x.den); - } - - double l, u; - std::tie(l, u) = to_interval(rat); // TODO: fails if boost_mp is not included! - const double inf = std::numeric_limits::infinity(); - - if (l == +inf) { - l = (std::numeric_limits::max)(); - CGAL_assertion(u == +inf); - } else if (u == -inf) { - u = std::numeric_limits::lowest(); - CGAL_assertion(l == -inf); - } - - CGAL_assertion(are_bounds_correct(l, u, x)); - return std::make_pair(l, u); - } - - std::pair get_interval_using_cpp_rational( const Type& x ) const { - - const double inf = std::numeric_limits::infinity(); - - const Interval_nt<> xn = Interval_nt<>(CGAL_NTS to_interval(x.num)); - if (CGAL::abs(xn.inf()) == inf || CGAL::abs(xn.sup()) == inf) { - return interval_from_cpp_rational(x); - } - CGAL_assertion(CGAL::abs(xn.inf()) != inf && CGAL::abs(xn.sup()) != inf); - - const Interval_nt<> xd = Interval_nt<>(CGAL_NTS to_interval(x.den)); - if (CGAL::abs(xd.inf()) == inf || CGAL::abs(xd.sup()) == inf) { - return interval_from_cpp_rational(x); - } - CGAL_assertion(CGAL::abs(xd.inf()) != inf && CGAL::abs(xd.sup()) != inf); - - const Interval_nt<> quot = xn / xd; - CGAL_assertion(are_bounds_correct(quot.inf(), quot.sup(), x)); - return std::make_pair(quot.inf(), quot.sup()); - } */ - - #endif // CPP_INT - + class To_interval_generic + : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { + public: std::pair operator()( const Type& x ) const { - - #if defined(CGAL_USE_CPP_INT) || !defined(CGAL_DO_NOT_RUN_TESTME) - - // Option 1. - // Seems to be less precise and we rarely end up with an interval [d,d] - // even for numbers, which are exactly representable as double. - // Otherwise, it is quite similar to the results of the option 3. - // return get_interval_as_gmpzf(x); - - // Option 2. - // Works slightly better than the first one. - // It always returns a correct interval, but it is sometimes less tight - // than the one from the option 3. - return get_interval_as_boost(x); - - // Option 3. - // This seems to give the tightest intervals. - // return get_interval_using_cpp_rational(x); - - #else // master version - - #if defined(CGAL_USE_TO_INTERVAL_WITH_BOOST) - return std::make_pair(static_cast(x.num), static_cast(x.den)); - #else const Interval_nt<> quot = - Interval_nt<>(CGAL_NTS to_interval(x.numerator())) / - Interval_nt<>(CGAL_NTS to_interval(x.denominator())); + Interval_nt<>(CGAL_NTS to_interval(x.numerator())) / + Interval_nt<>(CGAL_NTS to_interval(x.denominator())); return std::make_pair(quot.inf(), quot.sup()); - #endif - - #endif // master version } }; + #ifdef CGAL_USE_BOOST_MP + typedef typename std::conditional< + std::is_same::value, + To_interval_cpp_int, + To_interval_generic >::type To_interval; + #else + typedef To_interval_generic To_interval; + #endif + class Is_finite : public CGAL::cpp98::unary_function< Type, bool > { public: diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 3d2f5531ca21..53a510dab21a 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -20,7 +20,8 @@ // MSVC had trouble with versions <= 1.69: // https://github.com/boostorg/multiprecision/issues/98 #if !defined CGAL_DO_NOT_USE_BOOST_MP && \ - (!defined _MSC_VER || BOOST_VERSION >= 107000) || !defined(CGAL_DO_NOT_RUN_TESTME) + (!defined _MSC_VER || BOOST_VERSION >= 107000) || \ + defined CGAL_USE_CPP_INT || !defined CGAL_DO_NOT_RUN_TESTME #define CGAL_USE_BOOST_MP 1 #include // *ary_function @@ -318,7 +319,7 @@ struct RET_boost_mp_base_rational return Interval_nt ( CGAL_NTS is_finite(scale) ? scale * intv.inf() : CGAL_IA_MAX_DOUBLE, - scale == 0.0 ? CGAL_IA_MIN_DOUBLE : scale * intv.sup()); + scale == 0.0 ? CGAL_IA_MIN_DOUBLE : scale * intv.sup() ); } template @@ -337,7 +338,7 @@ struct RET_boost_mp_base_rational CGAL_assertion(p >= 0); const uint64_t pp = static_cast(p); - const uint64_t qq = static_cast(pp + 1); + const uint64_t qq = pp + 1; CGAL_assertion(pp >= 0); CGAL_assertion(qq > pp); const double pp_dbl = static_cast(pp); From 3ef9beef9256c3d29bb66efa1ef34cdf14ecb050 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 20 Sep 2021 17:19:46 +0200 Subject: [PATCH 081/127] correctly overload to_interval for boost types --- Number_types/include/CGAL/boost_mp.h | 120 ++++----------------------- 1 file changed, 17 insertions(+), 103 deletions(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 53a510dab21a..2d24408dcdd2 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -13,6 +13,7 @@ #define CGAL_BOOST_MP_H #include +#include // It is easier to disable this number type completely for old versions. // Before 1.63, I/O is broken. Again, disabling the whole file is just the @@ -201,16 +202,20 @@ struct RET_boost_mp_base // assume the conversion is within 1 ulp // adding IA::smallest() doesn't work because inf-e=inf, even rounded down. - // We must use to_nearest with cpp_int. + // We must use to_nearest here. double i; const double inf = std::numeric_limits::infinity(); { Protect_FPU_rounding P(CGAL_FE_TONEAREST); i = static_cast(x); - if (CGAL::abs(i) == inf) return std::make_pair(i, i); + if (i == +inf) { + return std::make_pair((std::numeric_limits::max)(), i); + } else if (i == -inf) { + return std::make_pair(i, std::numeric_limits::lowest()); + } } double s = i; - CGAL_assertion(i != inf && s != inf); + CGAL_assertion(CGAL::abs(i) != inf && CGAL::abs(s) != inf); // Throws uncaught exception: Cannot convert a non-finite number to an integer. // We can catch it earlier by using the CGAL_assertion() one line above. @@ -228,63 +233,20 @@ struct RET_boost_mp_base }; }; +template ::value> > +struct RET_boost_mp; + template -struct RET_boost_mp_base_rational - : public INTERN_RET::Real_embeddable_traits_base< NT , CGAL::Tag_true > { +struct RET_boost_mp > + : RET_boost_mp_base {}; +template +struct RET_boost_mp > + : RET_boost_mp_base { typedef NT Type; - - struct Is_zero: public CGAL::cpp98::unary_function { - bool operator()( const Type& x) const { - return x.is_zero(); - } - }; - - struct Is_positive: public CGAL::cpp98::unary_function { - bool operator()( const Type& x) const { - return x.sign() > 0; - } - }; - - struct Is_negative: public CGAL::cpp98::unary_function { - bool operator()( const Type& x) const { - return x.sign() < 0; - } - }; - - struct Abs : public CGAL::cpp98::unary_function { - template - Type operator()(const T& x) const { - return boost::multiprecision::abs(x); - } - }; - - struct Sgn : public CGAL::cpp98::unary_function { - ::CGAL::Sign operator()(Type const& x) const { - return CGAL::sign(x.sign()); - } - }; - - struct Compare - : public CGAL::cpp98::binary_function { - Comparison_result operator()(const Type& x, const Type& y) const { - return CGAL::sign(x.compare(y)); - } - }; - - struct To_double - : public CGAL::cpp98::unary_function { - double operator()(const Type& x) const { - return x.template convert_to(); - } - }; - struct To_interval : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { - // #if defined(CGAL_USE_TO_INTERVAL_WITH_BOOST) // test boost devel - use when the default is Quotient - #if !defined(CGAL_DO_NOT_RUN_TESTME) || defined(CGAL_USE_TO_INTERVAL_WITH_BOOST) // test boost devel - use when the default is cpp_rational - bool are_bounds_correct( const double l, const double u, const Type& x ) const { const double inf = std::numeric_limits::infinity(); @@ -347,8 +309,7 @@ struct RET_boost_mp_base_rational return my_ldexp(intv, -static_cast(shift)).pair(); } - std::pair - operator()(const Type& x) const { + std::pair operator()( const Type& x ) const { auto xnum = boost::multiprecision::numerator(x); auto xden = boost::multiprecision::denominator(x); @@ -436,56 +397,9 @@ struct RET_boost_mp_base_rational CGAL_assertion(are_bounds_correct(l, u, input)); return std::make_pair(l, u); } - - #else // default impl - - std::pair - operator()(const Type& x) const { - - // See if https://github.com/boostorg/multiprecision/issues/108 suggests anything better - // assume the conversion is within 1 ulp - // adding IA::smallest() doesn't work because inf-e=inf, even rounded down. - - // We must use to_nearest with cpp_int. - double i; - const double inf = std::numeric_limits::infinity(); - { - Protect_FPU_rounding P(CGAL_FE_TONEAREST); - i = static_cast(x); - if (CGAL::abs(i) == inf) return std::make_pair(i, i); - } - double s = i; - CGAL_assertion(i != inf && s != inf); - - // Throws uncaught exception: Cannot convert a non-finite number to an integer. - // We can catch it earlier by using the CGAL_assertion() one line above. - const int cmp = x.compare(i); - if (cmp > 0) { - s = nextafter(s, +inf); - CGAL_assertion(x.compare(s) < 0); - } - else if (cmp < 0) { - i = nextafter(i, -inf); - CGAL_assertion(x.compare(i) > 0); - } - return std::pair(i, s); - } - - #endif // default impl }; }; -template ::value> > -struct RET_boost_mp; - -template -struct RET_boost_mp > - : RET_boost_mp_base {}; - -template -struct RET_boost_mp > - : RET_boost_mp_base_rational {}; - #ifdef CGAL_USE_MPFR // Because of these full specializations, things get instantiated more eagerly. Make them artificially partial if necessary. template <> From 94a7121fde144986e568a63db96d9d8c41d184ad Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 21 Sep 2021 14:38:03 +0200 Subject: [PATCH 082/127] moved quotient with cpp_int stuff to boost mp --- Number_types/include/CGAL/Quotient.h | 330 +-------------------------- Number_types/include/CGAL/boost_mp.h | 319 ++++++++++++++++++++++++++ 2 files changed, 320 insertions(+), 329 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index a474e4f0f654..23e22a54b78a 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -31,7 +31,6 @@ #include #include -#include #include @@ -47,16 +46,6 @@ template < typename NT > inline void simplify_quotient(NT & , NT & ) {} -#ifdef CGAL_USE_BOOST_MP - template < > - inline void - simplify_quotient(boost::multiprecision::cpp_int & a, boost::multiprecision::cpp_int & b) { - const boost::multiprecision::cpp_int r = boost::multiprecision::gcd(a, b); - a /= r; - b /= r; - } -#endif // CGAL_USE_BOOST_MP - // This one should be replaced by some functor or tag. // Meanwhile, the class is specialized for Gmpz, mpz_class, leda_integer. template < typename NT > @@ -694,315 +683,7 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } }; - #if defined(CGAL_USE_BOOST_MP) - class To_interval_cpp_int - : public CGAL::cpp98::unary_function< Quotient, std::pair< double, double > > { - public: - - bool are_bounds_correct( - const double l, const double u, - const Quotient& x ) const { - - const double inf = std::numeric_limits::infinity(); - CGAL_assertion(u == l || u == std::nextafter(l, +inf)); - const bool are_bounds_tight = (u == l || u == std::nextafter(l, +inf)); - - if ( - CGAL::abs(l) == inf || - CGAL::abs(u) == inf || - CGAL::abs(l) == 0.0 || - CGAL::abs(u) == 0.0) { - return are_bounds_tight; - } - CGAL_assertion(CGAL::abs(l) != inf); - CGAL_assertion(CGAL::abs(u) != inf); - CGAL_assertion(CGAL::abs(l) != 0.0); - CGAL_assertion(CGAL::abs(u) != 0.0); - - const Quotient lb(l), ub(u); - CGAL_assertion(lb <= x); - CGAL_assertion(ub >= x); - const bool are_bounds_respected = (lb <= x && x <= ub); - return are_bounds_tight && are_bounds_respected; - } - - /* - // Option 1. - // Inspired by the one from the gmpzf type. - // Seems to be less precise and we rarely end up with an interval [d,d] - // even for numbers, which are exactly representable as double. - // Otherwise, it is quite similar to the results of the Option 3. - // It does not guarantee tight intervals! - std::pair< Interval_nt<>, int64_t > get_interval_exp( - boost::multiprecision::cpp_int& x ) const { - - CGAL_assertion(CGAL::is_positive(x)); - int64_t d = 0; - double l = 0.0, u = 0.0; - const int64_t n = static_cast(boost::multiprecision::msb(x)) + 1; - const int64_t num_dbl_digits = std::numeric_limits::digits; - - if (n > num_dbl_digits) { - d = n - num_dbl_digits; - x >>= d; - const uint64_t xx = static_cast(x); - const uint64_t yy = xx + 1; - CGAL_assertion(xx > 0 && yy > xx); - l = static_cast(xx); - u = static_cast(yy); - } else { - const uint64_t xx = static_cast(x); - CGAL_assertion(xx > 0); - l = static_cast(xx); - u = l; - } - return std::make_pair( Interval_nt<>(l, u), d ); - } - - std::pair get_interval_as_gmpzf( - Quotient x ) const { - - CGAL_assertion_code(const Quotient input = x); - double l = 0.0, u = 0.0; - if (CGAL::is_zero(x.num)) { // return [0.0, 0.0] - CGAL_assertion(are_bounds_correct(l, u, input)); - return std::make_pair(l, u); - } - CGAL_assertion(!CGAL::is_zero(x.num)); - CGAL_assertion(!CGAL::is_zero(x.den)); - - // Handle signs. - bool change_sign = false; - const bool is_num_pos = CGAL::is_positive(x.num); - const bool is_den_pos = CGAL::is_positive(x.den); - if (!is_num_pos && !is_den_pos) { - x.num = -x.num; - x.den = -x.den; - } else if (!is_num_pos && is_den_pos) { - change_sign = true; - x.num = -x.num; - } else if (is_num_pos && !is_den_pos) { - change_sign = true; - x.den = -x.den; - } - CGAL_assertion(CGAL::is_positive(x.num) && CGAL::is_positive(x.den)); - - const auto num = get_interval_exp(x.num); - const auto den = get_interval_exp(x.den); - - const Interval_nt<> div = num.first / den.first; - const int64_t e = num.second - den.second; - std::tie(l, u) = ldexp(div, e).pair(); - - if (change_sign) { - const double t = l; - l = -u; - u = -t; - } - - CGAL_assertion(are_bounds_correct(l, u, input)); - return std::make_pair(l, u); - } */ - - /* - // Option 3. - // This one requires a temporary conversion to cpp_rational and - // it does not guarantee tight intervals! It has intervals similar to the - // intervals produced by the Option 1. - std::pair interval_from_cpp_rational( - const Quotient& x ) const { - - // Seems fast enough because this conversion happens - // only a few times during the run, at least for NEF. - boost::multiprecision::cpp_rational rat; - CGAL_assertion(!CGAL::is_zero(x.den)); - if (CGAL::is_negative(x.den)) { - rat = boost::multiprecision::cpp_rational(-x.num, -x.den); - } else { - CGAL_assertion(CGAL::is_positive(x.den)); - rat = boost::multiprecision::cpp_rational( x.num, x.den); - } - - double l, u; - std::tie(l, u) = to_interval(rat); // fails if boost_mp is not included! - const double inf = std::numeric_limits::infinity(); - - if (l == +inf) { - l = (std::numeric_limits::max)(); - CGAL_assertion(u == +inf); - } else if (u == -inf) { - u = std::numeric_limits::lowest(); - CGAL_assertion(l == -inf); - } - - CGAL_assertion(are_bounds_correct(l, u, x)); - return std::make_pair(l, u); - } - - std::pair get_interval_using_cpp_rational( - const Quotient& x ) const { - - const double inf = std::numeric_limits::infinity(); - - const Interval_nt<> xn = Interval_nt<>(CGAL_NTS to_interval(x.num)); - if (CGAL::abs(xn.inf()) == inf || CGAL::abs(xn.sup()) == inf) { - return interval_from_cpp_rational(x); - } - CGAL_assertion(CGAL::abs(xn.inf()) != inf && CGAL::abs(xn.sup()) != inf); - - const Interval_nt<> xd = Interval_nt<>(CGAL_NTS to_interval(x.den)); - if (CGAL::abs(xd.inf()) == inf || CGAL::abs(xd.sup()) == inf) { - return interval_from_cpp_rational(x); - } - CGAL_assertion(CGAL::abs(xd.inf()) != inf && CGAL::abs(xd.sup()) != inf); - - const Interval_nt<> quot = xn / xd; - CGAL_assertion(are_bounds_correct(quot.inf(), quot.sup(), x)); - return std::make_pair(quot.inf(), quot.sup()); - } */ - - // TODO: This is a temporary implementation and - // should be replaced by the default one. The default one fails: - // For some reason, CGAL::ldexp on Interval_nt returns - // 2.752961027411077506e-308 instead of denorm_min! We can work it around: - - // See get_1ulp_interval() below: - // const auto res = CGAL::ldexp(intv, -static_cast(shift)).pair(); - // if (res.first == 0.0) { - // CGAL_assertion(res.second != 0.0); - // return std::make_pair(0.0, CGAL_IA_MIN_DOUBLE); - // } - // return res; - - Interval_nt - my_ldexp( const Interval_nt& intv, const int e ) const { - - CGAL_assertion(intv.inf() > 0.0); - CGAL_assertion(intv.sup() > 0.0); - const double scale = std::ldexp(1.0, e); - return Interval_nt ( - CGAL_NTS is_finite(scale) ? - scale * intv.inf() : CGAL_IA_MAX_DOUBLE, - scale == 0.0 ? CGAL_IA_MIN_DOUBLE : scale * intv.sup() ); - } - - std::pair get_0ulp_interval( - const int64_t shift, - const boost::multiprecision::cpp_int& p ) const { - - CGAL_assertion(p >= 0); - const uint64_t pp = static_cast(p); - CGAL_assertion(pp >= 0); - const double pp_dbl = static_cast(pp); - const Interval_nt intv(pp_dbl, pp_dbl); - return my_ldexp(intv, -static_cast(shift)).pair(); - } - - std::pair get_1ulp_interval( - const int64_t shift, - const boost::multiprecision::cpp_int& p ) const { - - CGAL_assertion(p >= 0); - const uint64_t pp = static_cast(p); - const uint64_t qq = pp + 1; - CGAL_assertion(pp >= 0); - CGAL_assertion(qq > pp); - const double pp_dbl = static_cast(pp); - const double qq_dbl = static_cast(qq); - const Interval_nt intv(pp_dbl, qq_dbl); - return my_ldexp(intv, -static_cast(shift)).pair(); - } - - std::pair operator()( - Quotient x ) const { - - CGAL_assertion(!CGAL::is_zero(x.den)); - CGAL_assertion_code(const Quotient input = x); - double l = 0.0, u = 0.0; - if (CGAL::is_zero(x.num)) { // return [0.0, 0.0] - CGAL_assertion(are_bounds_correct(l, u, input)); - return std::make_pair(l, u); - } - CGAL_assertion(!CGAL::is_zero(x.num)); - - // Handle signs. - bool change_sign = false; - const bool is_num_pos = CGAL::is_positive(x.num); - const bool is_den_pos = CGAL::is_positive(x.den); - if (!is_num_pos && !is_den_pos) { - x.num = -x.num; - x.den = -x.den; - } else if (!is_num_pos && is_den_pos) { - change_sign = true; - x.num = -x.num; - } else if (is_num_pos && !is_den_pos) { - change_sign = true; - x.den = -x.den; - } - CGAL_assertion(CGAL::is_positive(x.num) && CGAL::is_positive(x.den)); - - const int64_t num_dbl_digits = std::numeric_limits::digits - 1; - const int64_t msb_num = static_cast(boost::multiprecision::msb(x.num)); - const int64_t msb_den = static_cast(boost::multiprecision::msb(x.den)); - const int64_t msb_diff = msb_num - msb_den; - int64_t shift = num_dbl_digits - msb_diff; - - if (shift > 0) { - CGAL_assertion(msb_diff < num_dbl_digits); - x.num <<= +shift; - } else if (shift < 0) { - CGAL_assertion(msb_diff > num_dbl_digits); - x.den <<= -shift; - } - CGAL_assertion(num_dbl_digits == - static_cast(boost::multiprecision::msb(x.num)) - - static_cast(boost::multiprecision::msb(x.den))); - - boost::multiprecision::cpp_int p, r; - boost::multiprecision::divide_qr(x.num, x.den, p, r); - const int64_t p_bits = static_cast(boost::multiprecision::msb(p)); - - if (r == 0) { - std::tie(l, u) = get_0ulp_interval(shift, p); - } else { - CGAL_assertion(r > 0); - CGAL_assertion(r < x.den); - if (p_bits == num_dbl_digits - 1) { // we did not reach full precision - - p <<= 1; - r <<= 1; - ++shift; - - CGAL_assertion(r > 0); - const int cmp = r.compare(x.den); - if (cmp > 0) { - ++p; - std::tie(l, u) = get_1ulp_interval(shift, p); - } else if (cmp == 0) { - ++p; - std::tie(l, u) = get_0ulp_interval(shift, p); - } else { - std::tie(l, u) = get_1ulp_interval(shift, p); - } - - } else { - std::tie(l, u) = get_1ulp_interval(shift, p); - } - } - - if (change_sign) { - const double t = l; - l = -u; - u = -t; - } - - CGAL_assertion(are_bounds_correct(l, u, input)); - return std::make_pair(l, u); - } - }; - #endif // CGAL_USE_BOOST_MP - - class To_interval_generic + class To_interval : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { public: std::pair operator()( const Type& x ) const { @@ -1013,15 +694,6 @@ template < class NT > class Real_embeddable_traits_quotient_base< Quotient > } }; - #ifdef CGAL_USE_BOOST_MP - typedef typename std::conditional< - std::is_same::value, - To_interval_cpp_int, - To_interval_generic >::type To_interval; - #else - typedef To_interval_generic To_interval; - #endif - class Is_finite : public CGAL::cpp98::unary_function< Type, bool > { public: diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 2d24408dcdd2..7b50105f3511 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -782,6 +782,325 @@ namespace internal { #endif } // namespace internal +#ifdef CGAL_USE_BOOST_MP + +template < > +inline void +simplify_quotient(boost::multiprecision::cpp_int & a, boost::multiprecision::cpp_int & b) { + const boost::multiprecision::cpp_int r = boost::multiprecision::gcd(a, b); + a /= r; + b /= r; +} + +template< > class Real_embeddable_traits< Quotient > + : public INTERN_QUOTIENT::Real_embeddable_traits_quotient_base< Quotient > { + + public: + typedef Quotient Type; + + class To_interval + : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { + public: + + bool are_bounds_correct( const double l, const double u, const Type& x ) const { + + const double inf = std::numeric_limits::infinity(); + CGAL_assertion(u == l || u == std::nextafter(l, +inf)); + const bool are_bounds_tight = (u == l || u == std::nextafter(l, +inf)); + + if ( + CGAL::abs(l) == inf || + CGAL::abs(u) == inf || + CGAL::abs(l) == 0.0 || + CGAL::abs(u) == 0.0) { + return are_bounds_tight; + } + CGAL_assertion(CGAL::abs(l) != inf); + CGAL_assertion(CGAL::abs(u) != inf); + CGAL_assertion(CGAL::abs(l) != 0.0); + CGAL_assertion(CGAL::abs(u) != 0.0); + + const Type lb(l), ub(u); + CGAL_assertion(lb <= x); + CGAL_assertion(ub >= x); + const bool are_bounds_respected = (lb <= x && x <= ub); + return are_bounds_tight && are_bounds_respected; + } + + /* + // Option 1. + // Inspired by the one from the gmpzf type. + // Seems to be less precise and we rarely end up with an interval [d,d] + // even for numbers, which are exactly representable as double. + // Otherwise, it is quite similar to the results of the Option 3. + // It does not guarantee tight intervals! + std::pair< Interval_nt<>, int64_t > get_interval_exp( + boost::multiprecision::cpp_int& x ) const { + + CGAL_assertion(CGAL::is_positive(x)); + int64_t d = 0; + double l = 0.0, u = 0.0; + const int64_t n = static_cast(boost::multiprecision::msb(x)) + 1; + const int64_t num_dbl_digits = std::numeric_limits::digits; + + if (n > num_dbl_digits) { + d = n - num_dbl_digits; + x >>= d; + const uint64_t xx = static_cast(x); + const uint64_t yy = xx + 1; + CGAL_assertion(xx > 0 && yy > xx); + l = static_cast(xx); + u = static_cast(yy); + } else { + const uint64_t xx = static_cast(x); + CGAL_assertion(xx > 0); + l = static_cast(xx); + u = l; + } + return std::make_pair( Interval_nt<>(l, u), d ); + } + + std::pair get_interval_as_gmpzf( Type x ) const { + + CGAL_assertion_code(const Type input = x); + double l = 0.0, u = 0.0; + if (CGAL::is_zero(x.num)) { // return [0.0, 0.0] + CGAL_assertion(are_bounds_correct(l, u, input)); + return std::make_pair(l, u); + } + CGAL_assertion(!CGAL::is_zero(x.num)); + CGAL_assertion(!CGAL::is_zero(x.den)); + + // Handle signs. + bool change_sign = false; + const bool is_num_pos = CGAL::is_positive(x.num); + const bool is_den_pos = CGAL::is_positive(x.den); + if (!is_num_pos && !is_den_pos) { + x.num = -x.num; + x.den = -x.den; + } else if (!is_num_pos && is_den_pos) { + change_sign = true; + x.num = -x.num; + } else if (is_num_pos && !is_den_pos) { + change_sign = true; + x.den = -x.den; + } + CGAL_assertion(CGAL::is_positive(x.num) && CGAL::is_positive(x.den)); + + const auto num = get_interval_exp(x.num); + const auto den = get_interval_exp(x.den); + + const Interval_nt<> div = num.first / den.first; + const int64_t e = num.second - den.second; + std::tie(l, u) = ldexp(div, e).pair(); + + if (change_sign) { + const double t = l; + l = -u; + u = -t; + } + + CGAL_assertion(are_bounds_correct(l, u, input)); + return std::make_pair(l, u); + } */ + + /* + // Option 3. + // This one requires a temporary conversion to cpp_rational and + // it does not guarantee tight intervals! It has intervals similar to the + // intervals produced by the Option 1. + std::pair interval_from_cpp_rational( const Type& x ) const { + + // Seems fast enough because this conversion happens + // only a few times during the run, at least for NEF. + boost::multiprecision::cpp_rational rat; + CGAL_assertion(!CGAL::is_zero(x.den)); + if (CGAL::is_negative(x.den)) { + rat = boost::multiprecision::cpp_rational(-x.num, -x.den); + } else { + CGAL_assertion(CGAL::is_positive(x.den)); + rat = boost::multiprecision::cpp_rational( x.num, x.den); + } + + double l, u; + std::tie(l, u) = to_interval(rat); // fails if boost_mp is not included! + const double inf = std::numeric_limits::infinity(); + + if (l == +inf) { + l = (std::numeric_limits::max)(); + CGAL_assertion(u == +inf); + } else if (u == -inf) { + u = std::numeric_limits::lowest(); + CGAL_assertion(l == -inf); + } + + CGAL_assertion(are_bounds_correct(l, u, x)); + return std::make_pair(l, u); + } + + std::pair get_interval_using_cpp_rational( const Type& x ) const { + + const double inf = std::numeric_limits::infinity(); + + const Interval_nt<> xn = Interval_nt<>(CGAL_NTS to_interval(x.num)); + if (CGAL::abs(xn.inf()) == inf || CGAL::abs(xn.sup()) == inf) { + return interval_from_cpp_rational(x); + } + CGAL_assertion(CGAL::abs(xn.inf()) != inf && CGAL::abs(xn.sup()) != inf); + + const Interval_nt<> xd = Interval_nt<>(CGAL_NTS to_interval(x.den)); + if (CGAL::abs(xd.inf()) == inf || CGAL::abs(xd.sup()) == inf) { + return interval_from_cpp_rational(x); + } + CGAL_assertion(CGAL::abs(xd.inf()) != inf && CGAL::abs(xd.sup()) != inf); + + const Interval_nt<> quot = xn / xd; + CGAL_assertion(are_bounds_correct(quot.inf(), quot.sup(), x)); + return std::make_pair(quot.inf(), quot.sup()); + } */ + + // TODO: This is a temporary implementation and + // should be replaced by the default one. The default one fails: + // For some reason, CGAL::ldexp on Interval_nt returns + // 2.752961027411077506e-308 instead of denorm_min! We can work it around: + + // See get_1ulp_interval() below: + // const auto res = CGAL::ldexp(intv, -static_cast(shift)).pair(); + // if (res.first == 0.0) { + // CGAL_assertion(res.second != 0.0); + // return std::make_pair(0.0, CGAL_IA_MIN_DOUBLE); + // } + // return res; + + Interval_nt + my_ldexp( const Interval_nt& intv, const int e ) const { + + CGAL_assertion(intv.inf() > 0.0); + CGAL_assertion(intv.sup() > 0.0); + const double scale = std::ldexp(1.0, e); + return Interval_nt ( + CGAL_NTS is_finite(scale) ? + scale * intv.inf() : CGAL_IA_MAX_DOUBLE, + scale == 0.0 ? CGAL_IA_MIN_DOUBLE : scale * intv.sup() ); + } + + std::pair get_0ulp_interval( + const int64_t shift, + const boost::multiprecision::cpp_int& p ) const { + + CGAL_assertion(p >= 0); + const uint64_t pp = static_cast(p); + CGAL_assertion(pp >= 0); + const double pp_dbl = static_cast(pp); + const Interval_nt intv(pp_dbl, pp_dbl); + return my_ldexp(intv, -static_cast(shift)).pair(); + } + + std::pair get_1ulp_interval( + const int64_t shift, + const boost::multiprecision::cpp_int& p ) const { + + CGAL_assertion(p >= 0); + const uint64_t pp = static_cast(p); + const uint64_t qq = pp + 1; + CGAL_assertion(pp >= 0); + CGAL_assertion(qq > pp); + const double pp_dbl = static_cast(pp); + const double qq_dbl = static_cast(qq); + const Interval_nt intv(pp_dbl, qq_dbl); + return my_ldexp(intv, -static_cast(shift)).pair(); + } + + std::pair operator()( Type x ) const { + + CGAL_assertion(!CGAL::is_zero(x.den)); + CGAL_assertion_code(const Type input = x); + double l = 0.0, u = 0.0; + if (CGAL::is_zero(x.num)) { // return [0.0, 0.0] + CGAL_assertion(are_bounds_correct(l, u, input)); + return std::make_pair(l, u); + } + CGAL_assertion(!CGAL::is_zero(x.num)); + + // Handle signs. + bool change_sign = false; + const bool is_num_pos = CGAL::is_positive(x.num); + const bool is_den_pos = CGAL::is_positive(x.den); + if (!is_num_pos && !is_den_pos) { + x.num = -x.num; + x.den = -x.den; + } else if (!is_num_pos && is_den_pos) { + change_sign = true; + x.num = -x.num; + } else if (is_num_pos && !is_den_pos) { + change_sign = true; + x.den = -x.den; + } + CGAL_assertion(CGAL::is_positive(x.num) && CGAL::is_positive(x.den)); + + const int64_t num_dbl_digits = std::numeric_limits::digits - 1; + const int64_t msb_num = static_cast(boost::multiprecision::msb(x.num)); + const int64_t msb_den = static_cast(boost::multiprecision::msb(x.den)); + const int64_t msb_diff = msb_num - msb_den; + int64_t shift = num_dbl_digits - msb_diff; + + if (shift > 0) { + CGAL_assertion(msb_diff < num_dbl_digits); + x.num <<= +shift; + } else if (shift < 0) { + CGAL_assertion(msb_diff > num_dbl_digits); + x.den <<= -shift; + } + CGAL_assertion(num_dbl_digits == + static_cast(boost::multiprecision::msb(x.num)) - + static_cast(boost::multiprecision::msb(x.den))); + + boost::multiprecision::cpp_int p, r; + boost::multiprecision::divide_qr(x.num, x.den, p, r); + const int64_t p_bits = static_cast(boost::multiprecision::msb(p)); + + if (r == 0) { + std::tie(l, u) = get_0ulp_interval(shift, p); + } else { + CGAL_assertion(r > 0); + CGAL_assertion(r < x.den); + if (p_bits == num_dbl_digits - 1) { // we did not reach full precision + + p <<= 1; + r <<= 1; + ++shift; + + CGAL_assertion(r > 0); + const int cmp = r.compare(x.den); + if (cmp > 0) { + ++p; + std::tie(l, u) = get_1ulp_interval(shift, p); + } else if (cmp == 0) { + ++p; + std::tie(l, u) = get_0ulp_interval(shift, p); + } else { + std::tie(l, u) = get_1ulp_interval(shift, p); + } + + } else { + std::tie(l, u) = get_1ulp_interval(shift, p); + } + } + + if (change_sign) { + const double t = l; + l = -u; + u = -t; + } + + CGAL_assertion(are_bounds_correct(l, u, input)); + return std::make_pair(l, u); + } + }; +}; + +#endif // CGAL_USE_BOOST_MP + } //namespace CGAL #include From 8b825bc7653eec1f1d7f7301f02657c1542ed6f5 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 21 Sep 2021 16:15:25 +0200 Subject: [PATCH 083/127] missing include --- Number_types/include/CGAL/boost_mp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 7b50105f3511..e6fdd92e5283 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -25,6 +25,7 @@ defined CGAL_USE_CPP_INT || !defined CGAL_DO_NOT_RUN_TESTME #define CGAL_USE_BOOST_MP 1 +#include #include // *ary_function #include #include From ed79fea30ef9b1a96cd054d0b82749db4153f99f Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 23 Sep 2021 13:02:58 +0200 Subject: [PATCH 084/127] fixed wrong defines in boost mp arithmetic kernel --- Arithmetic_kernel/include/CGAL/BOOST_MP_arithmetic_kernel.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Arithmetic_kernel/include/CGAL/BOOST_MP_arithmetic_kernel.h b/Arithmetic_kernel/include/CGAL/BOOST_MP_arithmetic_kernel.h index 8b5273c2121d..b1c1b1532e83 100644 --- a/Arithmetic_kernel/include/CGAL/BOOST_MP_arithmetic_kernel.h +++ b/Arithmetic_kernel/include/CGAL/BOOST_MP_arithmetic_kernel.h @@ -9,8 +9,8 @@ // // Author: Marc Glisse -#ifndef CGAL_GMPXX_ARITHMETIC_KERNEL_H -#define CGAL_GMPXX_ARITHMETIC_KERNEL_H +#ifndef CGAL_BOOST_MP_ARITHMETIC_KERNEL_H +#define CGAL_BOOST_MP_ARITHMETIC_KERNEL_H #include #include From ab3828e0d77bdc11a3dd8f2951fe1261d3d39e2b Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 28 Sep 2021 10:02:35 +0200 Subject: [PATCH 085/127] remove changes from Installation --- Installation/CMakeLists.txt | 23 ------------------- .../modules/CGAL_SetupCGALDependencies.cmake | 3 --- .../cmake/modules/CGAL_SetupGMP.cmake | 17 ++++---------- 3 files changed, 5 insertions(+), 38 deletions(-) diff --git a/Installation/CMakeLists.txt b/Installation/CMakeLists.txt index 84cc57dc100c..16abec88e952 100644 --- a/Installation/CMakeLists.txt +++ b/Installation/CMakeLists.txt @@ -517,11 +517,6 @@ if($ENV{CGAL_DISABLE_GMP}) ON CACHE INTERNAL "") endif() -if($ENV{CGAL_DISABLE_GMPXX}) - set(CGAL_DISABLE_GMPXX - ON - CACHE INTERNAL "") -endif() if(CGAL_DISABLE_GMP) message("Disable the GMP support") list(LENGTH CGAL_ESSENTIAL_3RD_PARTY_LIBRARIES CGAL_ESSENTIAL_LENGTH) @@ -551,24 +546,6 @@ else() file(REMOVE "${CGAL_BINARY_DIR}/include/gmp.h") endif() -if(CGAL_DISABLE_GMPXX) - message("Disable the GMPXX support") - list(REMOVE_ITEM CGAL_ESSENTIAL_3RD_PARTY_LIBRARIES GMPXX) - unset(GMPXX_FOUND) - unset(GMPXX_FOUND CACHE) - unset(CGAL_USE_GMPXX) - unset(CGAL_USE_GMPXX CACHE) - # Nasty trick to make sure is not used when CGAL_DISABLE_GMPXX is TRUE - file(WRITE "${CGAL_BINARY_DIR}/include/gmpxx.h" - "#error GMPXX is disabled by the CMake option CGAL_DISABLE_GMPXX") -else() - list(APPEND CGAL_ESSENTIAL_3RD_PARTY_LIBRARIES GMPXX) - - # When CMake is run several times, to avoid duplicates. - list(REMOVE_DUPLICATES CGAL_ESSENTIAL_3RD_PARTY_LIBRARIES) - - file(REMOVE "${CGAL_BINARY_DIR}/include/gmpxx.h") -endif() hide_variable(CGAL_ESSENTIAL_3RD_PARTY_LIBRARIES) #-------------------------------------------------------------------------------------------------- diff --git a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake index 51f2bb333abc..cb16e161fc7a 100644 --- a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake +++ b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake @@ -74,9 +74,6 @@ endif() # keyword. # function(CGAL_setup_CGAL_dependencies target) - if(CGAL_DISABLE_GMPXX) - target_compile_definitions(${target} INTERFACE CGAL_DISABLE_GMPXX=1) - endif() if(CGAL_DISABLE_GMP) target_compile_definitions(${target} INTERFACE CGAL_DISABLE_GMP=1) else() diff --git a/Installation/cmake/modules/CGAL_SetupGMP.cmake b/Installation/cmake/modules/CGAL_SetupGMP.cmake index 7895f7e01a67..4a1df74eabc4 100644 --- a/Installation/cmake/modules/CGAL_SetupGMP.cmake +++ b/Installation/cmake/modules/CGAL_SetupGMP.cmake @@ -23,12 +23,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CGAL_MODULES_DIR}) find_package(GMP REQUIRED) find_package(MPFR REQUIRED) - -if(NOT CGAL_DISABLE_GMPXX) - find_package(GMPXX QUIET) -else() - message("GMPXX IS DISABLED!") -endif() +find_package(GMPXX QUIET) if(NOT GMPXX_FOUND) option(CGAL_WITH_GMPXX "Use CGAL with GMPXX: use C++ classes of GNU MP instead of CGAL wrappers" OFF) @@ -70,12 +65,10 @@ function(use_CGAL_GMP_support target) $ $) endif() - if(NOT CGAL_DISABLE_GMPXX) - if(WITH_GMPXX OR CGAL_WITH_GMPXX) - target_include_directories(${target} SYSTEM INTERFACE ${GMPXX_INCLUDE_DIR}) - target_link_libraries(${target} INTERFACE ${GMPXX_LIBRARIES}) - target_compile_definitions(${target} INTERFACE CGAL_USE_GMPXX=1) - endif() + if(WITH_GMPXX OR CGAL_WITH_GMPXX) + target_include_directories(${target} SYSTEM INTERFACE ${GMPXX_INCLUDE_DIR}) + target_link_libraries(${target} INTERFACE ${GMPXX_LIBRARIES}) + target_compile_definitions(${target} INTERFACE CGAL_USE_GMPXX=1) endif() target_link_libraries(${target} INTERFACE ${MPFR_LIBRARIES} ${GMP_LIBRARIES}) endfunction() From cf60cb0655352695a2d86e0c3814e403d1421b28 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 28 Sep 2021 10:40:00 +0200 Subject: [PATCH 086/127] remove testme and cppint defs --- Number_types/include/CGAL/Exact_integer.h | 14 +++---------- .../internal/Exact_type_selector.h | 21 ++++--------------- Number_types/include/CGAL/Quotient.h | 2 +- Number_types/include/CGAL/boost_mp.h | 3 +-- 4 files changed, 9 insertions(+), 31 deletions(-) diff --git a/Number_types/include/CGAL/Exact_integer.h b/Number_types/include/CGAL/Exact_integer.h index 3cc9e3cddafa..d28961930d39 100644 --- a/Number_types/include/CGAL/Exact_integer.h +++ b/Number_types/include/CGAL/Exact_integer.h @@ -50,19 +50,17 @@ typedef unspecified_type Exact_integer; #else // not DOXYGEN_RUNNING -#if defined(CGAL_DO_NOT_RUN_TESTME) // default types - #if CGAL_USE_GMPXX typedef mpz_class Exact_integer; #elif CGAL_USE_GMP -# ifdef CGAL_USE_BOOST_MP +#ifdef CGAL_USE_BOOST_MP typedef boost::multiprecision::mpz_int Exact_integer; -# else +#else typedef Gmpz Exact_integer; -# endif +#endif #elif CGAL_USE_LEDA @@ -78,12 +76,6 @@ typedef boost::multiprecision::cpp_int Exact_integer; #endif // CGAL_USE_BOOST_MP -#else // run testme - -typedef boost::multiprecision::cpp_int Exact_integer; - -#endif // run tesme - #endif // not DOXYGEN_RUNNING } /* end namespace CGAL */ diff --git a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h index 6a8e7569579e..ab2fcf47720f 100644 --- a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h @@ -55,37 +55,24 @@ namespace CGAL { namespace internal { template < typename > struct Exact_field_selector -#if defined(CGAL_DO_NOT_RUN_TESTME) // default types - #ifdef CGAL_USE_GMPXX { typedef mpq_class Type; }; #elif defined(CGAL_USE_GMP) -# if defined(CGAL_USE_BOOST_MP) +#if defined(CGAL_USE_BOOST_MP) { typedef boost::multiprecision::mpq_rational Type; }; -# else +#else { typedef Gmpq Type; }; -# endif +#endif #elif defined(CGAL_USE_LEDA) { typedef leda_rational Type; }; #elif defined(CGAL_USE_BOOST_MP) // See the discussion in https://github.com/CGAL/cgal/pull/3614 // This is disabled for now because cpp_rational is even slower than Quotient. Quotient will be a good candidate after some polishing. -#if defined(CGAL_USE_CPP_INT) -{ typedef Quotient Type; }; -#else { typedef BOOST_cpp_arithmetic_kernel::Rational Type; }; -# endif #else -{ typedef Quotient Type; }; +{ typedef Quotient Type; }; #endif -#else // run testme - -// { typedef Quotient Type; }; -{ typedef boost::multiprecision::cpp_rational Type; }; - -#endif // run testme - // By default, a field is a safe choice of ring. template < typename T > struct Exact_ring_selector : Exact_field_selector < T > { }; diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index 23e22a54b78a..e4099e4b1fd4 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -44,7 +44,7 @@ namespace CGAL { // This function is not documented as a number type requirement for now. template < typename NT > inline void -simplify_quotient(NT & , NT & ) {} +simplify_quotient(NT &, NT &) {} // This one should be replaced by some functor or tag. // Meanwhile, the class is specialized for Gmpz, mpz_class, leda_integer. diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index e6fdd92e5283..e13c0520e625 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -21,8 +21,7 @@ // MSVC had trouble with versions <= 1.69: // https://github.com/boostorg/multiprecision/issues/98 #if !defined CGAL_DO_NOT_USE_BOOST_MP && \ - (!defined _MSC_VER || BOOST_VERSION >= 107000) || \ - defined CGAL_USE_CPP_INT || !defined CGAL_DO_NOT_RUN_TESTME + (!defined _MSC_VER || BOOST_VERSION >= 107000) #define CGAL_USE_BOOST_MP 1 #include From d479eb2fefebc28e2229ff0d474dc794e29f5e70 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 28 Sep 2021 11:46:28 +0200 Subject: [PATCH 087/127] removed sh script + clean exact type selectors --- Number_types/include/CGAL/Exact_integer.h | 28 ++++++------------- .../internal/Exact_type_selector.h | 10 +++++-- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/Number_types/include/CGAL/Exact_integer.h b/Number_types/include/CGAL/Exact_integer.h index d28961930d39..9e4ea3a8f5e0 100644 --- a/Number_types/include/CGAL/Exact_integer.h +++ b/Number_types/include/CGAL/Exact_integer.h @@ -50,31 +50,21 @@ typedef unspecified_type Exact_integer; #else // not DOXYGEN_RUNNING -#if CGAL_USE_GMPXX - +#ifdef CGAL_USE_GMPXX typedef mpz_class Exact_integer; - -#elif CGAL_USE_GMP - -#ifdef CGAL_USE_BOOST_MP -typedef boost::multiprecision::mpz_int Exact_integer; +#elif defined(CGAL_USE_GMP) +#if defined(CGAL_USE_BOOST_MP) +typedef BOOST_gmp_arithmetic_kernel::Integer Exact_integer; #else typedef Gmpz Exact_integer; #endif - -#elif CGAL_USE_LEDA - +#elif defined(CGAL_USE_LEDA) typedef leda_integer Exact_integer; - -#elif CGAL_USE_CORE - +#elif defined(CGAL_USE_BOOST_MP) +typedef BOOST_cpp_arithmetic_kernel::Integer Exact_integer; +#elif defined(CGAL_USE_CORE) typedef CORE::BigInt Exact_integer; - -#elif defined CGAL_USE_BOOST_MP - -typedef boost::multiprecision::cpp_int Exact_integer; - -#endif // CGAL_USE_BOOST_MP +#endif // CGAL_USE_CORE #endif // not DOXYGEN_RUNNING diff --git a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h index ab2fcf47720f..55fee2acd5c9 100644 --- a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h @@ -40,7 +40,7 @@ # include #endif #ifdef CGAL_USE_CORE -// # include +// # include namespace CORE { class Expr; } @@ -59,7 +59,7 @@ struct Exact_field_selector { typedef mpq_class Type; }; #elif defined(CGAL_USE_GMP) #if defined(CGAL_USE_BOOST_MP) -{ typedef boost::multiprecision::mpq_rational Type; }; +{ typedef BOOST_gmp_arithmetic_kernel::Rational Type; }; #else { typedef Gmpq Type; }; #endif @@ -68,9 +68,13 @@ struct Exact_field_selector #elif defined(CGAL_USE_BOOST_MP) // See the discussion in https://github.com/CGAL/cgal/pull/3614 // This is disabled for now because cpp_rational is even slower than Quotient. Quotient will be a good candidate after some polishing. +// In fact, the new version of cpp_rational from here: https://github.com/boostorg/multiprecision/pull/366 +// is much better than Quotient because it is using smart gcd and is well-supported +// while Quotient does not. Though, we can still use it if needed. +// { typedef Quotient Type; }; { typedef BOOST_cpp_arithmetic_kernel::Rational Type; }; #else -{ typedef Quotient Type; }; +{ typedef Quotient Type; }; #endif // By default, a field is a safe choice of ring. From 5cd901f071a9194df6a44871118a0fe1473fb0af Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 28 Sep 2021 12:27:36 +0200 Subject: [PATCH 088/127] move to_interval tests from benches to tests --- Number_types/test/Number_types/CMakeLists.txt | 5 + .../Number_types/to_interval_test_boost.cpp | 701 ++++++++++++++++++ 2 files changed, 706 insertions(+) create mode 100644 Number_types/test/Number_types/to_interval_test_boost.cpp diff --git a/Number_types/test/Number_types/CMakeLists.txt b/Number_types/test/Number_types/CMakeLists.txt index 9cada3bf9216..371e4370e457 100644 --- a/Number_types/test/Number_types/CMakeLists.txt +++ b/Number_types/test/Number_types/CMakeLists.txt @@ -88,3 +88,8 @@ endif()#NOT CGAL_DISABLE_GMP # all the programs below will be linked against MPFI in case it is present create_single_source_cgal_program("Quotient_new.cpp") create_single_source_cgal_program("test_nt_Coercion_traits.cpp") + +find_package(Boost) +if(Boost_FOUND) +create_single_source_cgal_program("to_interval_test_boost.cpp") +endif() diff --git a/Number_types/test/Number_types/to_interval_test_boost.cpp b/Number_types/test/Number_types/to_interval_test_boost.cpp new file mode 100644 index 000000000000..89e4cffc87b6 --- /dev/null +++ b/Number_types/test/Number_types/to_interval_test_boost.cpp @@ -0,0 +1,701 @@ +// STL. +#include +#include +#include +#include +#include +#include + +// Boost. +#include + +// Kernels. +#include +#include +#include + +// CGAL. +#include +#include +#include +#include +#include + +#ifdef CGAL_USE_BOOST_MP + +#if false // https://github.com/boostorg/multiprecision/issues/370 + +void test_boost_eval_lehmer() { + + const boost::multiprecision::cpp_int a("500000000000000052504760255204421627079393309355027816932345132815919505535709229444276879024105562954502314530690391078574434507015318513443905076213688875017942541908041275407131568575177172639474548726709751235383681696449966404295647940685784470144122251803020020951078103818191513659921807053133698549053838430992170843235673537548059987539601671975279280846041564435631581262016246808786828637048154067265620710396778995313534536353760281048487250661054626168637371167135426013683337484254647996964562455566714879467026196409913165805735073230830136024016362543811769017875638974011487488573436"); + const boost::multiprecision::cpp_int b("1500000000000000157514280765613264881238179928065083450797035398447758516607127688332830637072316688863506943592071173235723303521045955540331715228641066625053827625724123826221394705725531517918423646180129253706151045089349899212886943822057353410432366755409060062853234311454574540979765421159386595647161515292215193506006556519037965168192736708179557957863203557666055574947146355487693991882510747766220045897624670399027877365714431356466054500731862264092476764347207739651025585146903094168986610767496468412336047796468657032646893153521091155634158263410282629846280069312485301157888001"); + const boost::multiprecision::cpp_int r = boost::multiprecision::gcd(a, b); +} + +#endif // issue 370 + +void test_minimal_boost_gcd() { + + boost::multiprecision::cpp_int u = 1; + for (unsigned i = 1; i <= 50; ++i) { + u *= i; + } + std::cout << "u: " << u << std::endl; + + boost::multiprecision::cpp_int v = 1; + for (unsigned i = 1; i <= 100; ++i) { + v *= i; + } + std::cout << "v: " << v << std::endl; + + // const auto r = boost::multiprecision::gcd(u, v); // fail + const boost::multiprecision::cpp_int r = boost::multiprecision::gcd(u, v); // pass + std::cout << "r: " << r << std::endl; + + u = u / r; + v = v / r; + + std::cout << "new u: " << u << std::endl; + std::cout << "new v: " << v << std::endl; +} + +void test_minimal_nextafter() { + + _MM_SET_ROUNDING_MODE(_MM_ROUND_UP); // fail + // _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST); // pass + + const boost::multiprecision::cpp_int x("1312729512902970206056841780066779136"); + + double i = x.template convert_to(); + double s = i; + + const double inf = std::numeric_limits::infinity(); + assert(i != inf && s != inf); + const int cmp = x.compare(i); + if (cmp > 0) { + s = nextafter(s, +inf); + assert(x.compare(s) < 0); + } else if (cmp < 0) { + i = nextafter(i, -inf); + assert(x.compare(i) > 0); + } +} + +void test_to_interval_boost() { + + using NT = boost::multiprecision::cpp_int; + using Quotient = CGAL::Quotient; + using Traits = CGAL::Real_embeddable_traits; + using Interval = typename Traits::To_interval; + + NT n, d; + Quotient x; + double i, s; + + n = NT("-15284404573383541"); + d = NT("4503599627370496"); + + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: -3.3938195750112902793" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: -3.3938195750112898352" << std::endl; + std::cout << std::endl; + + // Results for current tight using cpp_rational. + assert(i == -3.3938195750112902793); + assert(s == -3.3938195750112898352); +} + +// In assert, we use values from impl2. +void test_to_interval_tight_1() { + + // In green, we compare to impl2. + #define TESTCASE10 // pass all three + #define TESTCASE11 // impl1: fails tightness (sup is larger, s = 9.3488310472396616291) + #define TESTCASE12 // pass all three + #define TESTCASE13 // pass all three + #define TESTCASE14 // pass all three + #define TESTCASE15 // pass all three + #define TESTCASE16 // pass all three + #define TESTCASE17 // pass all three + #define TESTCASE18 // pass all three + #define TESTCASE19 // pass all three + + using NT = boost::multiprecision::cpp_int; + using Quotient = CGAL::Quotient; + using Traits = CGAL::Real_embeddable_traits; + using Interval = typename Traits::To_interval; + + // std::cout << std::endl; + // std::cout << boost::typeindex::type_id() << std::endl; + // std::cout << std::endl; + // std::cout << boost::typeindex::type_id() << std::endl; + // std::cout << std::endl; + + NT n, d; + Quotient x; + double i, s; + + std::cout << std::endl; + std::cout << "- T1 testing tight interval ..." << std::endl; + std::cout << std::endl; + + #ifdef TESTCASE10 // small numbers + + std::cout << "=============" << std::endl; + std::cout << "CASE0 RESULT:" << std::endl; + std::cout << "=============" << std::endl; + + n = NT("39792587355159975"); + d = NT("140737488355328"); + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 282.7433388230813307" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: 282.74333882308138755" << std::endl; + std::cout << std::endl; + + // Results for current tight using master to_interval(). + assert(i == 282.7433388230813307); + assert(s == 282.74333882308138755); + + #endif + + #ifdef TESTCASE11 // large numbers + + std::cout << "=============" << std::endl; + std::cout << "CASE1 RESULT:" << std::endl; + std::cout << "=============" << std::endl; + + n = NT("772537196160711547532081795586792063331305895970601529435744397743492241616327030886637827664482971614281724796166908515292029740442872965475211471498392497954317530347232852540146110053764627070672243390766540271554856759037331142360111552286202392826786995364211101723592791550906796165626083442695020580821188398298798456115881346136681033873"); + d = NT("82634630175374856683315372867724319098240552701588533218371381248009342768269285501674184091886435054368116496214846441734481770666205690731018817430937185570378353100803926136323598244976110318516454816403989543192819758059431171537258117598056453283568595627159988837663160716950017789671313834717457946818990093589809113731838629064768225280"); + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 9.3488310472396563" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: 9.3488310472396580764" << std::endl; + std::cout << std::endl; + + // Results for current tight using cpp_rational. + assert(i == 9.3488310472396563); + assert(s == 9.3488310472396580764); + + #endif + + #ifdef TESTCASE12 + + std::cout << "=============" << std::endl; + std::cout << "CASE2 RESULT:" << std::endl; + std::cout << "=============" << std::endl; + + n = NT("772537196160711547532081795586792063331305895970601529435744397743492241616327030886637827664482971614281724796166908515292029740442872965475211471498392497954317530347232852540146110053764627070672243390766540271554856759037331142360111552286202392826786995364211101723592791550906796165626083442695020580821188398298798456115881346136681033873"); + d = NT("1"); + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 1.7976931348623157081e+308" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: inf" << std::endl; + std::cout << std::endl; + + assert(i == std::numeric_limits::max()); + assert(s == std::numeric_limits::infinity()); + + #endif + + #ifdef TESTCASE13 + + std::cout << "=============" << std::endl; + std::cout << "CASE3 RESULT:" << std::endl; + std::cout << "=============" << std::endl; + + n = NT("1"); + d = NT("772537196160711547532081795586792063331305895970601529435744397743492241616327030886637827664482971614281724796166908515292029740442872965475211471498392497954317530347232852540146110053764627070672243390766540271554856759037331142360111552286202392826786995364211101723592791550906796165626083442695020580821188398298798456115881346136681033873"); + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 0" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: 4.9406564584124654418e-324" << std::endl; + std::cout << std::endl; + + assert(i == 0.0); + assert(s == std::numeric_limits::denorm_min()); + + #endif + + #ifdef TESTCASE14 + + std::cout << "=============" << std::endl; + std::cout << "CASE4 RESULT:" << std::endl; + std::cout << "=============" << std::endl; + + n = NT("10"); + d = NT("10"); + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 1" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: 1" << std::endl; + std::cout << std::endl; + + assert(i == 1.0); + assert(s == 1.0); + + #endif + + #ifdef TESTCASE15 + + std::cout << "=============" << std::endl; + std::cout << "CASE5 RESULT:" << std::endl; + std::cout << "=============" << std::endl; + + n = NT("1"); + d = NT("6"); + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 0.16666666666666665741" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: 0.16666666666666668517" << std::endl; + std::cout << std::endl; + + assert(i == 0.16666666666666665741); + assert(s == 0.16666666666666668517); + + #endif + + #ifdef TESTCASE16 + + std::cout << "=============" << std::endl; + std::cout << "CASE6 RESULT:" << std::endl; + std::cout << "=============" << std::endl; + + n = +NT("6"); + d = +NT("3"); + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: " << 6.0 / 3.0 << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: " << 6.0 / 3.0 << std::endl; + std::cout << std::endl; + + assert(i == 2.0); + assert(s == 2.0); + + #endif + + #ifdef TESTCASE17 + + std::cout << "=============" << std::endl; + std::cout << "CASE7 RESULT:" << std::endl; + std::cout << "=============" << std::endl; + + n = -NT("1"); + d = -NT("2"); + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: " << 1.0 / 2.0 << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: " << 1.0 / 2.0 << std::endl; + std::cout << std::endl; + + assert(i == 1.0 / 2.0); + assert(s == 1.0 / 2.0); + + #endif + + #ifdef TESTCASE18 + + std::cout << "=============" << std::endl; + std::cout << "CASE8 RESULT:" << std::endl; + std::cout << "=============" << std::endl; + + n = -NT("1"); + d = +NT("3"); + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: -0.33333333333333337034" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: -0.33333333333333331483" << std::endl; + std::cout << std::endl; + + assert(i == -0.33333333333333337034); + assert(s == -0.33333333333333331483); + + #endif + + #ifdef TESTCASE19 // small numbers, num > 0 and den < 0 + + std::cout << "=============" << std::endl; + std::cout << "CASE9 RESULT:" << std::endl; + std::cout << "=============" << std::endl; + + n = +NT("39792587355159975"); + d = -NT("140737488355328"); + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: -282.74333882308138755" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: -282.7433388230813307" << std::endl; + std::cout << std::endl; + + assert(i == -282.74333882308138755); + assert(s == -282.7433388230813307); + + #endif + + std::cout << "---SUCCESS ALL---" << std::endl; + std::cout << std::endl; +} + +// In assert, we use values from impl2. +void test_to_interval_tight_2() { + + // In green, we compare to impl2. + #define TESTCASE20 // pass all three + #define TESTCASE21 // impl1: fails tightness (sup is larger, s = 0.43464565325999998668) + #define TESTCASE22 // pass all three + #define TESTCASE23 // pass all three + #define TESTCASE24 // pass all three + #define TESTCASE25 // pass all three + #define TESTCASE26 // pass all three + #define TESTCASE27 // pass all three + #define TESTCASE28 // pass all three + #define TESTCASE29 // pass all three + #define TESTCASE210 // impl1, impl3: fails tightness (sup is larger, s = 5.9425938166208590782e+26) + #define TESTCASE211 // impl1, impl3: fails tightness (inf is smaller, i = 3602879701896396.5, sup is larger, s = 3602879701896398) + + using NT = boost::multiprecision::cpp_int; + using Quotient = CGAL::Quotient; + using Traits = CGAL::Real_embeddable_traits; + using Interval = typename Traits::To_interval; + + NT n, d; + Quotient x; + double i, s; + + std::cout << std::endl; + std::cout << "- T2 testing tight interval ..." << std::endl; + std::cout << std::endl; + + #ifdef TESTCASE20 + + std::cout << "TEST 0" << std::endl; // num, case 2 + + n = NT("-15284404573383541"); + d = NT("4503599627370496"); + + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: -3.3938195750112902793" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: -3.3938195750112898352" << std::endl; + std::cout << std::endl; + + assert(i == -3.3938195750112902793); + assert(s == -3.3938195750112898352); + + #endif + + #ifdef TESTCASE21 + + std::cout << "TEST 1" << std::endl; // num, case 4 + + const double nn = 0.43464565326; + x = Quotient(nn); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 0.43464565325999998668" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: 0.43464565325999998668" << std::endl; + std::cout << std::endl; + + assert(i == 0.43464565325999998668); + assert(s == 0.43464565325999998668); + assert(i == s); + + #endif + + #ifdef TESTCASE22 + + std::cout << "TEST 2" << std::endl; // num, case 4 + + n = NT("1"); + d = NT("2"); + + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 0.5" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: 0.5" << std::endl; + std::cout << std::endl; + + assert(i == 0.5); + assert(s == 0.5); + + #endif + + #ifdef TESTCASE23 + + std::cout << "TEST 3" << std::endl; // shift = 0 + + n = NT("7725371961607115"); + d = NT("1"); + + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 7725371961607115" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: 7725371961607115" << std::endl; + std::cout << std::endl; + + assert(i == 7725371961607115); + assert(s == 7725371961607115); + + #endif + + #ifdef TESTCASE24 + + std::cout << "TEST 4" << std::endl; + + n = NT("772537196160711547532081795586792063331305895970601529435744397743492241616327030886637827664482971614281724796166908515292029740442872965475211471498392497954317530347232852540146110053764627070672243390766540271554856759037331142360111552286202392826786995364211101723592791550906796165626083442695020580821188398298798456115881346136681033873"); + d = NT("1"); + + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 1.7976931348623157081e+308" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: inf" << std::endl; + std::cout << std::endl; + + assert(i == std::numeric_limits::max()); + assert(s == std::numeric_limits::infinity()); + + #endif + + #ifdef TESTCASE25 + + std::cout << "TEST 5" << std::endl; + + n = NT("1"); + d = NT("772537196160711547532081795586792063331305895970601529435744397743492241616327030886637827664482971614281724796166908515292029740442872965475211471498392497954317530347232852540146110053764627070672243390766540271554856759037331142360111552286202392826786995364211101723592791550906796165626083442695020580821188398298798456115881346136681033873"); + + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 0" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: 4.9406564584124654418e-324" << std::endl; + std::cout << std::endl; + + assert(i == 0); + assert(s == std::numeric_limits::denorm_min()); + + #endif + + #ifdef TESTCASE26 + + std::cout << "TEST 6" << std::endl; // case shift > 0 && p_bits = 51, subcase1 + + n = NT("1"); + d = NT("10"); + + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 0.099999999999999991673" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: 0.10000000000000000555" << std::endl; + std::cout << std::endl; + + assert(i == 0.099999999999999991673); + assert(s == 0.10000000000000000555); + + #endif + + #ifdef TESTCASE27 + + std::cout << "TEST 7" << std::endl; // non representable double + + n = NT("1"); + d = NT("3"); + + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 0.33333333333333331483" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: 0.33333333333333337034" << std::endl; + std::cout << std::endl; + + assert(i == 0.33333333333333331483); + assert(s == 0.33333333333333337034); + + #endif + + #ifdef TESTCASE28 + + std::cout << "TEST 8" << std::endl; // fails assertion (q_bits == num_dbl_digits || r != 0) + + n = NT("21"); + d = NT("3"); + + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 7" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: 7" << std::endl; + std::cout << std::endl; + + assert(i == 7); + assert(s == 7); + + #endif + + #ifdef TESTCASE29 + + std::cout << "TEST 9" << std::endl; // case shift > 0 && p_bits = 51, subcase3 + + n = NT("17"); + d = NT("3"); + + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 5.6666666666666660745" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: 5.6666666666666669627" << std::endl; + std::cout << std::endl; + + assert(i == 5.6666666666666660745); + assert(s == 5.6666666666666669627); + + #endif + + #ifdef TESTCASE210 + + std::cout << "TEST 10" << std::endl; // case shift < 0 && p_bits = 51 + + n = NT("7725371961607115475320817955"); + d = NT("13"); + + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 5.9425938166208577038e+26" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: 5.942593816620858391e+26" << std::endl; + std::cout << std::endl; + + assert(i == 5.9425938166208577038e+26); + assert(s == 5.942593816620858391e+26); + + #endif + + #ifdef TESTCASE211 + + std::cout << "TEST 11" << std::endl; // case shift = 0 && p_bits = 51 && cmp = 0, subcase3 + + n = NT("36028797018963975"); + d = NT("10"); + + x = Quotient(n, d); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 3602879701896397.5" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: 3602879701896397.5" << std::endl; + std::cout << std::endl; + + assert(i == 3602879701896397.5); + assert(s == 3602879701896397.5); + + #endif + + std::cout << "---SUCCESS ALL---" << std::endl; + std::cout << std::endl; +} + +#endif // CGAL_USE_BOOST_MP + +int main(int argc, char* argv[]) { + + // Make sure we have the same seed. + CGAL::get_default_random() = CGAL::Random(0); + std::cout.precision(20); + #ifdef CGAL_USE_BOOST_MP + + #if false + test_boost_eval_lehmer(); + #endif + test_minimal_boost_gcd(); + test_minimal_nextafter(); + test_to_interval_boost(); + + test_to_interval_tight_1(); + test_to_interval_tight_2(); + + #endif // CGAL_USE_BOOST_MP + return EXIT_SUCCESS; +} From 88741c6f7c29d0aca4b1fc88cb27c970c35c2be8 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 28 Sep 2021 16:59:57 +0200 Subject: [PATCH 089/127] cleanup --- Number_types/test/Number_types/to_interval_test_boost.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Number_types/test/Number_types/to_interval_test_boost.cpp b/Number_types/test/Number_types/to_interval_test_boost.cpp index 89e4cffc87b6..461b90166747 100644 --- a/Number_types/test/Number_types/to_interval_test_boost.cpp +++ b/Number_types/test/Number_types/to_interval_test_boost.cpp @@ -679,7 +679,7 @@ void test_to_interval_tight_2() { #endif // CGAL_USE_BOOST_MP -int main(int argc, char* argv[]) { +int main() { // Make sure we have the same seed. CGAL::get_default_random() = CGAL::Random(0); @@ -688,9 +688,9 @@ int main(int argc, char* argv[]) { #if false test_boost_eval_lehmer(); + test_minimal_nextafter(); #endif test_minimal_boost_gcd(); - test_minimal_nextafter(); test_to_interval_boost(); test_to_interval_tight_1(); From 9c041567498e2e8ba5fac5a8c7d1a1d9bae7441a Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 4 Oct 2021 16:29:14 +0200 Subject: [PATCH 090/127] removed duplicated code --- Number_types/include/CGAL/Exact_integer.h | 2 + Number_types/include/CGAL/boost_mp.h | 466 ++++++++-------------- 2 files changed, 169 insertions(+), 299 deletions(-) diff --git a/Number_types/include/CGAL/Exact_integer.h b/Number_types/include/CGAL/Exact_integer.h index 9e4ea3a8f5e0..5b6e0988d7b0 100644 --- a/Number_types/include/CGAL/Exact_integer.h +++ b/Number_types/include/CGAL/Exact_integer.h @@ -64,6 +64,8 @@ typedef leda_integer Exact_integer; typedef BOOST_cpp_arithmetic_kernel::Integer Exact_integer; #elif defined(CGAL_USE_CORE) typedef CORE::BigInt Exact_integer; +#else +#error "ERROR: Cannot determine a BigInt type!" #endif // CGAL_USE_CORE #endif // not DOXYGEN_RUNNING diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index e13c0520e625..d153dd8a6fb7 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -141,6 +141,159 @@ struct Algebraic_structure_traits + my_ldexp( const Interval_nt& intv, const int e ) const { + + CGAL_assertion(intv.inf() > 0.0); + CGAL_assertion(intv.sup() > 0.0); + const double scale = std::ldexp(1.0, e); + return Interval_nt ( + CGAL_NTS is_finite(scale) ? + scale * intv.inf() : CGAL_IA_MAX_DOUBLE, + scale == 0.0 ? CGAL_IA_MIN_DOUBLE : scale * intv.sup() ); + } + + bool are_bounds_correct( const double l, const double u, const Type& x ) const { + + const double inf = std::numeric_limits::infinity(); + CGAL_assertion(u == l || u == std::nextafter(l, +inf)); + const bool are_bounds_tight = (u == l || u == std::nextafter(l, +inf)); + + if ( + CGAL::abs(l) == inf || + CGAL::abs(u) == inf || + CGAL::abs(l) == 0.0 || + CGAL::abs(u) == 0.0) { + return are_bounds_tight; + } + CGAL_assertion(CGAL::abs(l) != inf); + CGAL_assertion(CGAL::abs(u) != inf); + CGAL_assertion(CGAL::abs(l) != 0.0); + CGAL_assertion(CGAL::abs(u) != 0.0); + + const Type lb(l), ub(u); + CGAL_assertion(lb <= x); + CGAL_assertion(ub >= x); + const bool are_bounds_respected = (lb <= x && x <= ub); + return are_bounds_tight && are_bounds_respected; + } + + template + std::pair get_0ulp_interval( const int64_t shift, const ET& p ) const { + + CGAL_assertion(p >= 0); + const uint64_t pp = static_cast(p); + CGAL_assertion(pp >= 0); + const double pp_dbl = static_cast(pp); + const Interval_nt intv(pp_dbl, pp_dbl); + return my_ldexp(intv, -static_cast(shift)).pair(); + } + + template + std::pair get_1ulp_interval( const int64_t shift, const ET& p ) const { + + CGAL_assertion(p >= 0); + const uint64_t pp = static_cast(p); + const uint64_t qq = pp + 1; + CGAL_assertion(pp >= 0); + CGAL_assertion(qq > pp); + const double pp_dbl = static_cast(pp); + const double qq_dbl = static_cast(qq); + const Interval_nt intv(pp_dbl, qq_dbl); + return my_ldexp(intv, -static_cast(shift)).pair(); + } + + template + std::pair to_interval( ET xnum, ET xden ) const { + + CGAL_assertion(!CGAL::is_zero(xden)); + CGAL_assertion_code(const Type input = x); + double l = 0.0, u = 0.0; + if (CGAL::is_zero(xnum)) { // return [0.0, 0.0] + CGAL_assertion(are_bounds_correct(l, u, input)); + return std::make_pair(l, u); + } + CGAL_assertion(!CGAL::is_zero(xnum)); + + // Handle signs. + bool change_sign = false; + const bool is_num_pos = CGAL::is_positive(xnum); + const bool is_den_pos = CGAL::is_positive(xden); + if (!is_num_pos && !is_den_pos) { + xnum = -xnum; + xden = -xden; + } else if (!is_num_pos && is_den_pos) { + change_sign = true; + xnum = -xnum; + } else if (is_num_pos && !is_den_pos) { + change_sign = true; + xden = -xden; + } + CGAL_assertion(CGAL::is_positive(xnum) && CGAL::is_positive(xden)); + + const int64_t num_dbl_digits = std::numeric_limits::digits - 1; + const int64_t msb_num = static_cast(boost::multiprecision::msb(xnum)); + const int64_t msb_den = static_cast(boost::multiprecision::msb(xden)); + const int64_t msb_diff = msb_num - msb_den; + int64_t shift = num_dbl_digits - msb_diff; + + if (shift > 0) { + CGAL_assertion(msb_diff < num_dbl_digits); + xnum <<= +shift; + } else if (shift < 0) { + CGAL_assertion(msb_diff > num_dbl_digits); + xden <<= -shift; + } + CGAL_assertion(num_dbl_digits == + static_cast(boost::multiprecision::msb(xnum)) - + static_cast(boost::multiprecision::msb(xden))); + + decltype(xnum) p, r; + boost::multiprecision::divide_qr(xnum, xden, p, r); + const int64_t p_bits = static_cast(boost::multiprecision::msb(p)); + + if (r == 0) { + std::tie(l, u) = get_0ulp_interval(shift, p); + } else { + CGAL_assertion(r > 0); + CGAL_assertion(r < xden); + if (p_bits == num_dbl_digits - 1) { // we did not reach full precision + + p <<= 1; + r <<= 1; + ++shift; + + CGAL_assertion(r > 0); + const int cmp = r.compare(xden); + if (cmp > 0) { + ++p; + std::tie(l, u) = get_1ulp_interval(shift, p); + } else if (cmp == 0) { + ++p; + std::tie(l, u) = get_0ulp_interval(shift, p); + } else { + std::tie(l, u) = get_1ulp_interval(shift, p); + } + + } else { + std::tie(l, u) = get_1ulp_interval(shift, p); + } + } + + if (change_sign) { + const double t = l; + l = -u; + u = -t; + } + + CGAL_assertion(are_bounds_correct(l, u, input)); + return std::make_pair(l, u); + } + +} // Boost_MP_internal + template struct RET_boost_mp_base : public INTERN_RET::Real_embeddable_traits_base< NT , CGAL::Tag_true > { @@ -247,155 +400,11 @@ struct RET_boost_mp > { - bool are_bounds_correct( const double l, const double u, const Type& x ) const { - - const double inf = std::numeric_limits::infinity(); - CGAL_assertion(u == l || u == std::nextafter(l, +inf)); - const bool are_bounds_tight = (u == l || u == std::nextafter(l, +inf)); - - if ( - CGAL::abs(l) == inf || - CGAL::abs(u) == inf || - CGAL::abs(l) == 0.0 || - CGAL::abs(u) == 0.0) { - return are_bounds_tight; - } - CGAL_assertion(CGAL::abs(l) != inf); - CGAL_assertion(CGAL::abs(u) != inf); - CGAL_assertion(CGAL::abs(l) != 0.0); - CGAL_assertion(CGAL::abs(u) != 0.0); - - const Type lb(l), ub(u); - CGAL_assertion(lb <= x); - CGAL_assertion(ub >= x); - const bool are_bounds_respected = (lb <= x && x <= ub); - return are_bounds_tight && are_bounds_respected; - } - - Interval_nt - my_ldexp( const Interval_nt& intv, const int e ) const { - - CGAL_assertion(intv.inf() > 0.0); - CGAL_assertion(intv.sup() > 0.0); - const double scale = std::ldexp(1.0, e); - return Interval_nt ( - CGAL_NTS is_finite(scale) ? - scale * intv.inf() : CGAL_IA_MAX_DOUBLE, - scale == 0.0 ? CGAL_IA_MIN_DOUBLE : scale * intv.sup() ); - } - - template - std::pair get_0ulp_interval( const int64_t shift, const ET& p ) const { - - CGAL_assertion(p >= 0); - const uint64_t pp = static_cast(p); - CGAL_assertion(pp >= 0); - const double pp_dbl = static_cast(pp); - const Interval_nt intv(pp_dbl, pp_dbl); - return my_ldexp(intv, -static_cast(shift)).pair(); - } - - template - std::pair get_1ulp_interval( const int64_t shift, const ET& p ) const { - - CGAL_assertion(p >= 0); - const uint64_t pp = static_cast(p); - const uint64_t qq = pp + 1; - CGAL_assertion(pp >= 0); - CGAL_assertion(qq > pp); - const double pp_dbl = static_cast(pp); - const double qq_dbl = static_cast(qq); - const Interval_nt intv(pp_dbl, qq_dbl); - return my_ldexp(intv, -static_cast(shift)).pair(); - } - std::pair operator()( const Type& x ) const { - auto xnum = boost::multiprecision::numerator(x); - auto xden = boost::multiprecision::denominator(x); - - CGAL_assertion(!CGAL::is_zero(xden)); - CGAL_assertion_code(const Type input = x); - double l = 0.0, u = 0.0; - if (CGAL::is_zero(xnum)) { // return [0.0, 0.0] - CGAL_assertion(are_bounds_correct(l, u, input)); - return std::make_pair(l, u); - } - CGAL_assertion(!CGAL::is_zero(xnum)); - - // Handle signs. - bool change_sign = false; - const bool is_num_pos = CGAL::is_positive(xnum); - const bool is_den_pos = CGAL::is_positive(xden); - if (!is_num_pos && !is_den_pos) { - xnum = -xnum; - xden = -xden; - } else if (!is_num_pos && is_den_pos) { - change_sign = true; - xnum = -xnum; - } else if (is_num_pos && !is_den_pos) { - change_sign = true; - xden = -xden; - } - CGAL_assertion(CGAL::is_positive(xnum) && CGAL::is_positive(xden)); - - const int64_t num_dbl_digits = std::numeric_limits::digits - 1; - const int64_t msb_num = static_cast(boost::multiprecision::msb(xnum)); - const int64_t msb_den = static_cast(boost::multiprecision::msb(xden)); - const int64_t msb_diff = msb_num - msb_den; - int64_t shift = num_dbl_digits - msb_diff; - - if (shift > 0) { - CGAL_assertion(msb_diff < num_dbl_digits); - xnum <<= +shift; - } else if (shift < 0) { - CGAL_assertion(msb_diff > num_dbl_digits); - xden <<= -shift; - } - CGAL_assertion(num_dbl_digits == - static_cast(boost::multiprecision::msb(xnum)) - - static_cast(boost::multiprecision::msb(xden))); - - decltype(xnum) p, r; - boost::multiprecision::divide_qr(xnum, xden, p, r); - const int64_t p_bits = static_cast(boost::multiprecision::msb(p)); - - if (r == 0) { - std::tie(l, u) = get_0ulp_interval(shift, p); - } else { - CGAL_assertion(r > 0); - CGAL_assertion(r < xden); - if (p_bits == num_dbl_digits - 1) { // we did not reach full precision - - p <<= 1; - r <<= 1; - ++shift; - - CGAL_assertion(r > 0); - const int cmp = r.compare(xden); - if (cmp > 0) { - ++p; - std::tie(l, u) = get_1ulp_interval(shift, p); - } else if (cmp == 0) { - ++p; - std::tie(l, u) = get_0ulp_interval(shift, p); - } else { - std::tie(l, u) = get_1ulp_interval(shift, p); - } - - } else { - std::tie(l, u) = get_1ulp_interval(shift, p); - } - } - - if (change_sign) { - const double t = l; - l = -u; - u = -t; - } - - CGAL_assertion(are_bounds_correct(l, u, input)); - return std::make_pair(l, u); + const auto& xnum = boost::multiprecision::numerator(x); + const auto& xden = boost::multiprecision::denominator(x); + return Boost_MP_internal::to_interval(xnum, xden); } }; }; @@ -802,31 +811,6 @@ template< > class Real_embeddable_traits< Quotient > { public: - bool are_bounds_correct( const double l, const double u, const Type& x ) const { - - const double inf = std::numeric_limits::infinity(); - CGAL_assertion(u == l || u == std::nextafter(l, +inf)); - const bool are_bounds_tight = (u == l || u == std::nextafter(l, +inf)); - - if ( - CGAL::abs(l) == inf || - CGAL::abs(u) == inf || - CGAL::abs(l) == 0.0 || - CGAL::abs(u) == 0.0) { - return are_bounds_tight; - } - CGAL_assertion(CGAL::abs(l) != inf); - CGAL_assertion(CGAL::abs(u) != inf); - CGAL_assertion(CGAL::abs(l) != 0.0); - CGAL_assertion(CGAL::abs(u) != 0.0); - - const Type lb(l), ub(u); - CGAL_assertion(lb <= x); - CGAL_assertion(ub >= x); - const bool are_bounds_respected = (lb <= x && x <= ub); - return are_bounds_tight && are_bounds_respected; - } - /* // Option 1. // Inspired by the one from the gmpzf type. @@ -865,7 +849,8 @@ template< > class Real_embeddable_traits< Quotient class Real_embeddable_traits< Quotient class Real_embeddable_traits< Quotient class Real_embeddable_traits< Quotient quot = xn / xd; - CGAL_assertion(are_bounds_correct(quot.inf(), quot.sup(), x)); + CGAL_assertion(Boost_MP_internal:: + are_bounds_correct(quot.inf(), quot.sup(), x)); return std::make_pair(quot.inf(), quot.sup()); } */ @@ -972,129 +960,9 @@ template< > class Real_embeddable_traits< Quotient - my_ldexp( const Interval_nt& intv, const int e ) const { - - CGAL_assertion(intv.inf() > 0.0); - CGAL_assertion(intv.sup() > 0.0); - const double scale = std::ldexp(1.0, e); - return Interval_nt ( - CGAL_NTS is_finite(scale) ? - scale * intv.inf() : CGAL_IA_MAX_DOUBLE, - scale == 0.0 ? CGAL_IA_MIN_DOUBLE : scale * intv.sup() ); - } - - std::pair get_0ulp_interval( - const int64_t shift, - const boost::multiprecision::cpp_int& p ) const { - - CGAL_assertion(p >= 0); - const uint64_t pp = static_cast(p); - CGAL_assertion(pp >= 0); - const double pp_dbl = static_cast(pp); - const Interval_nt intv(pp_dbl, pp_dbl); - return my_ldexp(intv, -static_cast(shift)).pair(); - } - - std::pair get_1ulp_interval( - const int64_t shift, - const boost::multiprecision::cpp_int& p ) const { - - CGAL_assertion(p >= 0); - const uint64_t pp = static_cast(p); - const uint64_t qq = pp + 1; - CGAL_assertion(pp >= 0); - CGAL_assertion(qq > pp); - const double pp_dbl = static_cast(pp); - const double qq_dbl = static_cast(qq); - const Interval_nt intv(pp_dbl, qq_dbl); - return my_ldexp(intv, -static_cast(shift)).pair(); - } - - std::pair operator()( Type x ) const { - - CGAL_assertion(!CGAL::is_zero(x.den)); - CGAL_assertion_code(const Type input = x); - double l = 0.0, u = 0.0; - if (CGAL::is_zero(x.num)) { // return [0.0, 0.0] - CGAL_assertion(are_bounds_correct(l, u, input)); - return std::make_pair(l, u); - } - CGAL_assertion(!CGAL::is_zero(x.num)); - - // Handle signs. - bool change_sign = false; - const bool is_num_pos = CGAL::is_positive(x.num); - const bool is_den_pos = CGAL::is_positive(x.den); - if (!is_num_pos && !is_den_pos) { - x.num = -x.num; - x.den = -x.den; - } else if (!is_num_pos && is_den_pos) { - change_sign = true; - x.num = -x.num; - } else if (is_num_pos && !is_den_pos) { - change_sign = true; - x.den = -x.den; - } - CGAL_assertion(CGAL::is_positive(x.num) && CGAL::is_positive(x.den)); - - const int64_t num_dbl_digits = std::numeric_limits::digits - 1; - const int64_t msb_num = static_cast(boost::multiprecision::msb(x.num)); - const int64_t msb_den = static_cast(boost::multiprecision::msb(x.den)); - const int64_t msb_diff = msb_num - msb_den; - int64_t shift = num_dbl_digits - msb_diff; - - if (shift > 0) { - CGAL_assertion(msb_diff < num_dbl_digits); - x.num <<= +shift; - } else if (shift < 0) { - CGAL_assertion(msb_diff > num_dbl_digits); - x.den <<= -shift; - } - CGAL_assertion(num_dbl_digits == - static_cast(boost::multiprecision::msb(x.num)) - - static_cast(boost::multiprecision::msb(x.den))); - - boost::multiprecision::cpp_int p, r; - boost::multiprecision::divide_qr(x.num, x.den, p, r); - const int64_t p_bits = static_cast(boost::multiprecision::msb(p)); - - if (r == 0) { - std::tie(l, u) = get_0ulp_interval(shift, p); - } else { - CGAL_assertion(r > 0); - CGAL_assertion(r < x.den); - if (p_bits == num_dbl_digits - 1) { // we did not reach full precision - - p <<= 1; - r <<= 1; - ++shift; - - CGAL_assertion(r > 0); - const int cmp = r.compare(x.den); - if (cmp > 0) { - ++p; - std::tie(l, u) = get_1ulp_interval(shift, p); - } else if (cmp == 0) { - ++p; - std::tie(l, u) = get_0ulp_interval(shift, p); - } else { - std::tie(l, u) = get_1ulp_interval(shift, p); - } - - } else { - std::tie(l, u) = get_1ulp_interval(shift, p); - } - } - - if (change_sign) { - const double t = l; - l = -u; - u = -t; - } - - CGAL_assertion(are_bounds_correct(l, u, input)); - return std::make_pair(l, u); + // Option 2. Stable one! + std::pair operator()( const Type& x ) const { + return Boost_MP_internal::to_interval(x.num, x.den); } }; }; From ca17b38bf02dce546bc6039e85925e059622ac35 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 4 Oct 2021 16:47:33 +0200 Subject: [PATCH 091/127] removed const in free functions --- Number_types/include/CGAL/boost_mp.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index d153dd8a6fb7..d64cdf650aed 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -144,7 +144,7 @@ struct Algebraic_structure_traits - my_ldexp( const Interval_nt& intv, const int e ) const { + my_ldexp( const Interval_nt& intv, const int e ) { CGAL_assertion(intv.inf() > 0.0); CGAL_assertion(intv.sup() > 0.0); @@ -155,7 +155,8 @@ namespace Boost_MP_internal { scale == 0.0 ? CGAL_IA_MIN_DOUBLE : scale * intv.sup() ); } - bool are_bounds_correct( const double l, const double u, const Type& x ) const { + template + bool are_bounds_correct( const double l, const double u, const Type& x ) { const double inf = std::numeric_limits::infinity(); CGAL_assertion(u == l || u == std::nextafter(l, +inf)); @@ -181,7 +182,7 @@ namespace Boost_MP_internal { } template - std::pair get_0ulp_interval( const int64_t shift, const ET& p ) const { + std::pair get_0ulp_interval( const int64_t shift, const ET& p ) { CGAL_assertion(p >= 0); const uint64_t pp = static_cast(p); @@ -192,7 +193,7 @@ namespace Boost_MP_internal { } template - std::pair get_1ulp_interval( const int64_t shift, const ET& p ) const { + std::pair get_1ulp_interval( const int64_t shift, const ET& p ) { CGAL_assertion(p >= 0); const uint64_t pp = static_cast(p); @@ -205,8 +206,8 @@ namespace Boost_MP_internal { return my_ldexp(intv, -static_cast(shift)).pair(); } - template - std::pair to_interval( ET xnum, ET xden ) const { + template + std::pair to_interval(const Type& x, ET xnum, ET xden ) { CGAL_assertion(!CGAL::is_zero(xden)); CGAL_assertion_code(const Type input = x); @@ -404,7 +405,7 @@ struct RET_boost_mp class Real_embeddable_traits< Quotient operator()( const Type& x ) const { - return Boost_MP_internal::to_interval(x.num, x.den); + return Boost_MP_internal::to_interval(x, x.num, x.den); } }; }; From a037ca12d9111bc88ff1fac6f7d45e945ebd3f95 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 4 Oct 2021 17:01:41 +0200 Subject: [PATCH 092/127] user overload instead of specialization of simplify_quotient --- Number_types/include/CGAL/Quotient.h | 12 ++++++++++++ Number_types/include/CGAL/boost_mp.h | 8 -------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Number_types/include/CGAL/Quotient.h b/Number_types/include/CGAL/Quotient.h index de1e6adbebe7..c27dc82af730 100644 --- a/Number_types/include/CGAL/Quotient.h +++ b/Number_types/include/CGAL/Quotient.h @@ -33,6 +33,9 @@ #include #include +#ifdef CGAL_USE_BOOST_MP +#include +#endif // CGAL_USE_BOOST_MP namespace CGAL { @@ -46,6 +49,15 @@ template < typename NT > inline void simplify_quotient(NT &, NT &) {} +#ifdef CGAL_USE_BOOST_MP +inline void +simplify_quotient(boost::multiprecision::cpp_int & a, boost::multiprecision::cpp_int & b) { + const boost::multiprecision::cpp_int r = boost::multiprecision::gcd(a, b); + a /= r; + b /= r; +} +#endif // CGAL_USE_BOOST_MP + // This one should be replaced by some functor or tag. // Meanwhile, the class is specialized for Gmpz, mpz_class, leda_integer. template < typename NT > diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index d64cdf650aed..c650273aa9f4 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -794,14 +794,6 @@ namespace internal { #ifdef CGAL_USE_BOOST_MP -template < > -inline void -simplify_quotient(boost::multiprecision::cpp_int & a, boost::multiprecision::cpp_int & b) { - const boost::multiprecision::cpp_int r = boost::multiprecision::gcd(a, b); - a /= r; - b /= r; -} - template< > class Real_embeddable_traits< Quotient > : public INTERN_QUOTIENT::Real_embeddable_traits_quotient_base< Quotient > { From 7c9982b4956c1c4d95632cb1b957117b893f06e6 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 8 Oct 2021 11:48:55 +0200 Subject: [PATCH 093/127] fixed errors in github workflow + added more comments --- .../internal/Exact_type_selector.h | 6 +++- Number_types/include/CGAL/boost_mp.h | 32 +++++++++++++------ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h index 55fee2acd5c9..c9a2b122a711 100644 --- a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h @@ -71,8 +71,12 @@ struct Exact_field_selector // In fact, the new version of cpp_rational from here: https://github.com/boostorg/multiprecision/pull/366 // is much better than Quotient because it is using smart gcd and is well-supported // while Quotient does not. Though, we can still use it if needed. -// { typedef Quotient Type; }; +#if BOOST_VERSION <= 107700 +// See this comment: https://github.com/CGAL/cgal/pull/5937#discussion_r721533675 +{ typedef Quotient Type; }; +#else { typedef BOOST_cpp_arithmetic_kernel::Rational Type; }; +#endif #else { typedef Quotient Type; }; #endif diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index c650273aa9f4..e7739b60e331 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -143,18 +143,25 @@ struct Algebraic_structure_traits - my_ldexp( const Interval_nt& intv, const int e ) { + // We use this function instead of ldexp overload from Interval_nt.h because: + // - see this issue: https://github.com/CGAL/cgal/issues/6004 + // - in the original ldexp, when working with limit cases, we get CGAL_IA_MIN_DOUBLE + // e.g. that after multiplication by scale turns into a value that is not minimal double, + // which is expected for that limit case. So, we avoid multiplication by scale in this version + // for the limit cases and use it only for normal inf and sup cases. + template + Interval_nt my_ldexp( const Interval_nt& intv, const int e ) { CGAL_assertion(intv.inf() > 0.0); CGAL_assertion(intv.sup() > 0.0); const double scale = std::ldexp(1.0, e); - return Interval_nt ( + return Interval_nt( CGAL_NTS is_finite(scale) ? scale * intv.inf() : CGAL_IA_MAX_DOUBLE, - scale == 0.0 ? CGAL_IA_MIN_DOUBLE : scale * intv.sup() ); + scale == 0.0 ? CGAL_IA_MIN_DOUBLE : scale * intv.sup()); } + // This function checks if the computed interval is correct and if it is tight. template bool are_bounds_correct( const double l, const double u, const Type& x ) { @@ -181,6 +188,7 @@ namespace Boost_MP_internal { return are_bounds_tight && are_bounds_respected; } + // This one returns zero length interval that is inf = sup. template std::pair get_0ulp_interval( const int64_t shift, const ET& p ) { @@ -188,10 +196,12 @@ namespace Boost_MP_internal { const uint64_t pp = static_cast(p); CGAL_assertion(pp >= 0); const double pp_dbl = static_cast(pp); + // Here, false means no protection that is rounding is set to_nearest. const Interval_nt intv(pp_dbl, pp_dbl); return my_ldexp(intv, -static_cast(shift)).pair(); } + // This one returns 1 unit length interval. template std::pair get_1ulp_interval( const int64_t shift, const ET& p ) { @@ -202,10 +212,13 @@ namespace Boost_MP_internal { CGAL_assertion(qq > pp); const double pp_dbl = static_cast(pp); const double qq_dbl = static_cast(qq); + // Here, false means no protection that is rounding is set to_nearest. const Interval_nt intv(pp_dbl, qq_dbl); return my_ldexp(intv, -static_cast(shift)).pair(); } + // This is a version of to_interval that converts a rational type into + // double tight interval. template std::pair to_interval(const Type& x, ET xnum, ET xden ) { @@ -402,10 +415,8 @@ struct RET_boost_mp > { std::pair operator()( const Type& x ) const { - - const auto& xnum = boost::multiprecision::numerator(x); - const auto& xden = boost::multiprecision::denominator(x); - return Boost_MP_internal::to_interval(x, xnum, xden); + return Boost_MP_internal::to_interval(x, + boost::multiprecision::numerator(x), boost::multiprecision::denominator(x)); } }; }; @@ -943,7 +954,8 @@ template< > class Real_embeddable_traits< Quotient(shift)).pair(); @@ -953,6 +965,8 @@ template< > class Real_embeddable_traits< Quotient operator()( const Type& x ) const { return Boost_MP_internal::to_interval(x, x.num, x.den); From 5ac8bb0f7eef748c5ba39d8ee7cbf0489cf4d734 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 8 Oct 2021 12:24:41 +0200 Subject: [PATCH 094/127] added to_interval for integer boost types --- Number_types/include/CGAL/boost_mp.h | 66 +++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index e7739b60e331..af53174996eb 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -217,7 +217,7 @@ namespace Boost_MP_internal { return my_ldexp(intv, -static_cast(shift)).pair(); } - // This is a version of to_interval that converts a rational type into + // This is a version of to_interval that converts a rational type into a // double tight interval. template std::pair to_interval(const Type& x, ET xnum, ET xden ) { @@ -306,6 +306,59 @@ namespace Boost_MP_internal { return std::make_pair(l, u); } + // This is a version of to_interval that converts an integer type into a + // double tight interval. + template + std::pair to_interval( ET x ) { + + CGAL_assertion_code(const ET input = x); + double l = 0.0, u = 0.0; + if (CGAL::is_zero(x)) { // return [0.0, 0.0] + CGAL_assertion(are_bounds_correct(l, u, input)); + return std::make_pair(l, u); + } + CGAL_assertion(!CGAL::is_zero(x)); + + bool change_sign = false; + const bool is_pos = CGAL::is_positive(x); + if (!is_pos) { + change_sign = true; + x = -x; + } + CGAL_assertion(CGAL::is_positive(x)); + + int64_t e = 0; + const int64_t n = static_cast(boost::multiprecision::msb(x)) + 1; + const int64_t num_dbl_digits = std::numeric_limits::digits; + + if (n > num_dbl_digits) { + e = n - num_dbl_digits; + x >>= e; + const uint64_t xx = static_cast(x); + const uint64_t yy = xx + 1; + CGAL_assertion(xx > 0 && yy > xx); + l = static_cast(xx); + u = static_cast(yy); + } else { + const uint64_t xx = static_cast(x); + CGAL_assertion(xx > 0); + l = static_cast(xx); + u = l; + } + + const Interval_nt intv(l, u); + std::tie(l, u) = my_ldexp(intv, e).pair(); + + if (change_sign) { + const double t = l; + l = -u; + u = -t; + } + + CGAL_assertion(are_bounds_correct(l, u, input)); + return std::make_pair(l, u); + } + } // Boost_MP_internal template @@ -405,7 +458,16 @@ struct RET_boost_mp; template struct RET_boost_mp > - : RET_boost_mp_base {}; + : RET_boost_mp_base { + typedef NT Type; + struct To_interval + : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { + + std::pair operator()( const Type& x ) const { + return Boost_MP_internal::to_interval(x); + } + }; +}; template struct RET_boost_mp > From 1ae8b32859db6d46585899e5ef0e6db49bbcd4d4 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 8 Oct 2021 13:39:35 +0200 Subject: [PATCH 095/127] use cpp rational only if boost is >= 1.78 --- Number_types/include/CGAL/Exact_integer.h | 5 +++++ .../include/CGAL/Number_types/internal/Exact_type_selector.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/Number_types/include/CGAL/Exact_integer.h b/Number_types/include/CGAL/Exact_integer.h index 5b6e0988d7b0..3c3cb4713eca 100644 --- a/Number_types/include/CGAL/Exact_integer.h +++ b/Number_types/include/CGAL/Exact_integer.h @@ -50,6 +50,10 @@ typedef unspecified_type Exact_integer; #else // not DOXYGEN_RUNNING +#if BOOST_VERSION > 107700 && defined(CGAL_USE_BOOST_MP) +// TODO: That is used for testing, it must be removed when merging into master. +typedef BOOST_cpp_arithmetic_kernel::Integer Exact_integer; +#else // BOOST_VERSION <= 107700 #ifdef CGAL_USE_GMPXX typedef mpz_class Exact_integer; #elif defined(CGAL_USE_GMP) @@ -67,6 +71,7 @@ typedef CORE::BigInt Exact_integer; #else #error "ERROR: Cannot determine a BigInt type!" #endif // CGAL_USE_CORE +#endif // BOOST_VERSION <= 107700 #endif // not DOXYGEN_RUNNING diff --git a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h index c9a2b122a711..def7a052ed73 100644 --- a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h @@ -55,6 +55,10 @@ namespace CGAL { namespace internal { template < typename > struct Exact_field_selector +#if BOOST_VERSION > 107700 && defined(CGAL_USE_BOOST_MP) +// TODO: That is used for testing, it must be removed when merging into master. +{ typedef BOOST_cpp_arithmetic_kernel::Rational Type; }; +#else // BOOST_VERSION <= 107700 #ifdef CGAL_USE_GMPXX { typedef mpq_class Type; }; #elif defined(CGAL_USE_GMP) @@ -80,6 +84,7 @@ struct Exact_field_selector #else { typedef Quotient Type; }; #endif +#endif // BOOST_VERSION <= 107700 // By default, a field is a safe choice of ring. template < typename T > From 4f4b48e369facdcad6a8554d6adfaf7a9c7f0da7 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 8 Oct 2021 14:09:25 +0200 Subject: [PATCH 096/127] added tests for to_interval(cpp_int) --- .../Number_types/to_interval_test_boost.cpp | 217 ++++++++++++++---- 1 file changed, 166 insertions(+), 51 deletions(-) diff --git a/Number_types/test/Number_types/to_interval_test_boost.cpp b/Number_types/test/Number_types/to_interval_test_boost.cpp index 461b90166747..4c456651fb4e 100644 --- a/Number_types/test/Number_types/to_interval_test_boost.cpp +++ b/Number_types/test/Number_types/to_interval_test_boost.cpp @@ -111,19 +111,19 @@ void test_to_interval_boost() { } // In assert, we use values from impl2. -void test_to_interval_tight_1() { +void test_to_interval_tight_rational_1() { // In green, we compare to impl2. - #define TESTCASE10 // pass all three - #define TESTCASE11 // impl1: fails tightness (sup is larger, s = 9.3488310472396616291) - #define TESTCASE12 // pass all three - #define TESTCASE13 // pass all three - #define TESTCASE14 // pass all three - #define TESTCASE15 // pass all three - #define TESTCASE16 // pass all three - #define TESTCASE17 // pass all three - #define TESTCASE18 // pass all three - #define TESTCASE19 // pass all three + #define TESTCASE_RAT_10 // pass all three + #define TESTCASE_RAT_11 // impl1: fails tightness (sup is larger, s = 9.3488310472396616291) + #define TESTCASE_RAT_12 // pass all three + #define TESTCASE_RAT_13 // pass all three + #define TESTCASE_RAT_14 // pass all three + #define TESTCASE_RAT_15 // pass all three + #define TESTCASE_RAT_16 // pass all three + #define TESTCASE_RAT_17 // pass all three + #define TESTCASE_RAT_18 // pass all three + #define TESTCASE_RAT_19 // pass all three using NT = boost::multiprecision::cpp_int; using Quotient = CGAL::Quotient; @@ -141,10 +141,10 @@ void test_to_interval_tight_1() { double i, s; std::cout << std::endl; - std::cout << "- T1 testing tight interval ..." << std::endl; + std::cout << "- T1 testing tight interval for rationals ..." << std::endl; std::cout << std::endl; - #ifdef TESTCASE10 // small numbers + #ifdef TESTCASE_RAT_10 // small numbers std::cout << "=============" << std::endl; std::cout << "CASE0 RESULT:" << std::endl; @@ -162,13 +162,12 @@ void test_to_interval_tight_1() { std::cout << "ref: 282.74333882308138755" << std::endl; std::cout << std::endl; - // Results for current tight using master to_interval(). assert(i == 282.7433388230813307); assert(s == 282.74333882308138755); #endif - #ifdef TESTCASE11 // large numbers + #ifdef TESTCASE_RAT_11 // large numbers std::cout << "=============" << std::endl; std::cout << "CASE1 RESULT:" << std::endl; @@ -192,7 +191,7 @@ void test_to_interval_tight_1() { #endif - #ifdef TESTCASE12 + #ifdef TESTCASE_RAT_12 std::cout << "=============" << std::endl; std::cout << "CASE2 RESULT:" << std::endl; @@ -215,7 +214,7 @@ void test_to_interval_tight_1() { #endif - #ifdef TESTCASE13 + #ifdef TESTCASE_RAT_13 std::cout << "=============" << std::endl; std::cout << "CASE3 RESULT:" << std::endl; @@ -238,7 +237,7 @@ void test_to_interval_tight_1() { #endif - #ifdef TESTCASE14 + #ifdef TESTCASE_RAT_14 std::cout << "=============" << std::endl; std::cout << "CASE4 RESULT:" << std::endl; @@ -261,7 +260,7 @@ void test_to_interval_tight_1() { #endif - #ifdef TESTCASE15 + #ifdef TESTCASE_RAT_15 std::cout << "=============" << std::endl; std::cout << "CASE5 RESULT:" << std::endl; @@ -284,7 +283,7 @@ void test_to_interval_tight_1() { #endif - #ifdef TESTCASE16 + #ifdef TESTCASE_RAT_16 std::cout << "=============" << std::endl; std::cout << "CASE6 RESULT:" << std::endl; @@ -307,7 +306,7 @@ void test_to_interval_tight_1() { #endif - #ifdef TESTCASE17 + #ifdef TESTCASE_RAT_17 std::cout << "=============" << std::endl; std::cout << "CASE7 RESULT:" << std::endl; @@ -330,7 +329,7 @@ void test_to_interval_tight_1() { #endif - #ifdef TESTCASE18 + #ifdef TESTCASE_RAT_18 std::cout << "=============" << std::endl; std::cout << "CASE8 RESULT:" << std::endl; @@ -353,7 +352,7 @@ void test_to_interval_tight_1() { #endif - #ifdef TESTCASE19 // small numbers, num > 0 and den < 0 + #ifdef TESTCASE_RAT_19 // small numbers, num > 0 and den < 0 std::cout << "=============" << std::endl; std::cout << "CASE9 RESULT:" << std::endl; @@ -381,21 +380,21 @@ void test_to_interval_tight_1() { } // In assert, we use values from impl2. -void test_to_interval_tight_2() { +void test_to_interval_tight_rational_2() { // In green, we compare to impl2. - #define TESTCASE20 // pass all three - #define TESTCASE21 // impl1: fails tightness (sup is larger, s = 0.43464565325999998668) - #define TESTCASE22 // pass all three - #define TESTCASE23 // pass all three - #define TESTCASE24 // pass all three - #define TESTCASE25 // pass all three - #define TESTCASE26 // pass all three - #define TESTCASE27 // pass all three - #define TESTCASE28 // pass all three - #define TESTCASE29 // pass all three - #define TESTCASE210 // impl1, impl3: fails tightness (sup is larger, s = 5.9425938166208590782e+26) - #define TESTCASE211 // impl1, impl3: fails tightness (inf is smaller, i = 3602879701896396.5, sup is larger, s = 3602879701896398) + #define TESTCASE_RAT_20 // pass all three + #define TESTCASE_RAT_21 // impl1: fails tightness (sup is larger, s = 0.43464565325999998668) + #define TESTCASE_RAT_22 // pass all three + #define TESTCASE_RAT_23 // pass all three + #define TESTCASE_RAT_24 // pass all three + #define TESTCASE_RAT_25 // pass all three + #define TESTCASE_RAT_26 // pass all three + #define TESTCASE_RAT_27 // pass all three + #define TESTCASE_RAT_28 // pass all three + #define TESTCASE_RAT_29 // pass all three + #define TESTCASE_RAT_210 // impl1, impl3: fails tightness (sup is larger, s = 5.9425938166208590782e+26) + #define TESTCASE_RAT_211 // impl1, impl3: fails tightness (inf is smaller, i = 3602879701896396.5, sup is larger, s = 3602879701896398) using NT = boost::multiprecision::cpp_int; using Quotient = CGAL::Quotient; @@ -407,10 +406,10 @@ void test_to_interval_tight_2() { double i, s; std::cout << std::endl; - std::cout << "- T2 testing tight interval ..." << std::endl; + std::cout << "- T2 testing tight interval for rationals ..." << std::endl; std::cout << std::endl; - #ifdef TESTCASE20 + #ifdef TESTCASE_RAT_20 std::cout << "TEST 0" << std::endl; // num, case 2 @@ -432,7 +431,7 @@ void test_to_interval_tight_2() { #endif - #ifdef TESTCASE21 + #ifdef TESTCASE_RAT_21 std::cout << "TEST 1" << std::endl; // num, case 4 @@ -453,7 +452,7 @@ void test_to_interval_tight_2() { #endif - #ifdef TESTCASE22 + #ifdef TESTCASE_RAT_22 std::cout << "TEST 2" << std::endl; // num, case 4 @@ -475,7 +474,7 @@ void test_to_interval_tight_2() { #endif - #ifdef TESTCASE23 + #ifdef TESTCASE_RAT_23 std::cout << "TEST 3" << std::endl; // shift = 0 @@ -497,7 +496,7 @@ void test_to_interval_tight_2() { #endif - #ifdef TESTCASE24 + #ifdef TESTCASE_RAT_24 std::cout << "TEST 4" << std::endl; @@ -519,7 +518,7 @@ void test_to_interval_tight_2() { #endif - #ifdef TESTCASE25 + #ifdef TESTCASE_RAT_25 std::cout << "TEST 5" << std::endl; @@ -541,7 +540,7 @@ void test_to_interval_tight_2() { #endif - #ifdef TESTCASE26 + #ifdef TESTCASE_RAT_26 std::cout << "TEST 6" << std::endl; // case shift > 0 && p_bits = 51, subcase1 @@ -563,7 +562,7 @@ void test_to_interval_tight_2() { #endif - #ifdef TESTCASE27 + #ifdef TESTCASE_RAT_27 std::cout << "TEST 7" << std::endl; // non representable double @@ -585,7 +584,7 @@ void test_to_interval_tight_2() { #endif - #ifdef TESTCASE28 + #ifdef TESTCASE_RAT_28 std::cout << "TEST 8" << std::endl; // fails assertion (q_bits == num_dbl_digits || r != 0) @@ -607,7 +606,7 @@ void test_to_interval_tight_2() { #endif - #ifdef TESTCASE29 + #ifdef TESTCASE_RAT_29 std::cout << "TEST 9" << std::endl; // case shift > 0 && p_bits = 51, subcase3 @@ -629,7 +628,7 @@ void test_to_interval_tight_2() { #endif - #ifdef TESTCASE210 + #ifdef TESTCASE_RAT_210 std::cout << "TEST 10" << std::endl; // case shift < 0 && p_bits = 51 @@ -651,7 +650,7 @@ void test_to_interval_tight_2() { #endif - #ifdef TESTCASE211 + #ifdef TESTCASE_RAT_211 std::cout << "TEST 11" << std::endl; // case shift = 0 && p_bits = 51 && cmp = 0, subcase3 @@ -677,6 +676,118 @@ void test_to_interval_tight_2() { std::cout << std::endl; } +void test_to_interval_tight_integer() { + + #define TESTCASE_INT_0 + #define TESTCASE_INT_1 + #define TESTCASE_INT_2 + #define TESTCASE_INT_3 + + using NT = boost::multiprecision::cpp_int; + using Traits = CGAL::Real_embeddable_traits; + using Interval = typename Traits::To_interval; + + // std::cout << std::endl; + // std::cout << boost::typeindex::type_id() << std::endl; + // std::cout << std::endl; + // std::cout << boost::typeindex::type_id() << std::endl; + // std::cout << std::endl; + + NT x; + double i, s; + + std::cout << std::endl; + std::cout << "- T testing tight interval for integers ..." << std::endl; + std::cout << std::endl; + + #ifdef TESTCASE_INT_0 + + std::cout << "=============" << std::endl; + std::cout << "CASE0 RESULT:" << std::endl; + std::cout << "=============" << std::endl; + + x = NT("0"); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 0" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: 0" << std::endl; + std::cout << std::endl; + + assert(i == 0.0); + assert(s == 0.0); + + #endif + + #ifdef TESTCASE_INT_1 + + std::cout << "=============" << std::endl; + std::cout << "CASE1 RESULT:" << std::endl; + std::cout << "=============" << std::endl; + + x = NT("5"); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 5" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: 5" << std::endl; + std::cout << std::endl; + + assert(i == 5.0); + assert(s == 5.0); + + #endif + + #ifdef TESTCASE_INT_2 + + std::cout << "=============" << std::endl; + std::cout << "CASE2 RESULT:" << std::endl; + std::cout << "=============" << std::endl; + + x = NT(-12); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: -12" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: -12" << std::endl; + std::cout << std::endl; + + assert(i == -12.0); + assert(s == -12.0); + + #endif + + #ifdef TESTCASE_INT_3 + + std::cout << "=============" << std::endl; + std::cout << "CASE3 RESULT:" << std::endl; + std::cout << "=============" << std::endl; + + x = NT("772537196160711547532081795586792063331305895970601529435744397743492241616327030886637827664482971614281724796166908515292029740442872965475211471498392497954317530347232852540146110053764627070672243390766540271554856759037331142360111552286202392826786995364211101723592791550906796165626083442695020580821188398298798456115881346136681033873"); + std::tie(i, s) = Interval()(x); + + std::cout << std::endl; + std::cout << "inf: " << i << std::endl; + std::cout << "ref: 1.7976931348623157081e+308" << std::endl; + std::cout << "sup: " << s << std::endl; + std::cout << "ref: inf" << std::endl; + std::cout << std::endl; + + assert(i == std::numeric_limits::max()); + assert(s == std::numeric_limits::infinity()); + + #endif + + std::cout << "---SUCCESS ALL---" << std::endl; + std::cout << std::endl; +} + #endif // CGAL_USE_BOOST_MP int main() { @@ -693,8 +804,12 @@ int main() { test_minimal_boost_gcd(); test_to_interval_boost(); - test_to_interval_tight_1(); - test_to_interval_tight_2(); + // Test rational types. + test_to_interval_tight_rational_1(); + test_to_interval_tight_rational_2(); + + // Test integer types. + test_to_interval_tight_integer(); #endif // CGAL_USE_BOOST_MP return EXIT_SUCCESS; From 253a3e9bbefe90cc03e87743ba86c4106697a745 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 8 Oct 2021 16:40:12 +0200 Subject: [PATCH 097/127] use better rounding --- Number_types/include/CGAL/boost_mp.h | 54 +++++++++++++------ .../Number_types/to_interval_test_boost.cpp | 16 +++--- 2 files changed, 47 insertions(+), 23 deletions(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index af53174996eb..be75a1ad2b53 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -149,16 +149,29 @@ namespace Boost_MP_internal { // e.g. that after multiplication by scale turns into a value that is not minimal double, // which is expected for that limit case. So, we avoid multiplication by scale in this version // for the limit cases and use it only for normal inf and sup cases. - template - Interval_nt my_ldexp( const Interval_nt& intv, const int e ) { - - CGAL_assertion(intv.inf() > 0.0); - CGAL_assertion(intv.sup() > 0.0); - const double scale = std::ldexp(1.0, e); - return Interval_nt( - CGAL_NTS is_finite(scale) ? - scale * intv.inf() : CGAL_IA_MAX_DOUBLE, - scale == 0.0 ? CGAL_IA_MIN_DOUBLE : scale * intv.sup()); + + // template + // Interval_nt my_ldexp( const Interval_nt& intv, const int e ) { + // CGAL_assertion(intv.inf() > 0.0); + // CGAL_assertion(intv.sup() > 0.0); + // const double scale = std::ldexp(1.0, e); + // Protect_FPU_rounding P(CGAL_FE_UPWARD); + // return Interval_nt( + // CGAL_NTS is_finite(scale) ? + // scale * intv.inf() : CGAL_IA_MAX_DOUBLE, + // scale == 0.0 ? CGAL_IA_MIN_DOUBLE : scale * intv.sup()); + // } + + template + bool is_spliiter_working(const T d) { + T num = d; + T den = 1.0; + while (std::ceil(num) != num) { + num *= 2.0; + den *= 2.0; + } + if (d != num / den) return false; + return true; } // This function checks if the computed interval is correct and if it is tight. @@ -169,6 +182,16 @@ namespace Boost_MP_internal { CGAL_assertion(u == l || u == std::nextafter(l, +inf)); const bool are_bounds_tight = (u == l || u == std::nextafter(l, +inf)); + // This check is required until a bug in double.h:split_numerator_denominator() is fixed. + // For the moment, this splitter does not handle certain limit values. + // See also: https://github.com/CGAL/cgal/issues/5982 + // E.g. it fails for d = 2.752961027411077E-308! + if (!is_spliiter_working(l) || !is_spliiter_working(u)) { + return are_bounds_tight; + } + CGAL_assertion(is_spliiter_working(l) && is_spliiter_working(u)); + + // We cannot convert inf to Type so we skip. if ( CGAL::abs(l) == inf || CGAL::abs(u) == inf || @@ -196,9 +219,9 @@ namespace Boost_MP_internal { const uint64_t pp = static_cast(p); CGAL_assertion(pp >= 0); const double pp_dbl = static_cast(pp); - // Here, false means no protection that is rounding is set to_nearest. const Interval_nt intv(pp_dbl, pp_dbl); - return my_ldexp(intv, -static_cast(shift)).pair(); + Protect_FPU_rounding P(CGAL_FE_UPWARD); + return CGAL::ldexp(intv, -static_cast(shift)).pair(); } // This one returns 1 unit length interval. @@ -212,9 +235,9 @@ namespace Boost_MP_internal { CGAL_assertion(qq > pp); const double pp_dbl = static_cast(pp); const double qq_dbl = static_cast(qq); - // Here, false means no protection that is rounding is set to_nearest. const Interval_nt intv(pp_dbl, qq_dbl); - return my_ldexp(intv, -static_cast(shift)).pair(); + Protect_FPU_rounding P(CGAL_FE_UPWARD); + return CGAL::ldexp(intv, -static_cast(shift)).pair(); } // This is a version of to_interval that converts a rational type into a @@ -347,7 +370,8 @@ namespace Boost_MP_internal { } const Interval_nt intv(l, u); - std::tie(l, u) = my_ldexp(intv, e).pair(); + Protect_FPU_rounding P(CGAL_FE_UPWARD); + std::tie(l, u) = CGAL::ldexp(intv, e).pair(); if (change_sign) { const double t = l; diff --git a/Number_types/test/Number_types/to_interval_test_boost.cpp b/Number_types/test/Number_types/to_interval_test_boost.cpp index 4c456651fb4e..9455a9ad319a 100644 --- a/Number_types/test/Number_types/to_interval_test_boost.cpp +++ b/Number_types/test/Number_types/to_interval_test_boost.cpp @@ -227,13 +227,13 @@ void test_to_interval_tight_rational_1() { std::cout << std::endl; std::cout << "inf: " << i << std::endl; - std::cout << "ref: 0" << std::endl; + std::cout << "ref: 2.7529610274110770119e-308" << std::endl; std::cout << "sup: " << s << std::endl; - std::cout << "ref: 4.9406564584124654418e-324" << std::endl; + std::cout << "ref: 2.7529610274110775060e-308" << std::endl; std::cout << std::endl; - assert(i == 0.0); - assert(s == std::numeric_limits::denorm_min()); + assert(i == 2.7529610274110770119e-308); + assert(s == 2.7529610274110775060e-308); #endif @@ -530,13 +530,13 @@ void test_to_interval_tight_rational_2() { std::cout << std::endl; std::cout << "inf: " << i << std::endl; - std::cout << "ref: 0" << std::endl; + std::cout << "ref: 2.7529610274110770119e-308" << std::endl; std::cout << "sup: " << s << std::endl; - std::cout << "ref: 4.9406564584124654418e-324" << std::endl; + std::cout << "ref: 2.7529610274110775060e-308" << std::endl; std::cout << std::endl; - assert(i == 0); - assert(s == std::numeric_limits::denorm_min()); + assert(i == 2.7529610274110770119e-308); + assert(s == 2.7529610274110775060e-308); #endif From a78c2798f39439754471e8a51e397b951fc75f68 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 16 Nov 2021 15:43:17 +0100 Subject: [PATCH 098/127] remove warning about unused variable --- Number_types/include/CGAL/boost_mp.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index be75a1ad2b53..5fd0609ddd81 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -243,10 +243,10 @@ namespace Boost_MP_internal { // This is a version of to_interval that converts a rational type into a // double tight interval. template - std::pair to_interval(const Type& x, ET xnum, ET xden ) { + std::pair to_interval( ET xnum, ET xden ) { CGAL_assertion(!CGAL::is_zero(xden)); - CGAL_assertion_code(const Type input = x); + CGAL_assertion_code(const Type input(xnum, xden)); double l = 0.0, u = 0.0; if (CGAL::is_zero(xnum)) { // return [0.0, 0.0] CGAL_assertion(are_bounds_correct(l, u, input)); @@ -501,8 +501,8 @@ struct RET_boost_mp > { std::pair operator()( const Type& x ) const { - return Boost_MP_internal::to_interval(x, - boost::multiprecision::numerator(x), boost::multiprecision::denominator(x)); + return Boost_MP_internal::to_interval( + boost::multiprecision::numerator(x), boost::multiprecision::denominator(x)); } }; }; @@ -1055,7 +1055,7 @@ template< > class Real_embeddable_traits< Quotient operator()( const Type& x ) const { - return Boost_MP_internal::to_interval(x, x.num, x.den); + return Boost_MP_internal::to_interval(x.num, x.den); } }; }; From 8015cb7d8a8acb09c19f833205ec454ec7e7dcbe Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 16 Nov 2021 15:46:24 +0100 Subject: [PATCH 099/127] fixed warning about converting int64 to int --- Number_types/include/CGAL/boost_mp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 5fd0609ddd81..e8ab70ac9be6 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -371,7 +371,7 @@ namespace Boost_MP_internal { const Interval_nt intv(l, u); Protect_FPU_rounding P(CGAL_FE_UPWARD); - std::tie(l, u) = CGAL::ldexp(intv, e).pair(); + std::tie(l, u) = CGAL::ldexp(intv, static_cast(e)).pair(); if (change_sign) { const double t = l; From 8ad618c7a2c737b298bc6d2781a431205a69d50a Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 16 Nov 2021 16:31:20 +0100 Subject: [PATCH 100/127] fixed compilation error --- .../include/CGAL/Number_types/internal/Exact_type_selector.h | 3 +++ Number_types/include/CGAL/boost_mp.h | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h index 0b55c8e3b094..a157ba253525 100644 --- a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h @@ -24,7 +24,10 @@ #include #include +#ifdef CGAL_USE_BOOST_MP #include +#endif + #ifdef CGAL_USE_GMP # include # include diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index e8ab70ac9be6..778e1ddeed2c 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -501,7 +501,7 @@ struct RET_boost_mp > { std::pair operator()( const Type& x ) const { - return Boost_MP_internal::to_interval( + return Boost_MP_internal::to_interval( boost::multiprecision::numerator(x), boost::multiprecision::denominator(x)); } }; @@ -1055,7 +1055,7 @@ template< > class Real_embeddable_traits< Quotient operator()( const Type& x ) const { - return Boost_MP_internal::to_interval(x.num, x.den); + return Boost_MP_internal::to_interval(x.num, x.den); } }; }; From 9fd2da61d3b90240f5730aa2814f51832ce2ea9b Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 16 Nov 2021 16:31:34 +0100 Subject: [PATCH 101/127] fixed runtime errors --- .../Number_types/to_interval_test_boost.cpp | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Number_types/test/Number_types/to_interval_test_boost.cpp b/Number_types/test/Number_types/to_interval_test_boost.cpp index 9455a9ad319a..5cf577fec223 100644 --- a/Number_types/test/Number_types/to_interval_test_boost.cpp +++ b/Number_types/test/Number_types/to_interval_test_boost.cpp @@ -59,6 +59,8 @@ void test_minimal_boost_gcd() { std::cout << "new v: " << v << std::endl; } +#if false // _MM_ROUND_UP is not available on all platforms + void test_minimal_nextafter() { _MM_SET_ROUNDING_MODE(_MM_ROUND_UP); // fail @@ -81,6 +83,8 @@ void test_minimal_nextafter() { } } +#endif // test_minimal_nextafter + void test_to_interval_boost() { using NT = boost::multiprecision::cpp_int; @@ -227,13 +231,14 @@ void test_to_interval_tight_rational_1() { std::cout << std::endl; std::cout << "inf: " << i << std::endl; - std::cout << "ref: 2.7529610274110770119e-308" << std::endl; + std::cout << "ref: 0.0 or higher" << std::endl; std::cout << "sup: " << s << std::endl; - std::cout << "ref: 2.7529610274110775060e-308" << std::endl; + std::cout << "ref: 0.0 or higher" << std::endl; std::cout << std::endl; - assert(i == 2.7529610274110770119e-308); - assert(s == 2.7529610274110775060e-308); + assert(i >= 0.0 && i <= std::numeric_limits::min() * 2.0); + assert(s >= 0.0 && s <= std::numeric_limits::min() * 2.0); + assert(i <= s); #endif @@ -530,13 +535,14 @@ void test_to_interval_tight_rational_2() { std::cout << std::endl; std::cout << "inf: " << i << std::endl; - std::cout << "ref: 2.7529610274110770119e-308" << std::endl; + std::cout << "ref: 0.0 or higher" << std::endl; std::cout << "sup: " << s << std::endl; - std::cout << "ref: 2.7529610274110775060e-308" << std::endl; + std::cout << "ref: 0.0 or higher" << std::endl; std::cout << std::endl; - assert(i == 2.7529610274110770119e-308); - assert(s == 2.7529610274110775060e-308); + assert(i >= 0.0 && i <= std::numeric_limits::min() * 2.0); + assert(s >= 0.0 && s <= std::numeric_limits::min() * 2.0); + assert(i <= s); #endif From d7a7f76a5fbbccdede17e113b5497734260ab67d Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 17 Nov 2021 11:41:44 +0100 Subject: [PATCH 102/127] fixed errors in the workflow --- NewKernel_d/test/NewKernel_d/Epick_d.cpp | 1 + .../include/CGAL/Number_types/internal/Exact_type_selector.h | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/NewKernel_d/test/NewKernel_d/Epick_d.cpp b/NewKernel_d/test/NewKernel_d/Epick_d.cpp index 3f13d8970d5e..335d72166646 100644 --- a/NewKernel_d/test/NewKernel_d/Epick_d.cpp +++ b/NewKernel_d/test/NewKernel_d/Epick_d.cpp @@ -1,6 +1,7 @@ #include //#define BOOST_RESULT_OF_USE_DECLTYPE 1 +#define CGAL_DO_NOT_USE_BOOST_MP // this test does not compile with cpp_rational #include #include #include diff --git a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h index a157ba253525..0b55c8e3b094 100644 --- a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h @@ -24,10 +24,7 @@ #include #include -#ifdef CGAL_USE_BOOST_MP #include -#endif - #ifdef CGAL_USE_GMP # include # include From 07607223a2f939e83ad859bf80bf61faaf1ce7d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 2 Feb 2022 10:48:24 +0100 Subject: [PATCH 103/127] use custom ldexp for positive intervals --- Number_types/include/CGAL/boost_mp.h | 73 +++++++++++++++------------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 778e1ddeed2c..ad23d9517f7a 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -143,27 +143,28 @@ struct Algebraic_structure_traits - // Interval_nt my_ldexp( const Interval_nt& intv, const int e ) { - // CGAL_assertion(intv.inf() > 0.0); - // CGAL_assertion(intv.sup() > 0.0); - // const double scale = std::ldexp(1.0, e); - // Protect_FPU_rounding P(CGAL_FE_UPWARD); - // return Interval_nt( - // CGAL_NTS is_finite(scale) ? - // scale * intv.inf() : CGAL_IA_MAX_DOUBLE, - // scale == 0.0 ? CGAL_IA_MIN_DOUBLE : scale * intv.sup()); - // } + Interval_nt shift_positive_interval( const Interval_nt& intv, const int e ) { + CGAL_assertion(intv.inf() > 0.0); + CGAL_assertion(intv.sup() > 0.0); + typedef std::numeric_limits limits; + + if (e < std::numeric_limits::min_exponent) + { + if ( e+std::numeric_limits::digits < std::numeric_limits::min_exponent) + return CGAL::Interval_nt(0, (limits::min)()); + // following calls to ldexp call are exact (e+digits is larger or equal to min_exponent) is less than min_exponent + return CGAL::Interval_nt(std::ldexp(intv.inf(), e), std::ldexp(intv.sup(), e)); + } + if (e > limits::max_exponent) + return CGAL::Interval_nt((limits::max)(), limits::infinity()); // no multiplication as intv is positive + + const double scale = std::ldexp(1.0, e); // ldexp call is exact (e is less than min_exponent) + return scale * intv; + } +/* template - bool is_spliiter_working(const T d) { + bool is_splitter_working(const T d) { T num = d; T den = 1.0; while (std::ceil(num) != num) { @@ -173,40 +174,46 @@ namespace Boost_MP_internal { if (d != num / den) return false; return true; } +*/ // This function checks if the computed interval is correct and if it is tight. template bool are_bounds_correct( const double l, const double u, const Type& x ) { + typedef std::numeric_limits limits; const double inf = std::numeric_limits::infinity(); - CGAL_assertion(u == l || u == std::nextafter(l, +inf)); + if ( u!=l && (u==-inf || l==inf + || (u==0 && l >= -(limits::min)()) + || (l==0 && u <= (limits::min)())) ) + { + return x > Type((limits::max)()) || + x < Type(-(limits::max)()) || + (x > Type(-(limits::min)()) && x < Type((limits::min)())); + } + +// CGAL_assertion(u == l || u == std::nextafter(l, +inf)); const bool are_bounds_tight = (u == l || u == std::nextafter(l, +inf)); +/* // This check is required until a bug in double.h:split_numerator_denominator() is fixed. // For the moment, this splitter does not handle certain limit values. // See also: https://github.com/CGAL/cgal/issues/5982 // E.g. it fails for d = 2.752961027411077E-308! - if (!is_spliiter_working(l) || !is_spliiter_working(u)) { + if (!is_splitter_working(l) || !is_splitter_working(u)) { return are_bounds_tight; } CGAL_assertion(is_spliiter_working(l) && is_spliiter_working(u)); - +*/ // We cannot convert inf to Type so we skip. if ( CGAL::abs(l) == inf || CGAL::abs(u) == inf || CGAL::abs(l) == 0.0 || - CGAL::abs(u) == 0.0) { + CGAL::abs(u) == 0.0) + { return are_bounds_tight; } - CGAL_assertion(CGAL::abs(l) != inf); - CGAL_assertion(CGAL::abs(u) != inf); - CGAL_assertion(CGAL::abs(l) != 0.0); - CGAL_assertion(CGAL::abs(u) != 0.0); - const Type lb(l), ub(u); - CGAL_assertion(lb <= x); - CGAL_assertion(ub >= x); const bool are_bounds_respected = (lb <= x && x <= ub); return are_bounds_tight && are_bounds_respected; } @@ -220,8 +227,8 @@ namespace Boost_MP_internal { CGAL_assertion(pp >= 0); const double pp_dbl = static_cast(pp); const Interval_nt intv(pp_dbl, pp_dbl); - Protect_FPU_rounding P(CGAL_FE_UPWARD); - return CGAL::ldexp(intv, -static_cast(shift)).pair(); + + return shift_positive_interval(intv, -static_cast(shift)).pair(); } // This one returns 1 unit length interval. @@ -237,7 +244,7 @@ namespace Boost_MP_internal { const double qq_dbl = static_cast(qq); const Interval_nt intv(pp_dbl, qq_dbl); Protect_FPU_rounding P(CGAL_FE_UPWARD); - return CGAL::ldexp(intv, -static_cast(shift)).pair(); + return shift_positive_interval(intv, -static_cast(shift)).pair(); } // This is a version of to_interval that converts a rational type into a From bc8b43653113b11cee8174c961f0f5113ca2475c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 2 Feb 2022 11:04:20 +0100 Subject: [PATCH 104/127] missing inline --- Number_types/include/CGAL/boost_mp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index ad23d9517f7a..58cae7eb18ec 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -143,6 +143,7 @@ struct Algebraic_structure_traits shift_positive_interval( const Interval_nt& intv, const int e ) { CGAL_assertion(intv.inf() > 0.0); CGAL_assertion(intv.sup() > 0.0); From 3d91757fdfb8800b5f71eb1d96e463aac4ae2aa5 Mon Sep 17 00:00:00 2001 From: Sebastien Loriot Date: Wed, 2 Feb 2022 11:17:24 +0100 Subject: [PATCH 105/127] fix comment Co-authored-by: Laurent Rineau --- Number_types/include/CGAL/boost_mp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 58cae7eb18ec..8159fd68d62b 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -153,7 +153,7 @@ namespace Boost_MP_internal { { if ( e+std::numeric_limits::digits < std::numeric_limits::min_exponent) return CGAL::Interval_nt(0, (limits::min)()); - // following calls to ldexp call are exact (e+digits is larger or equal to min_exponent) is less than min_exponent + // following calls to ldexp call are exact (e+digits is larger or equal to min_exponent) return CGAL::Interval_nt(std::ldexp(intv.inf(), e), std::ldexp(intv.sup(), e)); } if (e > limits::max_exponent) From 293ec172dc428a45d3fd417a46c9dfb3ce1ed7a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 3 Feb 2022 17:07:00 +0100 Subject: [PATCH 106/127] boost 1.79 is required to switch on boost mp by default --- Number_types/include/CGAL/Exact_integer.h | 6 +++--- .../CGAL/Number_types/internal/Exact_type_selector.h | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Number_types/include/CGAL/Exact_integer.h b/Number_types/include/CGAL/Exact_integer.h index 3c3cb4713eca..a55a63b20649 100644 --- a/Number_types/include/CGAL/Exact_integer.h +++ b/Number_types/include/CGAL/Exact_integer.h @@ -50,10 +50,10 @@ typedef unspecified_type Exact_integer; #else // not DOXYGEN_RUNNING -#if BOOST_VERSION > 107700 && defined(CGAL_USE_BOOST_MP) +#if BOOST_VERSION > 107800 && defined(CGAL_USE_BOOST_MP) // TODO: That is used for testing, it must be removed when merging into master. typedef BOOST_cpp_arithmetic_kernel::Integer Exact_integer; -#else // BOOST_VERSION <= 107700 +#else // BOOST_VERSION <= 107800 #ifdef CGAL_USE_GMPXX typedef mpz_class Exact_integer; #elif defined(CGAL_USE_GMP) @@ -71,7 +71,7 @@ typedef CORE::BigInt Exact_integer; #else #error "ERROR: Cannot determine a BigInt type!" #endif // CGAL_USE_CORE -#endif // BOOST_VERSION <= 107700 +#endif // BOOST_VERSION <= 107800 #endif // not DOXYGEN_RUNNING diff --git a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h index 0b55c8e3b094..54abcab97473 100644 --- a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h @@ -55,10 +55,10 @@ namespace CGAL { namespace internal { template < typename > struct Exact_field_selector -#if BOOST_VERSION > 107700 && defined(CGAL_USE_BOOST_MP) +#if BOOST_VERSION > 107800 && defined(CGAL_USE_BOOST_MP) // TODO: That is used for testing, it must be removed when merging into master. { typedef BOOST_cpp_arithmetic_kernel::Rational Type; }; -#else // BOOST_VERSION <= 107700 +#else // BOOST_VERSION <= 107800 #ifdef CGAL_USE_GMPXX { typedef mpq_class Type; }; #elif defined(CGAL_USE_GMP) @@ -75,7 +75,7 @@ struct Exact_field_selector // In fact, the new version of cpp_rational from here: https://github.com/boostorg/multiprecision/pull/366 // is much better than Quotient because it is using smart gcd and is well-supported // while Quotient does not. Though, we can still use it if needed. -#if BOOST_VERSION <= 107700 +#if BOOST_VERSION <= 107800 // See this comment: https://github.com/CGAL/cgal/pull/5937#discussion_r721533675 { typedef Quotient Type; }; #else @@ -84,7 +84,7 @@ struct Exact_field_selector #else { typedef Quotient Type; }; #endif -#endif // BOOST_VERSION <= 107700 +#endif // BOOST_VERSION <= 107800 // By default, a field is a safe choice of ring. template < typename T > From e82375ea226e85be9932c1e098cc7da7997e0049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 4 Feb 2022 09:39:38 +0100 Subject: [PATCH 107/127] try if the example now works --- NewKernel_d/test/NewKernel_d/Epick_d.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/NewKernel_d/test/NewKernel_d/Epick_d.cpp b/NewKernel_d/test/NewKernel_d/Epick_d.cpp index 335d72166646..824b9a526815 100644 --- a/NewKernel_d/test/NewKernel_d/Epick_d.cpp +++ b/NewKernel_d/test/NewKernel_d/Epick_d.cpp @@ -1,7 +1,5 @@ #include -//#define BOOST_RESULT_OF_USE_DECLTYPE 1 -#define CGAL_DO_NOT_USE_BOOST_MP // this test does not compile with cpp_rational #include #include #include From 1d285cc27ba7619e159d11dedd1019f5744e31c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 4 Feb 2022 13:54:11 +0100 Subject: [PATCH 108/127] add preconditions on intv --- Number_types/include/CGAL/boost_mp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 8159fd68d62b..1c2506d16197 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -143,6 +143,7 @@ struct Algebraic_structure_traits::digits-1 inline Interval_nt shift_positive_interval( const Interval_nt& intv, const int e ) { CGAL_assertion(intv.inf() > 0.0); From 9803e3e945b10165e298f6d7084a0ce90bbf2389 Mon Sep 17 00:00:00 2001 From: Sebastien Loriot Date: Fri, 4 Feb 2022 14:38:03 +0100 Subject: [PATCH 109/127] Update Number_types/include/CGAL/boost_mp.h Co-authored-by: Marc Glisse --- Number_types/include/CGAL/boost_mp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 1c2506d16197..889c1a2a2aad 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -150,7 +150,7 @@ namespace Boost_MP_internal { CGAL_assertion(intv.sup() > 0.0); typedef std::numeric_limits limits; - if (e < std::numeric_limits::min_exponent) + if (e < limits::min_exponent) { if ( e+std::numeric_limits::digits < std::numeric_limits::min_exponent) return CGAL::Interval_nt(0, (limits::min)()); From c62cdadcebd90cc94995ac721446e204323f34af Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 13 Apr 2022 11:38:43 +0200 Subject: [PATCH 110/127] Improve shift_positive_interval --- Number_types/include/CGAL/boost_mp.h | 212 ++------------------------- 1 file changed, 14 insertions(+), 198 deletions(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 889c1a2a2aad..d73f3723b49e 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -150,34 +150,16 @@ namespace Boost_MP_internal { CGAL_assertion(intv.sup() > 0.0); typedef std::numeric_limits limits; - if (e < limits::min_exponent) - { - if ( e+std::numeric_limits::digits < std::numeric_limits::min_exponent) - return CGAL::Interval_nt(0, (limits::min)()); - // following calls to ldexp call are exact (e+digits is larger or equal to min_exponent) - return CGAL::Interval_nt(std::ldexp(intv.inf(), e), std::ldexp(intv.sup(), e)); - } - if (e > limits::max_exponent) - return CGAL::Interval_nt((limits::max)(), limits::infinity()); // no multiplication as intv is positive - - const double scale = std::ldexp(1.0, e); // ldexp call is exact (e is less than min_exponent) - return scale * intv; + //TODO: think about strict, +-1 + if (e < std::numeric_limits::min_exponent - std::numeric_limits::digits) + return CGAL::Interval_nt(0, (limits::min)()); + if (e > limits::max_exponent - std::numeric_limits::digits) + return CGAL::Interval_nt((limits::max)(), limits::infinity()); // intv is positive + + const double scale = std::ldexp(1.0, e); // ldexp call is exact + return scale * intv; // cases that would require a rounding mode have been handled above } -/* - template - bool is_splitter_working(const T d) { - T num = d; - T den = 1.0; - while (std::ceil(num) != num) { - num *= 2.0; - den *= 2.0; - } - if (d != num / den) return false; - return true; - } -*/ - // This function checks if the computed interval is correct and if it is tight. template bool are_bounds_correct( const double l, const double u, const Type& x ) { @@ -196,16 +178,6 @@ namespace Boost_MP_internal { // CGAL_assertion(u == l || u == std::nextafter(l, +inf)); const bool are_bounds_tight = (u == l || u == std::nextafter(l, +inf)); -/* - // This check is required until a bug in double.h:split_numerator_denominator() is fixed. - // For the moment, this splitter does not handle certain limit values. - // See also: https://github.com/CGAL/cgal/issues/5982 - // E.g. it fails for d = 2.752961027411077E-308! - if (!is_splitter_working(l) || !is_splitter_working(u)) { - return are_bounds_tight; - } - CGAL_assertion(is_spliiter_working(l) && is_spliiter_working(u)); -*/ // We cannot convert inf to Type so we skip. if ( CGAL::abs(l) == inf || @@ -224,9 +196,9 @@ namespace Boost_MP_internal { template std::pair get_0ulp_interval( const int64_t shift, const ET& p ) { - CGAL_assertion(p >= 0); + CGAL_assertion(p > 0); + CGAL_assertion(msb(p) == std::numeric_limits::digits); const uint64_t pp = static_cast(p); - CGAL_assertion(pp >= 0); const double pp_dbl = static_cast(pp); const Interval_nt intv(pp_dbl, pp_dbl); @@ -237,15 +209,13 @@ namespace Boost_MP_internal { template std::pair get_1ulp_interval( const int64_t shift, const ET& p ) { - CGAL_assertion(p >= 0); + CGAL_assertion(p > 0); + CGAL_assertion(msb(p) == std::numeric_limits::digits); const uint64_t pp = static_cast(p); - const uint64_t qq = pp + 1; - CGAL_assertion(pp >= 0); - CGAL_assertion(qq > pp); + CGAL_assertion(pp > 0); const double pp_dbl = static_cast(pp); - const double qq_dbl = static_cast(qq); + const double qq_dbl = pp+1; const Interval_nt intv(pp_dbl, qq_dbl); - Protect_FPU_rounding P(CGAL_FE_UPWARD); return shift_positive_interval(intv, -static_cast(shift)).pair(); } @@ -909,160 +879,6 @@ template< > class Real_embeddable_traits< Quotient > { public: - - /* - // Option 1. - // Inspired by the one from the gmpzf type. - // Seems to be less precise and we rarely end up with an interval [d,d] - // even for numbers, which are exactly representable as double. - // Otherwise, it is quite similar to the results of the Option 3. - // It does not guarantee tight intervals! - std::pair< Interval_nt<>, int64_t > get_interval_exp( - boost::multiprecision::cpp_int& x ) const { - - CGAL_assertion(CGAL::is_positive(x)); - int64_t d = 0; - double l = 0.0, u = 0.0; - const int64_t n = static_cast(boost::multiprecision::msb(x)) + 1; - const int64_t num_dbl_digits = std::numeric_limits::digits; - - if (n > num_dbl_digits) { - d = n - num_dbl_digits; - x >>= d; - const uint64_t xx = static_cast(x); - const uint64_t yy = xx + 1; - CGAL_assertion(xx > 0 && yy > xx); - l = static_cast(xx); - u = static_cast(yy); - } else { - const uint64_t xx = static_cast(x); - CGAL_assertion(xx > 0); - l = static_cast(xx); - u = l; - } - return std::make_pair( Interval_nt<>(l, u), d ); - } - - std::pair get_interval_as_gmpzf( Type x ) const { - - CGAL_assertion_code(const Type input = x); - double l = 0.0, u = 0.0; - if (CGAL::is_zero(x.num)) { // return [0.0, 0.0] - CGAL_assertion( - Boost_MP_internal::are_bounds_correct(l, u, input)); - return std::make_pair(l, u); - } - CGAL_assertion(!CGAL::is_zero(x.num)); - CGAL_assertion(!CGAL::is_zero(x.den)); - - // Handle signs. - bool change_sign = false; - const bool is_num_pos = CGAL::is_positive(x.num); - const bool is_den_pos = CGAL::is_positive(x.den); - if (!is_num_pos && !is_den_pos) { - x.num = -x.num; - x.den = -x.den; - } else if (!is_num_pos && is_den_pos) { - change_sign = true; - x.num = -x.num; - } else if (is_num_pos && !is_den_pos) { - change_sign = true; - x.den = -x.den; - } - CGAL_assertion(CGAL::is_positive(x.num) && CGAL::is_positive(x.den)); - - const auto num = get_interval_exp(x.num); - const auto den = get_interval_exp(x.den); - - const Interval_nt<> div = num.first / den.first; - const int64_t e = num.second - den.second; - std::tie(l, u) = ldexp(div, e).pair(); - - if (change_sign) { - const double t = l; - l = -u; - u = -t; - } - - CGAL_assertion( - Boost_MP_internal::are_bounds_correct(l, u, input)); - return std::make_pair(l, u); - } */ - - /* - // Option 3. - // This one requires a temporary conversion to cpp_rational and - // it does not guarantee tight intervals! It has intervals similar to the - // intervals produced by the Option 1. - std::pair interval_from_cpp_rational( const Type& x ) const { - - // Seems fast enough because this conversion happens - // only a few times during the run, at least for NEF. - boost::multiprecision::cpp_rational rat; - CGAL_assertion(!CGAL::is_zero(x.den)); - if (CGAL::is_negative(x.den)) { - rat = boost::multiprecision::cpp_rational(-x.num, -x.den); - } else { - CGAL_assertion(CGAL::is_positive(x.den)); - rat = boost::multiprecision::cpp_rational( x.num, x.den); - } - - double l, u; - std::tie(l, u) = to_interval(rat); // fails if boost_mp is not included! - const double inf = std::numeric_limits::infinity(); - - if (l == +inf) { - l = (std::numeric_limits::max)(); - CGAL_assertion(u == +inf); - } else if (u == -inf) { - u = std::numeric_limits::lowest(); - CGAL_assertion(l == -inf); - } - - CGAL_assertion( - Boost_MP_internal::are_bounds_correct(l, u, x)); - return std::make_pair(l, u); - } - - std::pair get_interval_using_cpp_rational( const Type& x ) const { - - const double inf = std::numeric_limits::infinity(); - - const Interval_nt<> xn = Interval_nt<>(CGAL_NTS to_interval(x.num)); - if (CGAL::abs(xn.inf()) == inf || CGAL::abs(xn.sup()) == inf) { - return interval_from_cpp_rational(x); - } - CGAL_assertion(CGAL::abs(xn.inf()) != inf && CGAL::abs(xn.sup()) != inf); - - const Interval_nt<> xd = Interval_nt<>(CGAL_NTS to_interval(x.den)); - if (CGAL::abs(xd.inf()) == inf || CGAL::abs(xd.sup()) == inf) { - return interval_from_cpp_rational(x); - } - CGAL_assertion(CGAL::abs(xd.inf()) != inf && CGAL::abs(xd.sup()) != inf); - - const Interval_nt<> quot = xn / xd; - CGAL_assertion(Boost_MP_internal:: - are_bounds_correct(quot.inf(), quot.sup(), x)); - return std::make_pair(quot.inf(), quot.sup()); - } */ - - // TODO: This is a temporary implementation and - // should be replaced by the default one. The default one fails: - // For some reason, CGAL::ldexp on Interval_nt returns - // 2.752961027411077506e-308 instead of denorm_min! - // We can work it around using - - // See get_1ulp_interval() below: - // const auto res = CGAL::ldexp(intv, -static_cast(shift)).pair(); - // if (res.first == 0.0) { - // CGAL_assertion(res.second != 0.0); - // return std::make_pair(0.0, CGAL_IA_MIN_DOUBLE); - // } - // return res; - - // Or alternatively, we can use my_ldexp above. - - // Option 2. Stable one! std::pair operator()( const Type& x ) const { return Boost_MP_internal::to_interval(x.num, x.den); } From e44af4d8734a744c4e83a74183c59c9db32b332e Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 13 Apr 2022 12:35:10 +0200 Subject: [PATCH 111/127] fix+clean up --- Number_types/include/CGAL/boost_mp.h | 81 ++++++++++------------------ 1 file changed, 28 insertions(+), 53 deletions(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index d73f3723b49e..aff22a96c7ea 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -144,6 +144,7 @@ struct Algebraic_structure_traits::digits-1 + // TODO: possibly return denormals sometimes... inline Interval_nt shift_positive_interval( const Interval_nt& intv, const int e ) { CGAL_assertion(intv.inf() > 0.0); @@ -157,6 +158,7 @@ namespace Boost_MP_internal { return CGAL::Interval_nt((limits::max)(), limits::infinity()); // intv is positive const double scale = std::ldexp(1.0, e); // ldexp call is exact + // TODO: multiply directly without using intervals return scale * intv; // cases that would require a rounding mode have been handled above } @@ -166,7 +168,7 @@ namespace Boost_MP_internal { typedef std::numeric_limits limits; const double inf = std::numeric_limits::infinity(); - if ( u!=l && (u==-inf || l==inf + if ( u!=l && (l==-inf || u==inf || (u==0 && l >= -(limits::min)()) || (l==0 && u <= (limits::min)())) ) { @@ -175,48 +177,30 @@ namespace Boost_MP_internal { (x > Type(-(limits::min)()) && x < Type((limits::min)())); } -// CGAL_assertion(u == l || u == std::nextafter(l, +inf)); - const bool are_bounds_tight = (u == l || u == std::nextafter(l, +inf)); + if (!(u == l || u == std::nextafter(l, +inf))) return false; + //TODO: Type(nextafter(l,inf))>x && Type(nextafter(u,-inf)) - std::pair get_0ulp_interval( const int64_t shift, const ET& p ) { + std::pair get_0ulp_interval( const int shift, const uint64_t p ) { - CGAL_assertion(p > 0); - CGAL_assertion(msb(p) == std::numeric_limits::digits); - const uint64_t pp = static_cast(p); - const double pp_dbl = static_cast(pp); + const double pp_dbl = static_cast(p); const Interval_nt intv(pp_dbl, pp_dbl); - return shift_positive_interval(intv, -static_cast(shift)).pair(); + return shift_positive_interval(intv, -shift).pair(); } // This one returns 1 unit length interval. - template - std::pair get_1ulp_interval( const int64_t shift, const ET& p ) { - - CGAL_assertion(p > 0); - CGAL_assertion(msb(p) == std::numeric_limits::digits); - const uint64_t pp = static_cast(p); - CGAL_assertion(pp > 0); - const double pp_dbl = static_cast(pp); - const double qq_dbl = pp+1; + std::pair get_1ulp_interval( const int shift, const uint64_t p ) { + + const double pp_dbl = static_cast(p); + const double qq_dbl = pp_dbl+1; const Interval_nt intv(pp_dbl, qq_dbl); - return shift_positive_interval(intv, -static_cast(shift)).pair(); + return shift_positive_interval(intv, -shift).pair(); } // This is a version of to_interval that converts a rational type into a @@ -253,7 +237,8 @@ namespace Boost_MP_internal { const int64_t msb_num = static_cast(boost::multiprecision::msb(xnum)); const int64_t msb_den = static_cast(boost::multiprecision::msb(xden)); const int64_t msb_diff = msb_num - msb_den; - int64_t shift = num_dbl_digits - msb_diff; + int shift = static_cast(num_dbl_digits - msb_diff); + CGAL_assertion(shift == num_dbl_digits - msb_diff); if (shift > 0) { CGAL_assertion(msb_diff < num_dbl_digits); @@ -269,9 +254,13 @@ namespace Boost_MP_internal { decltype(xnum) p, r; boost::multiprecision::divide_qr(xnum, xden, p, r); const int64_t p_bits = static_cast(boost::multiprecision::msb(p)); + //CGAL_assertion(p > 0); + //CGAL_assertion(msb(p) == std::numeric_limits::digits); + //const uint64_t pp = static_cast(p); if (r == 0) { - std::tie(l, u) = get_0ulp_interval(shift, p); + CGAL_assertion(msb(p) <= num_dbl_digits); + std::tie(l, u) = get_0ulp_interval(shift, static_cast(p)); } else { CGAL_assertion(r > 0); CGAL_assertion(r < xden); @@ -284,17 +273,15 @@ namespace Boost_MP_internal { CGAL_assertion(r > 0); const int cmp = r.compare(xden); if (cmp > 0) { - ++p; - std::tie(l, u) = get_1ulp_interval(shift, p); + std::tie(l, u) = get_1ulp_interval(shift, static_cast(p) + 1); } else if (cmp == 0) { - ++p; - std::tie(l, u) = get_0ulp_interval(shift, p); + std::tie(l, u) = get_0ulp_interval(shift, static_cast(p) + 1); } else { - std::tie(l, u) = get_1ulp_interval(shift, p); + std::tie(l, u) = get_1ulp_interval(shift, static_cast(p)); } } else { - std::tie(l, u) = get_1ulp_interval(shift, p); + std::tie(l, u) = get_1ulp_interval(shift, static_cast(p)); } } @@ -329,29 +316,17 @@ namespace Boost_MP_internal { } CGAL_assertion(CGAL::is_positive(x)); - int64_t e = 0; const int64_t n = static_cast(boost::multiprecision::msb(x)) + 1; const int64_t num_dbl_digits = std::numeric_limits::digits; if (n > num_dbl_digits) { - e = n - num_dbl_digits; + int e = static_cast(n - num_dbl_digits); x >>= e; - const uint64_t xx = static_cast(x); - const uint64_t yy = xx + 1; - CGAL_assertion(xx > 0 && yy > xx); - l = static_cast(xx); - u = static_cast(yy); + std::tie(l, u) = get_1ulp_interval(-e, static_cast(x)); } else { - const uint64_t xx = static_cast(x); - CGAL_assertion(xx > 0); - l = static_cast(xx); - u = l; + l = u = static_cast(static_cast(x)); } - const Interval_nt intv(l, u); - Protect_FPU_rounding P(CGAL_FE_UPWARD); - std::tie(l, u) = CGAL::ldexp(intv, static_cast(e)).pair(); - if (change_sign) { const double t = l; l = -u; From 64d759bd5720a0b4f0709c3c8c5840d19af5f93d Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 13 Apr 2022 12:41:27 +0200 Subject: [PATCH 112/127] 0ulp case for integers --- Number_types/include/CGAL/boost_mp.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index aff22a96c7ea..c20dfbeac26e 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -320,9 +320,13 @@ namespace Boost_MP_internal { const int64_t num_dbl_digits = std::numeric_limits::digits; if (n > num_dbl_digits) { + const int64_t mindig = static_cast(boost::multiprecision::lsb(x)); int e = static_cast(n - num_dbl_digits); x >>= e; - std::tie(l, u) = get_1ulp_interval(-e, static_cast(x)); + if (n - mindig > num_dbl_digits) + std::tie(l, u) = get_1ulp_interval(-e, static_cast(x)); + else + std::tie(l, u) = get_0ulp_interval(-e, static_cast(x)); } else { l = u = static_cast(static_cast(x)); } From cf84832ffa8195f94b6adc916979ace776964282 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 13 Apr 2022 12:56:10 +0200 Subject: [PATCH 113/127] Divide to 53-54 bits instead of 52-53 so we can work only on uint64_t and don't use cpp_int anymore --- Number_types/include/CGAL/boost_mp.h | 46 ++++++++-------------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index c20dfbeac26e..ec91ed63ea8e 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -237,53 +237,31 @@ namespace Boost_MP_internal { const int64_t msb_num = static_cast(boost::multiprecision::msb(xnum)); const int64_t msb_den = static_cast(boost::multiprecision::msb(xden)); const int64_t msb_diff = msb_num - msb_den; - int shift = static_cast(num_dbl_digits - msb_diff); - CGAL_assertion(shift == num_dbl_digits - msb_diff); + // Shift so the division result has at least 53 (and at most 54) bits + int shift = static_cast(num_dbl_digits - msb_diff + 1); + CGAL_assertion(shift == num_dbl_digits - msb_diff + 1); if (shift > 0) { - CGAL_assertion(msb_diff < num_dbl_digits); xnum <<= +shift; } else if (shift < 0) { - CGAL_assertion(msb_diff > num_dbl_digits); xden <<= -shift; } - CGAL_assertion(num_dbl_digits == + CGAL_assertion(num_dbl_digits + 1 == static_cast(boost::multiprecision::msb(xnum)) - static_cast(boost::multiprecision::msb(xden))); - decltype(xnum) p, r; + ET p, r; boost::multiprecision::divide_qr(xnum, xden, p, r); + uint64_t uip = static_cast(p); const int64_t p_bits = static_cast(boost::multiprecision::msb(p)); - //CGAL_assertion(p > 0); - //CGAL_assertion(msb(p) == std::numeric_limits::digits); - //const uint64_t pp = static_cast(p); + bool exact = r.is_zero(); - if (r == 0) { - CGAL_assertion(msb(p) <= num_dbl_digits); - std::tie(l, u) = get_0ulp_interval(shift, static_cast(p)); - } else { - CGAL_assertion(r > 0); - CGAL_assertion(r < xden); - if (p_bits == num_dbl_digits - 1) { // we did not reach full precision - - p <<= 1; - r <<= 1; - ++shift; - - CGAL_assertion(r > 0); - const int cmp = r.compare(xden); - if (cmp > 0) { - std::tie(l, u) = get_1ulp_interval(shift, static_cast(p) + 1); - } else if (cmp == 0) { - std::tie(l, u) = get_0ulp_interval(shift, static_cast(p) + 1); - } else { - std::tie(l, u) = get_1ulp_interval(shift, static_cast(p)); - } - - } else { - std::tie(l, u) = get_1ulp_interval(shift, static_cast(p)); - } + if (p_bits > num_dbl_digits) { // case 54 bits + exact &= ((uip & 1) == 0); + uip>>=1; + --shift; } + std::tie(l, u) = exact ? get_0ulp_interval(shift, uip) : get_1ulp_interval(shift, uip); if (change_sign) { const double t = l; From e540545b3bba66ee755d87d5076eb99103e5278c Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 13 Apr 2022 13:08:18 +0200 Subject: [PATCH 114/127] no TABs! --- Number_types/include/CGAL/boost_mp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index ec91ed63ea8e..4387a3f47018 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -302,9 +302,9 @@ namespace Boost_MP_internal { int e = static_cast(n - num_dbl_digits); x >>= e; if (n - mindig > num_dbl_digits) - std::tie(l, u) = get_1ulp_interval(-e, static_cast(x)); + std::tie(l, u) = get_1ulp_interval(-e, static_cast(x)); else - std::tie(l, u) = get_0ulp_interval(-e, static_cast(x)); + std::tie(l, u) = get_0ulp_interval(-e, static_cast(x)); } else { l = u = static_cast(static_cast(x)); } From e1be45c3212c7121d796d855125e84527459e0e7 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 13 Apr 2022 14:20:49 +0200 Subject: [PATCH 115/127] Missing inline was a template --- Number_types/include/CGAL/boost_mp.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 4387a3f47018..e27d0533bbb2 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -186,6 +186,7 @@ namespace Boost_MP_internal { } // This one returns zero length interval that is inf = sup. + inline std::pair get_0ulp_interval( const int shift, const uint64_t p ) { const double pp_dbl = static_cast(p); @@ -195,6 +196,7 @@ namespace Boost_MP_internal { } // This one returns 1 unit length interval. + inline std::pair get_1ulp_interval( const int shift, const uint64_t p ) { const double pp_dbl = static_cast(p); From c0cfd156557f33a17d48da1f41f44d3ed3f4ca69 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 13 Apr 2022 14:46:42 +0200 Subject: [PATCH 116/127] check input exponent in pseudo-ldexp --- Number_types/include/CGAL/boost_mp.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index e27d0533bbb2..4708ad3b15fa 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -149,6 +149,22 @@ namespace Boost_MP_internal { Interval_nt shift_positive_interval( const Interval_nt& intv, const int e ) { CGAL_assertion(intv.inf() > 0.0); CGAL_assertion(intv.sup() > 0.0); + + CGAL_assertion_code( + union { +#ifdef CGAL_LITTLE_ENDIAN + struct { uint64_t man:52; uint64_t exp:11; uint64_t sig:1; } s; +#else /* CGAL_BIG_ENDIAN */ + //WARNING: untested! + struct { uint64_t sig:1; uint64_t exp:11; uint64_t man:52; } s; +#endif + double d; + } conv; + conv.d = intv.inf(); + ) + // Check that the exponent of intv.inf is 52, which corresponds to a 53 bit integer + CGAL_assertion(conv.s.exp - ((1 << (11 - 1)) - 1) == std::numeric_limits::digits - 1); + typedef std::numeric_limits limits; //TODO: think about strict, +-1 From e4c3e38b21e8b6f2273a3cc3a59442d4b59abe70 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 13 Apr 2022 15:35:53 +0200 Subject: [PATCH 117/127] confirm and test bounds for shift_positive --- Number_types/include/CGAL/boost_mp.h | 7 +-- .../Number_types/to_interval_test_boost.cpp | 44 +++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 4708ad3b15fa..347f3ee5a140 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -167,10 +167,11 @@ namespace Boost_MP_internal { typedef std::numeric_limits limits; - //TODO: think about strict, +-1 - if (e < std::numeric_limits::min_exponent - std::numeric_limits::digits) + //TODO: Add a test that fails without the -1 on the next line + // warning: min_exponent and max_exponent are 1 more than what the name suggests + if (e < limits::min_exponent - limits::digits) return CGAL::Interval_nt(0, (limits::min)()); - if (e > limits::max_exponent - std::numeric_limits::digits) + if (e > limits::max_exponent - limits::digits) return CGAL::Interval_nt((limits::max)(), limits::infinity()); // intv is positive const double scale = std::ldexp(1.0, e); // ldexp call is exact diff --git a/Number_types/test/Number_types/to_interval_test_boost.cpp b/Number_types/test/Number_types/to_interval_test_boost.cpp index 5cf577fec223..e660b6c6a4d4 100644 --- a/Number_types/test/Number_types/to_interval_test_boost.cpp +++ b/Number_types/test/Number_types/to_interval_test_boost.cpp @@ -794,9 +794,53 @@ void test_to_interval_tight_integer() { std::cout << std::endl; } +void test_shift_positive() { + { + double d = (1L << 53) - 1; + auto shift = std::numeric_limits::max_exponent - (std::numeric_limits::digits); + auto r = CGAL::Boost_MP_internal::shift_positive_interval(d,shift); + d = ldexp(d,shift); + assert(!isinf(d)); + assert(r.inf() == d && d == r.sup()); + } + { + double d = (1L << 52); + auto shift = std::numeric_limits::max_exponent - std::numeric_limits::digits + 1; + auto r = CGAL::Boost_MP_internal::shift_positive_interval(d,shift); + d = ldexp(d,shift); + assert(isinf(d)); + assert(r.inf() < d && d <= r.sup()); + } + { + double d = (1L << 53) - 1; + auto shift = std::numeric_limits::min_exponent - std::numeric_limits::digits - 1; + auto r = CGAL::Boost_MP_internal::shift_positive_interval(d,shift); + d = ldexp(d,shift); + assert(d <= (std::numeric_limits::min)()); + assert(r.inf() <= d && d <= r.sup()); + } + { + double d = (1L << 53) - 2; + auto shift = std::numeric_limits::min_exponent - std::numeric_limits::digits - 1; + auto r = CGAL::Boost_MP_internal::shift_positive_interval(d,shift); + d = ldexp(d,shift); + assert(d < (std::numeric_limits::min)()); + assert(r.inf() <= d && d <= r.sup()); + } + { + double d = (1L << 52); + auto shift = std::numeric_limits::min_exponent - std::numeric_limits::digits; + auto r = CGAL::Boost_MP_internal::shift_positive_interval(d,shift); + d = ldexp(d,shift); + assert(d == (std::numeric_limits::min)()); + assert(r.inf() == d && d == r.sup()); + } +} #endif // CGAL_USE_BOOST_MP int main() { + test_shift_positive(); + return 0; // Make sure we have the same seed. CGAL::get_default_random() = CGAL::Random(0); From 2006461dba8ad5041d72b05b6b4a384fa694672e Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 13 Apr 2022 15:41:21 +0200 Subject: [PATCH 118/127] interval -> pair --- Number_types/include/CGAL/boost_mp.h | 24 +++++++++---------- .../Number_types/to_interval_test_boost.cpp | 20 ++++++++-------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 347f3ee5a140..ccc817700dda 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -146,9 +146,9 @@ namespace Boost_MP_internal { // here we know that `intv` contains int64 numbers such that their msb is std::numeric_limits::digits-1 // TODO: possibly return denormals sometimes... inline - Interval_nt shift_positive_interval( const Interval_nt& intv, const int e ) { - CGAL_assertion(intv.inf() > 0.0); - CGAL_assertion(intv.sup() > 0.0); + std::pair shift_positive_interval( const std::pair& intv, const int e ) { + CGAL_assertion(intv.first > 0.0); + CGAL_assertion(intv.second > 0.0); CGAL_assertion_code( union { @@ -160,23 +160,21 @@ namespace Boost_MP_internal { #endif double d; } conv; - conv.d = intv.inf(); + conv.d = intv.first; ) // Check that the exponent of intv.inf is 52, which corresponds to a 53 bit integer CGAL_assertion(conv.s.exp - ((1 << (11 - 1)) - 1) == std::numeric_limits::digits - 1); typedef std::numeric_limits limits; - //TODO: Add a test that fails without the -1 on the next line // warning: min_exponent and max_exponent are 1 more than what the name suggests if (e < limits::min_exponent - limits::digits) - return CGAL::Interval_nt(0, (limits::min)()); + return {0, (limits::min)()}; if (e > limits::max_exponent - limits::digits) - return CGAL::Interval_nt((limits::max)(), limits::infinity()); // intv is positive + return {(limits::max)(), limits::infinity()}; // intv is positive const double scale = std::ldexp(1.0, e); // ldexp call is exact - // TODO: multiply directly without using intervals - return scale * intv; // cases that would require a rounding mode have been handled above + return { scale * intv.first, scale * intv.second }; // cases that would require a rounding mode have been handled above } // This function checks if the computed interval is correct and if it is tight. @@ -207,9 +205,9 @@ namespace Boost_MP_internal { std::pair get_0ulp_interval( const int shift, const uint64_t p ) { const double pp_dbl = static_cast(p); - const Interval_nt intv(pp_dbl, pp_dbl); + const std::pair intv(pp_dbl, pp_dbl); - return shift_positive_interval(intv, -shift).pair(); + return shift_positive_interval(intv, -shift); } // This one returns 1 unit length interval. @@ -218,8 +216,8 @@ namespace Boost_MP_internal { const double pp_dbl = static_cast(p); const double qq_dbl = pp_dbl+1; - const Interval_nt intv(pp_dbl, qq_dbl); - return shift_positive_interval(intv, -shift).pair(); + const std::pair intv(pp_dbl, qq_dbl); + return shift_positive_interval(intv, -shift); } // This is a version of to_interval that converts a rational type into a diff --git a/Number_types/test/Number_types/to_interval_test_boost.cpp b/Number_types/test/Number_types/to_interval_test_boost.cpp index e660b6c6a4d4..4f549f77d0ee 100644 --- a/Number_types/test/Number_types/to_interval_test_boost.cpp +++ b/Number_types/test/Number_types/to_interval_test_boost.cpp @@ -798,42 +798,42 @@ void test_shift_positive() { { double d = (1L << 53) - 1; auto shift = std::numeric_limits::max_exponent - (std::numeric_limits::digits); - auto r = CGAL::Boost_MP_internal::shift_positive_interval(d,shift); + auto r = CGAL::Boost_MP_internal::shift_positive_interval({d,d},shift); d = ldexp(d,shift); assert(!isinf(d)); - assert(r.inf() == d && d == r.sup()); + assert(r.first == d && d == r.second); } { double d = (1L << 52); auto shift = std::numeric_limits::max_exponent - std::numeric_limits::digits + 1; - auto r = CGAL::Boost_MP_internal::shift_positive_interval(d,shift); + auto r = CGAL::Boost_MP_internal::shift_positive_interval({d,d},shift); d = ldexp(d,shift); assert(isinf(d)); - assert(r.inf() < d && d <= r.sup()); + assert(r.first < d && d <= r.second); } { double d = (1L << 53) - 1; auto shift = std::numeric_limits::min_exponent - std::numeric_limits::digits - 1; - auto r = CGAL::Boost_MP_internal::shift_positive_interval(d,shift); + auto r = CGAL::Boost_MP_internal::shift_positive_interval({d,d},shift); d = ldexp(d,shift); assert(d <= (std::numeric_limits::min)()); - assert(r.inf() <= d && d <= r.sup()); + assert(r.first <= d && d <= r.second); } { double d = (1L << 53) - 2; auto shift = std::numeric_limits::min_exponent - std::numeric_limits::digits - 1; - auto r = CGAL::Boost_MP_internal::shift_positive_interval(d,shift); + auto r = CGAL::Boost_MP_internal::shift_positive_interval({d,d},shift); d = ldexp(d,shift); assert(d < (std::numeric_limits::min)()); - assert(r.inf() <= d && d <= r.sup()); + assert(r.first <= d && d <= r.second); } { double d = (1L << 52); auto shift = std::numeric_limits::min_exponent - std::numeric_limits::digits; - auto r = CGAL::Boost_MP_internal::shift_positive_interval(d,shift); + auto r = CGAL::Boost_MP_internal::shift_positive_interval({d,d},shift); d = ldexp(d,shift); assert(d == (std::numeric_limits::min)()); - assert(r.inf() == d && d == r.sup()); + assert(r.first == d && d == r.second); } } #endif // CGAL_USE_BOOST_MP From e39b2a167523f1dc90aa8d0c26b5b314adf33d17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 13 Apr 2022 17:56:11 +0200 Subject: [PATCH 119/127] remove early exit --- Number_types/test/Number_types/to_interval_test_boost.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Number_types/test/Number_types/to_interval_test_boost.cpp b/Number_types/test/Number_types/to_interval_test_boost.cpp index 4f549f77d0ee..a24a6788ff2a 100644 --- a/Number_types/test/Number_types/to_interval_test_boost.cpp +++ b/Number_types/test/Number_types/to_interval_test_boost.cpp @@ -840,7 +840,6 @@ void test_shift_positive() { int main() { test_shift_positive(); - return 0; // Make sure we have the same seed. CGAL::get_default_random() = CGAL::Random(0); From 964318d55740e11f1671dddee5ca814f52ef4e4f Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 13 Apr 2022 16:27:10 +0200 Subject: [PATCH 120/127] special case when den is a power of 2 --- Number_types/include/CGAL/boost_mp.h | 35 ++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index ccc817700dda..84ba62494918 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -220,6 +220,9 @@ namespace Boost_MP_internal { return shift_positive_interval(intv, -shift); } + template + std::pair to_interval( ET x, int extra_shift = 0 ); + // This is a version of to_interval that converts a rational type into a // double tight interval. template @@ -253,6 +256,27 @@ namespace Boost_MP_internal { const int64_t num_dbl_digits = std::numeric_limits::digits - 1; const int64_t msb_num = static_cast(boost::multiprecision::msb(xnum)); const int64_t msb_den = static_cast(boost::multiprecision::msb(xden)); + + // An alternative strategy would be to convert numerator and denominator to + // intervals, then divide. However, this would require setting the rounding + // mode (and dividing intervals is not completely free). An important + // special case is when the rational is exactly equal to a double + // (fit_in_double). Then the denominator is a power of 2, so we can skip + // the division and it becomes unnecessary to set the rounding mode, we + // just need to modify the exponent correction for the denominator. + if(msb_den == lsb(xden)) { + std::tie(l,u)=to_interval(xnum, msb_den); + if (change_sign) { + const double t = l; + l = -u; + u = -t; + } + + CGAL_assertion(are_bounds_correct(l, u, input)); + return std::make_pair(l, u); + } + + const int64_t msb_diff = msb_num - msb_den; // Shift so the division result has at least 53 (and at most 54) bits int shift = static_cast(num_dbl_digits - msb_diff + 1); @@ -293,7 +317,7 @@ namespace Boost_MP_internal { // This is a version of to_interval that converts an integer type into a // double tight interval. template - std::pair to_interval( ET x ) { + std::pair to_interval( ET x, int extra_shift) { CGAL_assertion_code(const ET input = x); double l = 0.0, u = 0.0; @@ -319,11 +343,12 @@ namespace Boost_MP_internal { int e = static_cast(n - num_dbl_digits); x >>= e; if (n - mindig > num_dbl_digits) - std::tie(l, u) = get_1ulp_interval(-e, static_cast(x)); + std::tie(l, u) = get_1ulp_interval(-e+extra_shift, static_cast(x)); else - std::tie(l, u) = get_0ulp_interval(-e, static_cast(x)); + std::tie(l, u) = get_0ulp_interval(-e+extra_shift, static_cast(x)); } else { - l = u = static_cast(static_cast(x)); + // if extra_shift != 0 .... + l = u = std::ldexp(static_cast(static_cast(x)),-(int)extra_shift); } if (change_sign) { @@ -332,7 +357,7 @@ namespace Boost_MP_internal { u = -t; } - CGAL_assertion(are_bounds_correct(l, u, input)); + CGAL_assertion(extra_shift != 0 || are_bounds_correct(l, u, input)); return std::make_pair(l, u); } From 67be52d2b42fa9414e1bd6f260c15b1a4a2ac880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 13 Apr 2022 18:40:59 +0200 Subject: [PATCH 121/127] small clean-up --- Number_types/include/CGAL/boost_mp.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 84ba62494918..bc1d07358805 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -264,16 +264,14 @@ namespace Boost_MP_internal { // (fit_in_double). Then the denominator is a power of 2, so we can skip // the division and it becomes unnecessary to set the rounding mode, we // just need to modify the exponent correction for the denominator. - if(msb_den == lsb(xden)) { + if(msb_den == static_cast(lsb(xden))) { std::tie(l,u)=to_interval(xnum, msb_den); if (change_sign) { - const double t = l; - l = -u; - u = -t; + CGAL_assertion(are_bounds_correct(-u, -l, input)); + return {-u, -l}; } - CGAL_assertion(are_bounds_correct(l, u, input)); - return std::make_pair(l, u); + return {u, l}; } @@ -347,8 +345,8 @@ namespace Boost_MP_internal { else std::tie(l, u) = get_0ulp_interval(-e+extra_shift, static_cast(x)); } else { - // if extra_shift != 0 .... - l = u = std::ldexp(static_cast(static_cast(x)),-(int)extra_shift); + l = u = extra_shift==0 ? static_cast(static_cast(x)) + : std::ldexp(static_cast(static_cast(x)),-extra_shift); } if (change_sign) { From dad68d526230034638a59a074eabb1dea7252946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 13 Apr 2022 20:51:36 +0200 Subject: [PATCH 122/127] disable code portion that should be benchmarked --- Number_types/include/CGAL/boost_mp.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index bc1d07358805..6a0bf814d4d2 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -257,6 +257,7 @@ namespace Boost_MP_internal { const int64_t msb_num = static_cast(boost::multiprecision::msb(xnum)); const int64_t msb_den = static_cast(boost::multiprecision::msb(xden)); +#if 0 // Optimisation for the case of input that are double // An alternative strategy would be to convert numerator and denominator to // intervals, then divide. However, this would require setting the rounding // mode (and dividing intervals is not completely free). An important @@ -273,7 +274,7 @@ namespace Boost_MP_internal { CGAL_assertion(are_bounds_correct(l, u, input)); return {u, l}; } - +#endif const int64_t msb_diff = msb_num - msb_den; // Shift so the division result has at least 53 (and at most 54) bits From 80cd926cefac4d8b8903f7ba43288c183cb17658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 18 Apr 2022 20:40:39 +0200 Subject: [PATCH 123/127] test is conditional --- Number_types/test/Number_types/to_interval_test_boost.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Number_types/test/Number_types/to_interval_test_boost.cpp b/Number_types/test/Number_types/to_interval_test_boost.cpp index a24a6788ff2a..d3ea2435330b 100644 --- a/Number_types/test/Number_types/to_interval_test_boost.cpp +++ b/Number_types/test/Number_types/to_interval_test_boost.cpp @@ -839,7 +839,9 @@ void test_shift_positive() { #endif // CGAL_USE_BOOST_MP int main() { +#ifdef CGAL_USE_BOOST_MP test_shift_positive(); +#endif // Make sure we have the same seed. CGAL::get_default_random() = CGAL::Random(0); From 464e23bbb3da9bc41a77597a6b694ee016410a9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 20 Apr 2022 07:19:01 +0200 Subject: [PATCH 124/127] update bounds as it is not deterministic accross platforms --- Number_types/test/Number_types/to_interval_test_boost.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Number_types/test/Number_types/to_interval_test_boost.cpp b/Number_types/test/Number_types/to_interval_test_boost.cpp index d3ea2435330b..a317155e0796 100644 --- a/Number_types/test/Number_types/to_interval_test_boost.cpp +++ b/Number_types/test/Number_types/to_interval_test_boost.cpp @@ -808,8 +808,8 @@ void test_shift_positive() { auto shift = std::numeric_limits::max_exponent - std::numeric_limits::digits + 1; auto r = CGAL::Boost_MP_internal::shift_positive_interval({d,d},shift); d = ldexp(d,shift); - assert(isinf(d)); - assert(r.first < d && d <= r.second); + assert(d >= (std::numeric_limits::max)()); + assert(r.first <= d && d <= r.second); } { double d = (1L << 53) - 1; From cc5f54fec99ba58469d145127fc53abf287000db Mon Sep 17 00:00:00 2001 From: Sebastien Loriot Date: Mon, 25 Apr 2022 21:55:12 +0200 Subject: [PATCH 125/127] Update Number_types/test/Number_types/to_interval_test_boost.cpp Co-authored-by: Marc Glisse --- Number_types/test/Number_types/to_interval_test_boost.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Number_types/test/Number_types/to_interval_test_boost.cpp b/Number_types/test/Number_types/to_interval_test_boost.cpp index a317155e0796..01863799427b 100644 --- a/Number_types/test/Number_types/to_interval_test_boost.cpp +++ b/Number_types/test/Number_types/to_interval_test_boost.cpp @@ -796,7 +796,7 @@ void test_to_interval_tight_integer() { void test_shift_positive() { { - double d = (1L << 53) - 1; + double d = (1LL << 53) - 1; auto shift = std::numeric_limits::max_exponent - (std::numeric_limits::digits); auto r = CGAL::Boost_MP_internal::shift_positive_interval({d,d},shift); d = ldexp(d,shift); From 7e987e50fb55a72918c562243f1a34d59cb8623b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 26 Apr 2022 11:15:46 +0200 Subject: [PATCH 126/127] more fixes for 32bit platforms --- Number_types/test/Number_types/to_interval_test_boost.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Number_types/test/Number_types/to_interval_test_boost.cpp b/Number_types/test/Number_types/to_interval_test_boost.cpp index 01863799427b..3c8355b68688 100644 --- a/Number_types/test/Number_types/to_interval_test_boost.cpp +++ b/Number_types/test/Number_types/to_interval_test_boost.cpp @@ -804,7 +804,7 @@ void test_shift_positive() { assert(r.first == d && d == r.second); } { - double d = (1L << 52); + double d = (1LL << 52); auto shift = std::numeric_limits::max_exponent - std::numeric_limits::digits + 1; auto r = CGAL::Boost_MP_internal::shift_positive_interval({d,d},shift); d = ldexp(d,shift); @@ -812,7 +812,7 @@ void test_shift_positive() { assert(r.first <= d && d <= r.second); } { - double d = (1L << 53) - 1; + double d = (1LL << 53) - 1; auto shift = std::numeric_limits::min_exponent - std::numeric_limits::digits - 1; auto r = CGAL::Boost_MP_internal::shift_positive_interval({d,d},shift); d = ldexp(d,shift); @@ -820,7 +820,7 @@ void test_shift_positive() { assert(r.first <= d && d <= r.second); } { - double d = (1L << 53) - 2; + double d = (1LL << 53) - 2; auto shift = std::numeric_limits::min_exponent - std::numeric_limits::digits - 1; auto r = CGAL::Boost_MP_internal::shift_positive_interval({d,d},shift); d = ldexp(d,shift); @@ -828,7 +828,7 @@ void test_shift_positive() { assert(r.first <= d && d <= r.second); } { - double d = (1L << 52); + double d = (1LL << 52); auto shift = std::numeric_limits::min_exponent - std::numeric_limits::digits; auto r = CGAL::Boost_MP_internal::shift_positive_interval({d,d},shift); d = ldexp(d,shift); From 4bd7049f2f88e89e657e95358157bf2d003185f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 3 May 2022 12:14:50 +0200 Subject: [PATCH 127/127] test boost_mp before 5.5-beta1 is out --- Number_types/include/CGAL/Exact_integer.h | 9 +++++---- .../CGAL/Number_types/internal/Exact_type_selector.h | 10 ++++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Number_types/include/CGAL/Exact_integer.h b/Number_types/include/CGAL/Exact_integer.h index a55a63b20649..5e9c1910ca3c 100644 --- a/Number_types/include/CGAL/Exact_integer.h +++ b/Number_types/include/CGAL/Exact_integer.h @@ -50,10 +50,11 @@ typedef unspecified_type Exact_integer; #else // not DOXYGEN_RUNNING -#if BOOST_VERSION > 107800 && defined(CGAL_USE_BOOST_MP) -// TODO: That is used for testing, it must be removed when merging into master. +#if ( (defined(CGAL_TEST_SUITE) && CGAL_VERSION_NR == 1050500900) || defined(CGAL_FORCE_USE_BOOST_MP))\ + && BOOST_VERSION > 107800 && defined(CGAL_USE_BOOST_MP) +// use boost-mp by default in the testsuite until 5.5-beta is out typedef BOOST_cpp_arithmetic_kernel::Integer Exact_integer; -#else // BOOST_VERSION <= 107800 +#else // BOOST_VERSION > 107800 #ifdef CGAL_USE_GMPXX typedef mpz_class Exact_integer; #elif defined(CGAL_USE_GMP) @@ -71,7 +72,7 @@ typedef CORE::BigInt Exact_integer; #else #error "ERROR: Cannot determine a BigInt type!" #endif // CGAL_USE_CORE -#endif // BOOST_VERSION <= 107800 +#endif // BOOST_VERSION > 107800 #endif // not DOXYGEN_RUNNING diff --git a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h index 54abcab97473..6972c6f29d1a 100644 --- a/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h +++ b/Number_types/include/CGAL/Number_types/internal/Exact_type_selector.h @@ -55,10 +55,12 @@ namespace CGAL { namespace internal { template < typename > struct Exact_field_selector -#if BOOST_VERSION > 107800 && defined(CGAL_USE_BOOST_MP) -// TODO: That is used for testing, it must be removed when merging into master. +#if ( (defined(CGAL_TEST_SUITE) && CGAL_VERSION_NR == 1050500900) || defined(CGAL_FORCE_USE_BOOST_MP))\ + && BOOST_VERSION > 107800 && defined(CGAL_USE_BOOST_MP) +// use boost-mp by default in the testsuite until 5.5-beta is out +// Boost { typedef BOOST_cpp_arithmetic_kernel::Rational Type; }; -#else // BOOST_VERSION <= 107800 +#else // BOOST_VERSION > 107800 #ifdef CGAL_USE_GMPXX { typedef mpq_class Type; }; #elif defined(CGAL_USE_GMP) @@ -84,7 +86,7 @@ struct Exact_field_selector #else { typedef Quotient Type; }; #endif -#endif // BOOST_VERSION <= 107800 +#endif // BOOST_VERSION > 107800 // By default, a field is a safe choice of ring. template < typename T >