Precision loss with GMP - c++

I have a program that reads numbers from a string to an mpz_t and then converts it to an mpf_t. Despite of being read correctly from the file, there is a precision loss when I convert them to mpf_t. The code is the following:
#include <gmp.h>
#include <stdlib.h>
#include <stdio.h>
int main (int argc, char **argv) {
char* str = "632512364206354367378453";
mpz_t x;
mpz_init_set_str(x, str, 10);
mpf_t a;
mpf_init(a);
mpf_set_z(a, x);
gmp_printf("mpz_t: %Zd\n", x);
gmp_printf("mpf_t: %Ff\n", a);
}
The output for this example is:
mpz_t: 632512364206354367378453
mpf_t: 632512364206354367378000.000000
As you can see the last 3 digits are not correct. How can I avoid this? Is there any other function to perform this conversion?
Thanks

From the manual page:
Function: void mpf_init (mpf_t x)
Initialize x to 0. Normally, a variable should be initialized once only or at least be cleared, using mpf_clear, between initializations.
The precision of x is undefined unless a default precision has already
been established by a call to mpf_set_default_prec.
There's your problem.
Solution:
Function: void mpf_init2 (mpf_t x, mp_bitcnt_t prec)
Initialize x to 0 and set its precision to be at least prec bits. Normally, a variable should be initialized once only or at least be
cleared, using mpf_clear, between initializations.
That way, you can use the prec precision count argument to specify how many bits of precision you want.

Related

fmod() is not giving expected answer

i am begginner in c++
below is my code ,I am using fmod(),in which the value of k should be 0.23 but it is giving it 0
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
int k;
k=fmod(234.23,3);
cout<<"k="<<k<<endl;
return 0;
}
I am using codeblock.
Is it a compiler problem ?
You are assigning the result to a variable of type int, and int by its very nature can only represented integer numbers.
You need to use a floating-point type, such as float or double.
You must use float instead of int for k. An integer can only hold exact numbers, but no fractions. For this use, float or double.
C++ is a strongly typed language.
The result of fmod(234.23, 3) is 0.23, but you use an int to store it, so 0.23 is converted to a integer 0.
You should declare as float k;

const vs #define (strange behavior)

I used to replace const with #define, but in the below example it prints false.
#include <iostream>
#define x 3e+38
using namespace std;
int main() {
float p = x;
if (p==x)
cout<<"true"<<endl;
else
cout<<"false"<<endl;
return 0;
}
But if I replace
#define x 3e+38
with
const float x = 3e+38;
it works perfectly, question is why? (I know there are several topics discussed for #define vs const, but really didn't get this, kindly enlighten me)
In c++ the literals are double precision. In the first examples the number 3e+38 is first converted to float in the variable initialization and then back to double precision in the comparison. The conversions are not necessary exact, so the numbers may differ. In the second example numbers stay float all the time. To fix it you can change p to double, write
#define x 3e+38f
(which defines a float literal), or change the comparison to
if (p == static_cast<float>(x))
which performs the same conversion as the variable initialization, and does then the comparison in single precision.
Also as commented the comparison of floating point numbers with == is not usually a good idea, as rounding errors yield unexpected results, e.g., x*y might be different from y*x.
The number 3e+38 is double due its magnitude.
The assignment
float p = x;
causes the 3e+38 to lose its precision and hence its value when stored in p.
thats why the comparison :
if(p==x)
results in false because p has different value than 3e+38.

Output of large numbers

I need to use a high Number in my program. Here is an minimum example that shows the problem. It just reads in a number and gives out the number again.
using namespace std;
#include <iostream>
#include <stdlib.h>
int main(int argc, char* argv[])
{
double
N = atoi(argv[1]);
cout << N << endl;
return 0;
}
Everything works fine till 10^9 If I take 10^10 as input the result is 1.41007e+09. I just don't know why this is the case. I already tried the following:
Change the Datatype of N to double, long int, unsigned int
Define the Number directly in the program with N = pow(10,10). When I put out N and pow(10,10) directly, N gives the wrong value and pow(10,10) the right one.
Using atoi when the resulting value would be outside the bounds of int (i.e. greater than INT_MAX or less than INT_MIN) causes undefined behaviour.
This is a good reason to not use atoi. The alternatives strtol and strtoul from the C library have well-defined behaviour for all inputs.
The C++11 function std::stoi also has well-defined behaviour (it throws an exception if the value is out of range). istream::operator>>(int&) is also well-defined but it has some finicky details relating to the fact that streams can't "look ahead".
Using atoi on the number greater than INT_MAX will cause the resultant value to start from the negative value INT_MIN.
Try using atoll function. It is in . But this is defined in C++11. So, if your compiler is not up-to-date than it will throw an error.
If the value is again quite large (greater than 8 bytes), then I would suggest you to use external libraries.
The input 10^10 goes beyond the maximum limit of an integer that is 2147483648 and 10^9 is well within the limit.
Following code can be useful.
using namespace std;
#include <iostream>
#include <stdlib.h>
int main(int argc, char* argv[])
{
long long N = atoll (argv[1]);
cout << N << endl;
return 0;
}

double datatype casting works on windows but not on linux

I am having a string pointer in C which is having bigint data.
eg 9223372036854775807 i.e 2^63
I wanted to cast this to double but as you know double has 15/16 digits available to store in fraction part the rest of the bits are discarded.so the above number which is very large would be casted to 9.22337203685476E+18 i.e 922337203685476000.
This makes comparing the original value and casted value mismatch. This usually happens on Linux platform. Thing is why this doesnot happen on Windows?
Is it compiler dependent or something which is unknown to me. ?
That value is 2^63 - 1, which cannot be exactly represented with a double. The closest value that can be represented is 2^63. And that's what you get if you use e.g. sscanf or atof:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
const char *str = "9223372036854775807";
double d;
double e;
sscanf(str, "%lf", &d);
e = atof(str);
printf("%f\n", d); // 9223372036854775808.000000
printf("%f\n", e); // 9223372036854775808.000000
}
See http://ideone.com/zz2NIF.

Convert double to mpf_class precisely

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