My basic aim was to subtract two supposed to be equivalent float.
Consider this:-
float x=1;
float a=x/30-x/40;
float b=x/30;
b-=x/40;
std::cout<<a-b<<std::endl;
I should have got zero. But I didn't. Instead I got a very small number of around 10^(-10).
Now, there were two options:-
First, I thought of using rational expressions instead of fractions (that is deal with numerators and denominators) and then convert the final rational expression into fraction. I did this via Boost.rational. I used cpp_int to store the numerators and denominators since the numerators and denominators could get huge. It works fine. But the problem is that program which I'm making is taking a lot of time. I think that is because of having to deal with huge integers.
Secondly, I was advised to try fixed point arithmetic. I'm not very good at it. So, I'm not sure if fixed point arithmetic would give correct answer either? What I was thinking was this->
Suppose I want the result of my subtraction correct upto the 50th precision. So I get 50 digits to the left of decimal point by multiplying it with appropriate power of 10. Drop the fractional part and convert it into cpp_int. I do this with both the floats. And then perform subtraction on these cpp_int.
Two problems:-
First, I am unable to convert cpp_float_dec_50 to cpp_int. Boost does not allow this kind of (lossy) conversion directly.
Second, I'm just not confident on this approach working at all.
So, finally two questions:-
How to convert cpp_float_dec_50 to cpp_int?
What kind of approach would be the best two subtract two floats in the context presented so far in the question?
Thanks. And sorry if any of this comes across as highly noobish or stupid question.
I'm still learning.
you need to decide whether you want an exact representation or not. if 10^-10 is too much of an error, you might want exactness after all. i can say that fixed point representation is no better than the built-in types per se; if you extend its precision and capabilities, you arrive at a multiprecision library :).
i can recommend boost::multiprecision, and have found it fairly straightforward, though because it is a boost template lib, it takes some extra effort to hunt down compiler errors. number conversions just work, though of course there is no 'free lunch'; your results are just as easy to mess up as built-in numbers if used wrong.
things to keep in mind:
- performance is a function of precision. keep it under control!
- measure your precision over time. repeated multiplication, for example, will likely add precision without bound. eliminate unnecessary transformations in your math.
- many functions (e.g. trig, log, exp, ...) aren't implemented for rationals. you can only step around such math so carefully before you need to give up and accept controlled error (by using a floating point type).
- you may separate your program according to its precision requirements. for example when rendering in 2D, transform to view space (-1..1), then you can truncate values into floating point and operate with nice speed.
- boost::multiprecision has many backends that improve performance (though they will not fix mistakes in control of precision)
i use the following definitions for my boost mp types. in my case, i found turning expression templates off to be faster.
namespace mp = boost::multiprecision;
typedef mp::number<mp::cpp_int_backend<>, mp::et_off> int_mp;
typedef mp::number<mp::cpp_rational_backend, mp::et_off> rational_mp;
typedef mp::number<mp::cpp_dec_float<0>, mp::et_off> float_mp; // 0 means 'unlimited'