What is the correct way to initialize GMP floating point variables (mpf_t or mpf_class, does not matter) from double?
Code:
#include <iostream>
#include <gmpxx.h>
int main()
{
double d=0.1;
//1024 bits is more that 300 decimal digits
mpf_set_default_prec(1024);
mpf_class m(d);
//after initializing mpf_class variable, set default output precision
std::cout.precision(50);
std::cout.setf(std::ios_base::scientific);
std::cout << m << std::endl;
return 0;
}
The output is:
1.00000000000000005551115123125782702118158340454102e-01
It would be okay, if I printed d directly, but in the m variable 300 decimal digits of mantissa are trusted! I use GMP for an iterative numerical method, so these non-zeros introduce mistake and make the method converge slowly.
If I initilize m as mpf_class m("0.1");, the output is:
1.00000000000000000000000000000000000000000000000000e-01
So the problem is not in operator<< overload for mpf_class. The problem exists not only for initializing, but for assigning too.
At present I use the following:
mpf_class linsys::DtoGMP(const double& arg)
{
char buf[512];
sprintf(buf,"%.15le\n",arg);
return mpf_class(buf);
}
for correct conversion.
Is there a faster and/or more native way to do it?
My OS is OpenSUSE 12.1, compiler: gcc 4.6.2
If you print out the double with that same precision, you should see the same strange-looking number. That's simply because 0.1 can't be accurately represented in floating point. The mpf_class is accurately reproducing the value stored in the double. It's the double that isn't matching your expectations.
There's probably a way to specify a precision to gmp or some way to round the input. I'm not sure where to look though.
Edit
mpf_class has a constructor with a precision parameter: http://www.gnu.org/software/gmp/manual/html_node/C---Interface-Floats.html
You may use this method
mpf_class a;
double d=0.1;
a=static_cast<mpf_class>(d*10)/static_cast<mpf_class>(10);
this method can be used if you know how many decimal places a double has
Related
Consider the following piece of code:
#include <iostream>
#include <cmath>
int main() {
int i = 23;
int j = 1;
int base = 10;
int k = 2;
i += j * pow(base, k);
std::cout << i << std::endl;
}
It outputs "122" instead of "123". Is it a bug in g++ 4.7.2 (MinGW, Windows XP)?
std::pow() works with floating point numbers, which do not have infinite precision, and probably the implementation of the Standard Library you are using implements pow() in a (poor) way that makes this lack of infinite precision become relevant.
However, you could easily define your own version that works with integers. In C++11, you can even make it constexpr (so that the result could be computed at compile-time when possible):
constexpr int int_pow(int b, int e)
{
return (e == 0) ? 1 : b * int_pow(b, e - 1);
}
Here is a live example.
Tail-recursive form (credits to Dan Nissenbaum):
constexpr int int_pow(int b, int e, int res = 1)
{
return (e == 0) ? res : int_pow(b, e - 1, b * res);
}
All the other answers so far miss or dance around the one and only problem in the question:
The pow in your C++ implementation is poor quality. It returns an inaccurate answer when there is no need to.
Get a better C++ implementation, or at least replace the math functions in it. The one pointed to by Pascal Cuoq is good.
Not with mine at least:
$ g++ --version | head -1
g++ (GCC) 4.7.2 20120921 (Red Hat 4.7.2-2)
$ ./a.out
123
IDEone is also running version 4.7.2 and gives 123.
Signatures of pow() from http://www.cplusplus.com/reference/cmath/pow/
double pow ( double base, double exponent );
long double pow ( long double base, long double exponent );
float pow ( float base, float exponent );
double pow ( double base, int exponent );
long double pow ( long double base, int exponent );
You should set double base = 10.0; and double i = 23.0.
If you simply write
#include <iostream>
#include <cmath>
int main() {
int i = 23;
int j = 1;
int base = 10;
int k = 2;
i += j * pow(base, k);
std::cout << i << std::endl;
}
what do you think is pow supposed to refer to? The C++ standard does not even guarantee that after including cmath you'll have a pow function at global scope.
Keep in mind that all the overloads are at least in the std namespace. There is are pow functions that take an integer exponent and there are pow functions that take floating point exponents. It is quite possible that your C++ implementation only declares the C pow function at global scope. This function takes a floating point exponent. The thing is that this function is likely to have a couple of approximation and rounding errors. For example, one possible way of implementing that function is:
double pow(double base, double power)
{
return exp(log(base)*power);
}
It's quite possible that pow(10.0,2.0) yields something like 99.99999999992543453265 due to rounding and approximation errors. Combined with the fact that floating point to integer conversion yields the number before the decimal point this explains your result of 122 because 99+3=122.
Try using an overload of pow which takes an integer exponent and/or do some proper rounding from float to int. The overload taking an integer exponent might give you the exact result for 10 to the 2nd power.
Edit:
As you pointed out, trying to use the std::pow(double,int) overload also seems to yield a value slightly less 100. I took the time to check the ISO standards and the libstdc++ implementation to see that starting with C++11 the overloads taking integer exponents have been dropped as a result of resolving defect report 550. Enabling C++0x/C++11 support actually removes the overloads in the libstdc++ implementation which could explain why you did not see any improvement.
Anyhow, it is probably a bad idea to rely on the accuracy of such a function especially if a conversion to integer is involved. A slight error towards zero will obviously make a big difference if you expect a floating point value that is an integer (like 100) and then convert it to an int-type value. So my suggestion would be write your own pow function that takes all integers or take special care with respect to the double->int conversion using your own round function so that a slight error torwards zero does not change the result.
Your problem is not a bug in gcc, that's absolutely certain. It may be a bug in the implementation of pow, but I think your problem is really simply the fact that you are using pow which gives an imprecise floating point result (because it is implemented as something like exp(power * log(base)); and log(base) is never going to be absolutely accurate [unless base is a power of e].
Can anyone explain why these two variable of the same value can output different values when i use setprecision()?
#include <iostream>
#include <iomanip>
int main()
{
float a=98.765;
double b = 98.765;
//std::cout<<std::setprecision(2)<<a<<std::endl;
std::cout<<std::fixed;
std::cout<<std::setprecision(2)<<a<<std::endl;
std::cout<<std::setprecision(2)<<b<<std::endl;
}
The output for a will be 98.76 while the output for b will be 98.77.
Those variables don't have the same value. When you shoehorn the literal double of 98.765 into the float, it has to do a best fit, and some precision is lost.
You can see this quite easily if you change the precision to 50, you'll also see that not even the double can represent that value exactly:
98.76499938964843750000000000000000000000000000000000
98.76500000000000056843418860808014869689941406250000
However, the important thing is that the former float variable will round down, the latter double will round up.
See also the IEEE754 online converter.
When I debug I sometimes want to print the floating point number returned by a function and use it as an input value for another function. I wonder what are the default parameters which guide the formatting of the floating point numbers.
Are f1 and f2 always the same in the following code?
#include <sstream>
#include <cassert>
int main(int argc, const char *argv[])
{
std::stringstream ss;
float f1 = .1f;
ss << f1;
float f2;
ss >> f2;
assert(f1 == f2);
return 0;
}
Can I write a bunch of floating point numbers to std::cout or std::ofsteam and read them back to get exactly the same numbers or should I explicitly set the amount of numbers after the decimal mark (like it is suggested here?
What bothers me is that although .1 is not representable as a binary fraction it is still formatted correctly by the standard streams.
Not necessarily. By default, ostream outputs 6 digits of
precision. To be able to "round trip" a float, you need
a precision of std::numeric_limits<float>::max_digits10 (which
is 9 for the most common representation). If the stream is
being used for persistance, and you're only persisting floats,
just set the precision before writing anything, e.g.:
ss.precision( std::numeric_limits<float>::max_digits10 );
(If you need to handle both float and double, and don't want
the extra digits on float, you'll need to set the precision
each time you output a floating point value.)
No, they're not guaranteed to be the same.
What's happening is that the float itself has more precision than it'll print out as by default, so as long as what you read in has fewer significant digits than the default output precision, what you print out will (at least usually) be rounded back to the value you read in.
If, however, you have data that uses the full precision of your float, and you read it in and then write it back out at full precision, you'll start to see differences.
#include <sstream>
#include <iomanip>
#include <iostream>
int main() {
std::istringstream buffer("0.1");
float value;
buffer >> value;
std::cout << value << "\n";
std::cout << std::setprecision(10) << value;
}
Result:
0.1
0.1000000015
In this case, the trailing 15 is (approximately) the difference between 0.1 and the closest approximation to it that my compiler's float can represent.
Even more important, assert(f1 == f2); when f1 and f2 are both floating point numbers is rarely correct. You want something like assert(abs(f1 - f2) < tolerance); There are several techniques commonly used for choosing tolerance. Which one you should use depends on the problem your program is addressing.
Consider the following piece of code:
#include <iostream>
#include <cmath>
int main() {
int i = 23;
int j = 1;
int base = 10;
int k = 2;
i += j * pow(base, k);
std::cout << i << std::endl;
}
It outputs "122" instead of "123". Is it a bug in g++ 4.7.2 (MinGW, Windows XP)?
std::pow() works with floating point numbers, which do not have infinite precision, and probably the implementation of the Standard Library you are using implements pow() in a (poor) way that makes this lack of infinite precision become relevant.
However, you could easily define your own version that works with integers. In C++11, you can even make it constexpr (so that the result could be computed at compile-time when possible):
constexpr int int_pow(int b, int e)
{
return (e == 0) ? 1 : b * int_pow(b, e - 1);
}
Here is a live example.
Tail-recursive form (credits to Dan Nissenbaum):
constexpr int int_pow(int b, int e, int res = 1)
{
return (e == 0) ? res : int_pow(b, e - 1, b * res);
}
All the other answers so far miss or dance around the one and only problem in the question:
The pow in your C++ implementation is poor quality. It returns an inaccurate answer when there is no need to.
Get a better C++ implementation, or at least replace the math functions in it. The one pointed to by Pascal Cuoq is good.
Not with mine at least:
$ g++ --version | head -1
g++ (GCC) 4.7.2 20120921 (Red Hat 4.7.2-2)
$ ./a.out
123
IDEone is also running version 4.7.2 and gives 123.
Signatures of pow() from http://www.cplusplus.com/reference/cmath/pow/
double pow ( double base, double exponent );
long double pow ( long double base, long double exponent );
float pow ( float base, float exponent );
double pow ( double base, int exponent );
long double pow ( long double base, int exponent );
You should set double base = 10.0; and double i = 23.0.
If you simply write
#include <iostream>
#include <cmath>
int main() {
int i = 23;
int j = 1;
int base = 10;
int k = 2;
i += j * pow(base, k);
std::cout << i << std::endl;
}
what do you think is pow supposed to refer to? The C++ standard does not even guarantee that after including cmath you'll have a pow function at global scope.
Keep in mind that all the overloads are at least in the std namespace. There is are pow functions that take an integer exponent and there are pow functions that take floating point exponents. It is quite possible that your C++ implementation only declares the C pow function at global scope. This function takes a floating point exponent. The thing is that this function is likely to have a couple of approximation and rounding errors. For example, one possible way of implementing that function is:
double pow(double base, double power)
{
return exp(log(base)*power);
}
It's quite possible that pow(10.0,2.0) yields something like 99.99999999992543453265 due to rounding and approximation errors. Combined with the fact that floating point to integer conversion yields the number before the decimal point this explains your result of 122 because 99+3=122.
Try using an overload of pow which takes an integer exponent and/or do some proper rounding from float to int. The overload taking an integer exponent might give you the exact result for 10 to the 2nd power.
Edit:
As you pointed out, trying to use the std::pow(double,int) overload also seems to yield a value slightly less 100. I took the time to check the ISO standards and the libstdc++ implementation to see that starting with C++11 the overloads taking integer exponents have been dropped as a result of resolving defect report 550. Enabling C++0x/C++11 support actually removes the overloads in the libstdc++ implementation which could explain why you did not see any improvement.
Anyhow, it is probably a bad idea to rely on the accuracy of such a function especially if a conversion to integer is involved. A slight error towards zero will obviously make a big difference if you expect a floating point value that is an integer (like 100) and then convert it to an int-type value. So my suggestion would be write your own pow function that takes all integers or take special care with respect to the double->int conversion using your own round function so that a slight error torwards zero does not change the result.
Your problem is not a bug in gcc, that's absolutely certain. It may be a bug in the implementation of pow, but I think your problem is really simply the fact that you are using pow which gives an imprecise floating point result (because it is implemented as something like exp(power * log(base)); and log(base) is never going to be absolutely accurate [unless base is a power of e].
I'm trying to check if a std::complex number that is a result of a fourier transform (using http://fftw.org/) contains a NaN in either the real or imag part.
I'm using Borland C++, so I don't have access to std::isnan. I have tried to check if the number is NaN by comparing it to itself:
(n.imag() != n.imag())
However, as soon as I call the n.imag() or std::imag(n), I get a "floating point invalid operation".
Is there any way to validate if a std::complex is good; if it contains a NaN?
This works on g++ :
#include<iostream>
#include<cmath>
#include<complex>
int main(){
double x=sqrt(-1.);
std::complex<double> c(sqrt(-1.), 2.);
std::cout<<x<<"\n";
std::cout<<c<<"\n";
std::cout<< ( (c!=c) ? "yup" : "nope" )<<"\n";
}
From the float.h header
int _isnan(double d);
Returns a nonzero value (TRUE) if the value passed in is a NaN; otherwise it returns 0 (FALSE).
int _fpclass(double __d);
Returns an integer value that indicates the floating-point class of its argument. The possible values are defined in FLOAT.H (NaN, INF, etc.)
Is there fpclassify() in math.h? It should return FP_NAN for NaNs. Or better yet use isnan(). If there are no such functions/macros, you may look at the binary representation of your floats or doubles and check manually for NaNs. See IEEE-754 single and double precision formats for details.
I found out that Borland has its own math library. So if you want to avoid floating point errors, use IsNan from Borlands Math.
http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/Math_IsNan#Double.html