[GiNaC-list] Floating to Rational
Vladimir V. Kisil
V.Kisil at leeds.ac.uk
Wed Jul 19 16:50:35 CEST 2023
>>>>> On Wed, 19 Jul 2023 10:42:35 +0100, "Vladimir V. Kisil" <V.Kisil at leeds.ac.uk> said:
VVK> Yes, see the code below as an example.
It is easy to see that rationalize function from CLN produces huge
fractions due to floating point errors. I am including a second method
based on the continued fraction approximations. Its behaviour can be
adjusted through parameters tolerance and cf_size.
--
Vladimir V. Kisil http://www1.maths.leeds.ac.uk/~kisilv/
Book: Geometry of Mobius Maps https://doi.org/10.1142/p835
Soft: Geometry of cycles http://moebinv.sourceforge.net/
Jupyter notebooks: https://github.com/vvkisil?tab=repositories
#include <iostream>
#include <ginac/ginac.h>
#include <math.h>
using namespace std;
using namespace GiNaC;
int tolerance = 1E6;
int cf_size = 15;
numeric rationalize(numeric x) {
if (ex_to<numeric>(x).is_rational())
return x;
x = ex_to<numeric>(evalf(x));
int sign = (x.is_positive() ? +1 : -1);
double xf= abs(x.to_double());
lst coeff = lst{};
for (int i = 0; i < cf_size; ++i ) {
if ( xf > tolerance )
break;
else {
int base = floor(xf);
coeff.append(numeric(base));
if (xf - base == 0)
break;
xf = 1/(xf-base);
}
}
lst::const_reverse_iterator i = coeff.rbegin();
numeric res = ex_to<numeric>(*i);
++i;
while ( i != coeff.rend()) {
res = ex_to<numeric>(*i) + 1/res;
++i;
}
return sign*res;
}
struct map_rationalize_ex : public map_function {
ex operator()(const ex &e)
{
if (is_a<numeric>(e))
return rationalize(ex_to<numeric>(e).real()) + I * rationalize(ex_to<numeric>(e).imag());
else if (e.nops() > 0)
return e.map(*this);
else
return e;
}
};
int main()
{
symbol x("x"), y("y");
ex e = 0.5*sin((-.6+I*.3)*x +exp((.25-I*.8)*y+.3333-I*numeric(1,7)))+pow(.4*x, .6);
map_rationalize_ex rationalize_ex;
cout << e << endl << "is rationalised to" << endl << rationalize_ex(e) << endl;
return 0;
}
More information about the GiNaC-list
mailing list