I'm attempting to store the value 0.9999 into an mpfr_t variable using the mpfr_set_str() function
But 0.9999 is rounded to 1 (or some other value != 0.9999) during storage, no matter the round value (GMP_RNDD, GMP_RNDU, GMP_RNDN, GMP_RNDZ)
So what's the best method to store 0.9999 in an mpfr_t variable using mpfr_set_str()?
Is it possible?
Here is my test program, it prints "buffer is: 1", instead of the wanted "buffer is: 0.9999":
int main()
{
size_t precision = 4;
mpfr_t mpfrValue;
mpfr_init2(mpfrValue, precision);
mpfr_set_str(mpfrValue, "0.9999", 10, GMP_RNDN);
char *buffer = (char*)malloc((sizeof(char) * precision) + 3);
mp_exp_t exponent;
mpfr_get_str(buffer,
&exponent,
10,
precision,
mpfrValue,
GMP_RNDN);
printf("buffer is: %s\n", buffer);
free(buffer);
mpfr_clear(mpfrValue);
return 0;
}
Thanks for the help
precision is given in bits, not in decimal digits, as you seem to be assuming. It seems that you can reprint the correct value to 4 decimal digits with 15 bits precision. Also, you can output directly using mpfr_printf.
If you do need to use mpfr_get_str, I would pass null as the first parameter. If you do that the string is allocated for you. Then, to free it you call mpfr_free_str.
int main()
{
size_t precision = 15;
mpfr_t mpfrValue;
mpfr_init2(mpfrValue, precision);
mpfr_set_str(mpfrValue, "0.9999", 10, GMP_RNDN);
mpfr_printf("Value is: %Rf\n", mpfrValue);
mpfr_clear(mpfrValue);
return 0;
}
Related
I'm trying to print out the decimal expansion of a rational number in C. The problem I have is that when I divide the numerator by the denominator I lose precision. C rounds up the repeating part when I don't want it to.
For example, 1562/4995 = 0.3127127127... but in my program I get 1562/4995 = 0.312713. As you can see a part of the number that I need has been lost.
Is there a way to specify C to preserve a higher level of decimal precision?
I have tried to declare the result as a double, long double and float. I also tried to split the expansion into 2 integers seperated by a '.'
However both methods haven't been successful.
int main() {
int numerator, denominator;
numerator = 1562;
denominator = 4995;
double result;
result = (double) numerator / (double) denominator;
printf("%f\n", result);
return 0;
}
I expected the output to be 1562/4995 = 0.3127127127... but the actual output is 1562/4995 = 0.312713
The %f format specifier to printf shows 6 digits after the decimal point by default. If you want to show more digits, use a precision specifier:
printf("%.10f\n", result);
Also, the double type can only accurately store roughly 16 decimal digits of precision.
You need to change your output format, like this:
printf("%.10lf\n", result);
Note two things:
The value after the . specifies the decimal precision required (10 decimal places, here).
Note that I have added an l before the f to explicitly state that the argument is a double rather than a (single-precision) float.
EDIT: Note that, for the printf function, it is not strictly necessary to include the l modifier. However, when you come to use the 'corresponding' scanf function for input, it's absence will generate a warning and (probably) undefined behaviour:
scanf("%f", &result); // Not correct
scanf("%lf", &result); // Correct
If printing is all you want to do, you can do this with the same long division you were taught in elementary school:
#include <stdio.h>
/* Print the decimal representation of N/D with up to
P digits after the decimal point.
*/
#define P 60
static void PrintDecimal(unsigned N, unsigned D)
{
// Print the integer portion.
printf("%u.", N/D);
// Take the remainder.
N %= D;
for (int i = 0; i < P && N; ++i)
{
// Move to next digit position and print next digit.
N *= 10;
printf("%u", N/D);
// Take the remainder.
N %= D;
}
}
int main(void)
{
PrintDecimal(1562, 4995);
putchar('\n');
}
I was trying to extract the exact fractional part from a floating point number. I tried with this:
float f=254.73;
int integer = (int)f;
float fractional = f-integer;
printf ("The fractional part is: %f", fractional);
But the output is: 0.729996. For this reason when I was doing this:
float f=254.73;
int integer = (int)f;
float fractional = f-integer;
int fractional_part_in_integer = ((int)(f*100)%100);
printf ("The value is: %d", fractional_part_in_integer);
It gives me 72 as output. But, I want to extract exactly 73 from the given number 254.73. I already know how to use %.2f during printf() function to print upto two decimal numbers. But in my code I don't want to print the number right now. I have some calculations with that fractional part as integer form i.e. 73.
So, my problem is how could I extract the fractional part from 254.73 so that I can get exact 73 as integer to do more calculations?
How to get the exact fractional part from a floating point number as an integer?
trying to extract the exact fractional part from a floating point number.
Use modf() or modff()
double modf(double value, double *iptr);
float modff(float value, float *iptr);
The modf functions break the argument value into integral and fractional parts, ...
C11 ยง7.12.6.12 2
#include <math.h>
double value = 1.234;
double ipart;
double frac = modf(value, &ipart);
A better approach for OP's need may be to first round a scaled value and then back into whole and fractional parts.
double value = 254.73;
value = round(value*100.0);
double frac = fmod(value, 100); // fmod computes the floating-point remainder of x/y.
double ipart = (value - frac)/100.0;
printf("%f %f\n", ipart, frac);
254.000000 73.000000
Ref detail: When OP uses 254.73, this is converted to the nearest float value which may be 254.729995727539....
float f = 254.73;
printf("%.30f\n", f);
// 254.729995727539062500000000000000
You can use sprintf and sscanf to print the value to a string and then extract the fraction. The %*d scans and discards the first integer of the formatted string. A dot is scanned and then the fraction.
#include <stdio.h>
int main( void)
{
char fp[30];
int fraction;
float f = 254.73f;
sprintf ( fp, "%.2f", f);
sscanf ( fp, "%*d.%d", &fraction);
printf ( "%d\n", fraction);
return 0;
}
The easiest way is to use standard library function ceil from <math.h>.
The float number 254.73 may be converted to 254.7299957275390625000000.
f-integer will give 0.7299957275390625000000.
Now multiply it by 100 and use ceil function to get the smallest integer value not less than 72.99957275390625000000.
int fractional_part_in_integer = ((int)ceil(fractional*100)) % 100;
UPDATE: As pointed in a comment by #Sneftel, the above suggested method in this answer will not work consistently.
A simple hack is to use round function from math.h to round the f and then extract the fractional part
float f=254.73;
int int_part = (int)f;
float fractional = round(f*100)/100 - int_part;
int fractional_part_in_integer = (int)(fractional*100);
printf("%d, %d\n ", int_part, fractional_part_in_integer);
Output:
254, 73
Take the number in string use the built-in function find() to find the position of ".".
#include <iostream>
using namespace std;
int main()
{
string f = "254.7356656";
int position = f.find(".");
cout << f.substr(position + 1);
return 0;
}
Output: 7356656
I tried to convert a number n-based to decimal with C. I have this code :
scanf("%d", &n);
scanf("%d %d %d %d", &n1, &n2, &n3, &n4);
dec = ( n1*pow(n,3) + n2*pow(n,2) + n3*pow(n,1) + n4*pow(n,0) );
It works fine until I enter n=10 & n1 n2 n3 n4=0 2 5 4.
The result should be 254, but the terminal showed 253. It turns out that starting from 200-999, the dec decreased by 1. However when I input 1000, the dec=1000. How can I fix this?
Most likely you have declared dec as an int while the function pow returns a double value. Here double is converted to an int an is rounded.
change to
double dec = ( n1*pow(n,3) + n2*pow(n,2) + n3*pow(n,1) + n4*pow(n,0) );
printf("%f",dec);
and the output will be
254.000000
While the code you have provided works fine on some implementations, example here, you could preferably not use the pow function since you are working with integers and non-negatives as power, and define your own intpow function. A naive implementation of that would be:
int intpow(int n, unsigned int power)
{
int result = 1;
while (power)
{
result *= n;
power--;
}
return result;
}
It just might be that that whole sum, which is a sum of doubles, turns out to be less than the number you expect to see by, say, 0.000013, of which the digits after the decimal point are discarded when being converted to get assigned to that int dec.
You could check the double result by changing the type of dec to double and printing it with the format specifier "%f". If that's the case, my recommendation would be a proper solution.
You may also try and think of better ways of base conversion, because there is one which doesn't require a (int)pow at all.
I'm trying to convert the decimal portion of a double 247.32
into an int 32. I only need two decimal places.
I can cast the double as int and subtract from the double to get .32000
I can then multiply by 100 to get 32.000
But then when I try to cast that 32.000 as an int, it turns into 31.
Can I fix this?
Should I use a different datatype than a double to store that number?
Thanks
The problem (which skjaidev's answer doesn't solve) is that 247.32 cannot be represented exactly in binary floating-point. The actual stored value is likely to be:
247.31999999999999317878973670303821563720703125
So you can't just discard the integer part, multiply by 100, and convert to int, because the conversion truncates.
The round() function, declared in <math.h>, rounds a double value to the nearest integer -- though the result is still of type double.
double a = 247.32;
a -= trunc(a); /* a == 0.32 -- approximately */
a *= 100.0; /* a == 32.0 -- approximately */
a = round(a); /* a == 32.0 -- exactly */
printf ("%d\n", (int)a);
Or, putting the computation into a single line:
double a = 247.32;
printf("%d\n", (int)round(100.0 * (a - trunc(a))));
Actually, this is probably a cleaner way to do it:
double a = 247.32;
printf("%d\n", (int)round(100.0 * fmod(a, 1.0)));
Given input value x and output y:
char buf[5];
snprintf(buf, sizeof buf, "%.2f", fmod(x, 1.0));
y = strtol(buf+2, 0, 10);
Or just y = 10*(buf[2]-'0')+buf[3]-'0'; to avoid the strtol cost.
This is about the only way to do what you want without writing a ton of code yourself, since the printf family of functions are the only standard functions capable of performing decimal rounding.
If you have some additional constraints like that x is very close to a multiple of 1/100, you could perhaps cheat and just do something like:
int y = ((x+0.001)*100;
By the way, if your problem involves money, do not use floating point for money! Use integers in units of cents or whatever the natural smallest unit for your currency is.
Since you're only looking for 2 decimal places, this works for me:
double a = 247.32;
int b = (int) (a * 100)%100;
printf ("%d\n", b);
Update: See my comment below.
you could say that I am relatively new to C, but I need clarification on a question.
I have a char[] that represents a number. If this char[] is longer than LONG_MAX I want to tell the user it is too long. The problem is that when I compare its value to a float, it becomes truncated. Here's what I mean.
int main(int argc, char ** argv) {
char str[] = argv[1]; /* I set it to 9223372036854775809, only +1 higher than LONG_MAX */
double l = atof(str);
double j = LONG_MAX;
printf("%lf\n", l); /* This prints 9223372036854775808.000000, which is LONG_MAX ??? WHY?? */
printf("%lf\n", j); /* This prints same as above, 9223372036854775808.000000 */
printf("%s\n", l > j ? "true" : "false"); /* false */
return 0; /* what am I doing wrong? */
}
UPDATE:
I tried your iret solution and I still run into the same rounding problem
j = LONG_MAX;
int iret = sscanf (str, "%lf", &l);
if (iret != 1)
return 0; /* conversion was bad */
else {
if (l > j || l < -(j))
return 0; /* too small or too large */
}
printf("%lf\n", l);
printf("%lf\n", j);
printf("%s\n", l > j ? "true" : "false");
You can check for overflow easily enough with strtol, but it requires a little extra work.
const char *str = ...;
char *e;
long x;
errno = 0;
x = strtol(str, &e, 0);
if (!*str || *e) {
fprintf(stderr, "invalid number: %s\n", str);
exit(1);
}
if ((x == LONG_MAX || x == LONG_MIN) && errno == ERANGE) {
fprintf(stderr, "number too large: %s\n", str);
exit(1);
}
Now, let's talk about the problem with strtod (or atof, which is just a broken version of strtod).
If you convert 9223372036854775809 to a double, then 9223372036854775808 is correct. A double has 53 bits of precision, and a 64-bit long has, well, 64 bits. As soon as you start working with floating-point numbers you need to be prepared for rounding.
For example, there is round-off error in the following code. Can you spot it?
double x = 0.1;
Footnote: I'm assuming 64-bit long and IEEE double-precision double here.
Per the "man" page for atof:
http://linux.die.net/man/3/atof
The atof() function converts the initial portion of the string pointed
to by nptr to double. ... atof() does not detect errors.
Which is why I prefer to use "sscanf" instead:
int iret = sscanf (SOME_TEXT, "%lf", &SOME_DOUBLE);
If "iret != 1", then I know an error occurred, and can take the appropriate action.
IMHO...
PS:
Why aren't you declaring "l" and "j". Naughty naughty! You should always declare your variables, even in FORTRAN and Basic ;)
And why not declare them as float ("%f") or double ("%lf")?
I believe the reason why you are getting the value "9223372036854775808.000000" for both your inputs is due to the precision limitations of floating point approximations.
By the way, the value isn't LONG_MAX, but LONG_MAX + 1 -> 2^63.
By definition, the representation of LONG_MAX exactly (as an integer) requires 63 bits of precision. However, in a 64-bit floating point representation like double, there are only 53 bits of precision, since the other bits are required to store the sign and exponent. That's why both LONG_MAX and LONG_MAX + 2 end up being rounded to 9223372036854775808 <=> 2^63.
To handle this case properly, perhaps look at strtol which will set an error code when the input is out of range.
Your long seems to be 63 bits. A float has 23 significant bits (or 24 with leading 1). Your longs are the exactly the same in the upper 24 bits. So they become the same.
A float is basically mantissa*2^exponent. The exponent makes sure that the magnitude still matches. But you only have 23 bits of mantissa. So it becomes top23bitsoflong*2^(numberofremainingbits).
This is a bit simplified ignoring leading one and exponent bias.