higher precision floating point using boost lib (higher then 16 digits) - c++

I am running a simulation of physical experiments, so I need really high floating point precision (more than 16 digits). I use Boost.Multiprecision, however I can't get a precision higher than 16 digits, no matter what I tried. I run the simulation with C++ and eclipse compiler, for example:
#include <boost/math/constants/constants.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>
#include <limits>
using boost::multiprecision::cpp_dec_float_50;
void main()
{
cpp_dec_float_50 my_num= cpp_dec_float_50(0.123456789123456789123456789);
std::cout.precision(std::numeric_limits<cpp_dec_float_50>::digits10);
std::cout << my_num << std::endl;
}
The output is:
0.12345678912345678379658409085095627233386039733887
^
But it should be:
0.123456789123456789123456789
As you can see, after 16 digits it is incorrect. Why?

Your issue is here:
cpp_dec_float_50 my_num = cpp_dec_float_50(0.123456789123456789123456789);
^ // This number is a double!
The compiler does not use arbitrary-precision floating point literals, and instead uses IEEE-754 doubles, which have finite precision. In this case, the closest double to the number you have written is:
0.1234567891234567837965840908509562723338603973388671875
And printing it to the 50th decimal does indeed give the output you are observing.
What you want is to construct your arbitrary-precision float from a string instead (demo):
#include <boost/math/constants/constants.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>
#include <limits>
using boost::multiprecision::cpp_dec_float_50;
int main() {
cpp_dec_float_50 my_num = cpp_dec_float_50("0.123456789123456789123456789");
std::cout.precision(std::numeric_limits<cpp_dec_float_50>::digits10);
std::cout << my_num << std::endl;
}
Output:
0.123456789123456789123456789

The problem is that the C++ compiler converts numbers to doubles when compiling (I also learned this a while ago). You have to use special functions to handle more decimal points. See the Boost documentation or other answers here on SO for examples.
That said, it is almost impossible that there would be any real need for such high precision. If you are loosing precision you should consider other floating point algorithms instead of blindly increasing the number of decimals.

Related

boost int 128 division to floating point number

I am new in boost. I have 128 bit integer (int128_t boost/multiprecision/cpp_int.hpp) in my project, which I need to divide to floating point number. In my current platform I have limitation and can't use boost/multiprecision/float128.hpp. It's still not supported in clang now https://github.com/boostorg/math/issues/181
Is there any way to this with boost math lib?
Although you can't use float128, Boost has several other implementations of long floating-point types:
cpp_bin_float
cpp_dec_float
gmp_float
mpfr_float
In particular, if you need binary high-precision floating-point type without dependencies on external libraries like GMP, you can use cpp_bin_float. Example:
#include <iomanip>
#include <iostream>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_bin_float.hpp>
int main()
{
using LongFloat=boost::multiprecision::cpp_bin_float_quad;
const auto x=boost::multiprecision::int128_t(1234123521);
const auto y=LongFloat(34532.52346246234);
const auto z=LongFloat(x)/y;
std::cout << "Ratio: " << std::setprecision(10) << z << "\n";
}
Here we've used a built-in typedef for 113-bit floating-point number, which has the same precision and range as IEEE 754 binary128. You can choose other parameters for the precision and range, see the docs I've linked to above for details.
Note though, that int128_t has more precision than any kind of float128, because some bits of the latter are used to store its exponent. If that's an issue, be sure to use higher precision.
Perhaps split the int128 into 64-bit numbers?
i128 = h64 * (1<<64) + l64
Then you could easily load those values shift and sum them on the 64bit floating point to get the equivalent number.
Or, as the floating point hardware is actually only 64 bit precision anyway, you could just shift down your int128 until it fits in 64 bit, cast that to float and then shift it back up, but the former may actually be faster because it is simpler.

C++: boost multiprecision printing [duplicate]

I am running a simulation of physical experiments, so I need really high floating point precision (more than 16 digits). I use Boost.Multiprecision, however I can't get a precision higher than 16 digits, no matter what I tried. I run the simulation with C++ and eclipse compiler, for example:
#include <boost/math/constants/constants.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>
#include <limits>
using boost::multiprecision::cpp_dec_float_50;
void main()
{
cpp_dec_float_50 my_num= cpp_dec_float_50(0.123456789123456789123456789);
std::cout.precision(std::numeric_limits<cpp_dec_float_50>::digits10);
std::cout << my_num << std::endl;
}
The output is:
0.12345678912345678379658409085095627233386039733887
^
But it should be:
0.123456789123456789123456789
As you can see, after 16 digits it is incorrect. Why?
Your issue is here:
cpp_dec_float_50 my_num = cpp_dec_float_50(0.123456789123456789123456789);
^ // This number is a double!
The compiler does not use arbitrary-precision floating point literals, and instead uses IEEE-754 doubles, which have finite precision. In this case, the closest double to the number you have written is:
0.1234567891234567837965840908509562723338603973388671875
And printing it to the 50th decimal does indeed give the output you are observing.
What you want is to construct your arbitrary-precision float from a string instead (demo):
#include <boost/math/constants/constants.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>
#include <limits>
using boost::multiprecision::cpp_dec_float_50;
int main() {
cpp_dec_float_50 my_num = cpp_dec_float_50("0.123456789123456789123456789");
std::cout.precision(std::numeric_limits<cpp_dec_float_50>::digits10);
std::cout << my_num << std::endl;
}
Output:
0.123456789123456789123456789
The problem is that the C++ compiler converts numbers to doubles when compiling (I also learned this a while ago). You have to use special functions to handle more decimal points. See the Boost documentation or other answers here on SO for examples.
That said, it is almost impossible that there would be any real need for such high precision. If you are loosing precision you should consider other floating point algorithms instead of blindly increasing the number of decimals.

Loss of precision while working with double

Could we work with big numbers up to 10^308.
How can I calculate the 11^105 using just double?
The answer of (11^105) is:
22193813979407164354224423199022080924541468040973950575246733562521125229836087036788826138225193142654907051
Is it possible to get the correct result of 11^105?
As I know double can handle 10^308 which is much bigger than 11^105.
I know that this code is wrong:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <iomanip>
using namespace std;
int main()
{
double n, p, x;
cin >> n >> p;
//scanf("%lf %lf", &n,&p);
x = exp(log((double)n)*p);
//printf("%lf\n", x);
cout << x <<endl;
return 0;
}
Thanks.
double usually has 11bit for exp (-1022~1023 normalized), 52bit for fact and 1bit for sign. Thus 11^105 cannot be represented accurately.
For more explanation, see IEEE 754 on Wikipedia
Double can hold very large results, but not high precision. In constrast to fixed point numbers, double is floating point real number. This means, for the same accuracy double can shift the radix to handle different range of number and thus you see high range.
For your purpose, you need some home cooked big num library, or you can find one readily available and written by someone else.
BTW my home cooked recipe gives different answer for 11105
Confirmed with this haskell code

c++ precision issue in storing floating point numbers

I'm handling some mathematical calculation.
I'm losing precision. But i need extreme precision.
I then used to check the precision issue with the code given below.
Any solution for getting the precision?
#include <iostream>
#include <stdlib.h>
#include <cstdio>
#include <sstream>
#include <iomanip>
using namespace std;
int main(int argc,char** arvx)
{
float f = 1.00000001;
cout << "f: " <<std::setprecision(20)<< f <<endl;
return 0;
}
Output is
f: 1
If you truly want precise representation of these sorts of numbers (ie, with very small fractional components many places beyond the decimal point), then floating point types like float or even the much more precise double may still not give you the exact results you are looking for in all circumstances. Floating point types can only approximate some values with small fractional components.
You may need to use some sort of high precision fixed point C++ type in order to get exact representation of very small fractions in your values, and resulting accurate calculated results when you perform mathematical operations on such numbers. The following question/answers may provide you with some useful pointers: C++ fixed point library?
in c++
float f = 1.00000001;
support only 6 digits after decimal point
float f = 1.000001;
if you want more real calculation use double

Using a long double or just a double for calculating pi?

I'm calculating pi using a long winded formula. I'm trying to get more familiar with floating point numbers etc. I have a working program that uses doubles. The problem with my code is:
If I use a double, pi is only accurate to the 7th decimal place. I can't get it to be any more accurate.
If I use a long double, pi is accurate up to the 9th decimal place however the code takes much longer to run. If I check for precision for less than 0.00000001 using a long double, pi returns a value of 9.4246775. I assume that this is due to the long double.
My question is what is the most accurate variable type? How could I change my code to improve the precision of pi?
Here is my code:
#include <iomanip>
#include <cstdlib>
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
double arctan;
double pi;
double precision;
double previous=0;
int y=3;
int loopcount=0;
cout<<"Start\n";
arctan=1-(pow(1,y)/y);
do
{
y=y+2;
arctan=arctan+(pow(1,y)/y);
y=y+2;
arctan=arctan-(pow(1,y)/y);
pi=4*(arctan);
// cout<<"Pi is: ";
// cout<<setprecision(12)<<pi<<endl;
precision=(pi*(pow(10,10)/10));
loopcount++;
if(precision-previous<0.000000001)
break;
previous=precision;
}
while(true);
cout<<"Pi is:"<<endl;
cout<<setprecision(11)<<pi<<endl;
cout<<"Times looped:"<<endl;
cout<<loopcount<<endl;
return 0;
}
You can get the max limits of doubles/long doubles from std::numeric_limits
#include <iostream>
#include <limits>
int main()
{
std::cout << " Double::digits10: " << std::numeric_limits<double>::digits10 << "\n";
std::cout << "Long Double::digits10: " << std::numeric_limits<long double>::digits10 << "\n";
}
On my machine this gives:
Double::digits10: 15
Long Double::digits10: 18
So I expect long double to be accurate to 18 digits.
The definition of this term can be found here:
http://www.cplusplus.com/reference/std/limits/numeric_limits/
Standard quote: 18.3.2 Numeric limits [limits]
Also Note: As the comment is way down in the above list:
That #sarnold is incorrect (though mysteriously he has two silly people up-voting his comment without checking) in his assertions on pow(). What he states is only applicable to C. C++ has overloads for the types because in C++ pow() is a template function. See: http://www.cplusplus.com/reference/clibrary/cmath/pow/ in the standard at 26.4.7 complex value operations [complex.value.ops]
The predefined floating-point type with the greatest precision is long double.
There are three predefined floating-point types:
float has at least 6 decimal digits of precision
double has at least 10, and at least as many as float
long double has at least 10, and at least as many as double
These are minimum requirements; any or all of these types could have more precision.
If you need more precision than long double can provide, you might look at GMP, which supports arbitrary precision (at considerable expense in speed and memory usage).
Or, you could just hard-code the digits of PI and see what happens. ^_^
http://www.joyofpi.com/pi.html