I'm trying to get familiar with CGAL's exact number types and in the process, I'm trying to implement a function to compute the floating-point remainder of the division of two exact numbers (like std::fmod()
). However, I'm wondering how to do any arithmetic with exact numbers outside of the trivial operator+
, -
, *
, /
. After searching the documentation for a while I found CGAL::div()
and CGAL::mod()
, but these don't work (return CGAL::Null_tag
?) seemingly because they are defined for EuclideanRing
s only. Example code:
#include <iostream>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
using Kernel = CGAL::Exact_predicates_exact_constructions_kernel;
using Number = Kernel::FT;
int main() {
Number a(2.5);
Number b(1.5);
std::cout << CGAL::div(a, b) << "\n"; // error
}
Compile error:
/tmp/cgal-test/test.cpp: In function ‘int main()’:
/tmp/cgal-test/test.cpp:9:15: error: no match for ‘operator<<’ (operand types are ‘std::ostream’ {aka ‘std::basic_ostream<char>’} and ‘CGAL::Null_functor::result_type’ {aka ‘CGAL::Null_tag’})
9 | std::cout << CGAL::div(a, b) << "\n"; // error
| ~~~~~~~~~ ^~ ~~~~~~~~~~~~~~~
| | |
| | CGAL::Null_functor::result_type {aka CGAL::Null_tag}
| std::ostream {aka std::basic_ostream<char>}
Of course, a simple solution to compute a floating-point remainder would be to use CGAL::to_double()
and compute std::fmod()
on the results, but this may lose precision or overflow, so this would negate the benefits of using an exact number type in the first place. Another way is to do repeated subtraction, but this blows up the running time if a
is big and b
is small.
Could someone explain (or point me to relevant documentation explaining) what the intended way is to implement operations like this in an exact fashion?
Your code compiles for me, but it prints 1.66667
while I expect you wanted 1
? I do get a similar error if I define CGAL_USE_GMPXX=1
or CGAL_DO_NOT_USE_BOOST_MP=1
, so the error depends on the type used internally for exact rationals. There is also a function integral_division
.
The simplest way I can think of it to compute a/b
and convert it to an exact integer type: CGAL::Exact_integer(CGAL::exact(a/b))
(using <CGAL/Exact_integer.h>
, although there may be a cleaner way to get the integer type that corresponds to this rational type, possibly with Get_arithmetic_kernel
). Maybe the conversion could be done with NT_converter
or Coercion_traits
... Anyway, the direction in which this rounds may depend on the number type, so you should check the sign you get and possibly correct the quotient by 1.
Number q(CGAL::Exact_integer(CGAL::exact(a/b)));
std::cout << q << ' ' << (a-b*q) << '\n';
We never needed this kind of operation on rationals, which explains why we didn't implement it in CGAL.