I'm completely new to C and I'm trying to complete an assignment. The exercise is to print tan(x) with x incrementing from 0 to pi/2.
We need to print this in float and double. I wrote a program that seems to work, but I only printed floats, while I expected double.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
double x;
double pi;
pi = M_PI;
for (x = 0; x<=pi/2; x+= pi/20)
{
printf("x = %lf, tan = %lf\n",x, tan(x));
}
exit(0);
}
My question is:
Why do I get floats, while I defined the variables as double and used %lf in the printf function?
What do I need to change to get doubles as output?
"...but I only printed floats, while I expected double"
You are actually outputting double values.
float arguments to variadic functions (including printf()) are implicitly promoted to double in general. reference.
So even if your statement
printf("x = %lf, tan = %lf\n",x, tan(x));
were changed to:
printf("x = %f, tan = %f\n",x, tan(x));
It would still output double as both "%f" and "%lf" are used as double format specifiers for printf() (and other variadic functions).
Edit to address following statement/questions in comments:
"I know that a double notation has 15 digits of [precision]."
Yes. But there is a difference between the actual IEEE 754 specified characteristics of the float/double data types, and the way that they can be _made to appear using format specifiers in the printf() function.
In simplest terms:
double has double (2x) the precision of a float.
float is a 32 bit IEEE 754 single precision Floating Point Number with 1 bit for the sign, 8 bits for the exponent, and 24* for the value, resulting in 7 decimal digits of precision.
double is a 64 bit IEEE 754 double precision Floating Point Number with 1 bit for the sign, 11 bits for the exponent, and 53* bits for the value resulting in 15 decimal digits of precision.
* - including the implicit bit (which always equals 1 for normal numbers, and 0 for subnormal numbers. This implicit bit is not stored in memory), but not the sign bit.
"...But with %.20f I was able to print more digits, how is that possible and where do the digits come from?"
The extra digits are inaccuracies caused by binary representation of analog numbers, coupled with using a width specifier to force more information to display than what is actually represented by the stored value.
Although width specifiers have there rightful place, they can also result in providing misleading results.
Why do I get floats, while I defined the variables as double and used %lf in the printf function?
Code is not getting "floats", output is simply text. Even if the argument coded is a float or a double, the output is the text translation of the floating point number - often rounded.
printf() simply follows the behavior of "%lf": print a floating point value with 6 places after the decimal point. With printf(), "%lf" performs exactly like "%f".
printf("%lf\n%lf\n%f\n%f\n", 123.45, 123.45f, 123.45, 123.45f);
// 123.450000
// 123.449997
// 123.450000
// 123.449997
What do I need to change to get doubles as output?
Nothing, the output is text, not double. To see more digits, print with greater precision.
printf("%.50f\n%.25f\n", 123.45, 123.45f);
// 123.45000000000000284217094304040074348449710000000000
// 123.4499969482421875000000000
how do I manipulate the code so that my output is in float notation?
Try "%e", "%a" for exponential notation. For a better idea of how many digits to print: Printf width specifier to maintain precision of floating-point value.
printf("%.50e\n%.25e\n", 123.45, 123.45f);
printf("%a\n%a\n", 123.45, 123.45f);
// 1.23450000000000002842170943040400743484497100000000e+02
// 1.2344999694824218750000000e+02
// 0x1.edccccccccccdp+6
// 0x1.edccccp+6
printf("%.*e\n%.*e\n", DBL_DECIMAL_DIG-1, 123.45, FLT_DECIMAL_DIG-1,123.45f);
// 1.2345000000000000e+02
// 1.23449997e+02
Related
Here's my code:
float x = 21.195;
printf("%.2f\n", x);
printf("%.2f\n", 21.195);
I would expect both print statements to have identical output, but instead, the first prints 21.19, and the second prints 21.20.
Could someone explain why the output is different?
The values are different. The first is a float, which is typically 4 bytes. The second is a double, which is typically 8 bytes.
The rules for rounding are based on the third digit after the decimal place. So, in one case, the value is something like 21.19499997 and the other 21.1950000000001, or something like that. (These are made up to illustrate the issue with rounding and imprecise numeric formats.)
By default 21.195 is a double.
If you want a float, write :
21.195F
or
(float)21.195
Regards
When a floating point variable is defined in C, by default it is set to double. So x is set to float because you mentioned it explicitly, else 21.195 is considered to be double.
Now, as mentioned above, float is usually about 4 bytes and double is about 8 bytes. So a float value has 24 significant bits with 7 digits of precision and double has 53 significant bits with 15 to 16 digits of precision.
A roundoff function %.2f works to round off the number correct to 2 decimal places and checks the third digit after the decimal point for rounding off.
So 21.195 in float expands to 21.19499998 and is then reduced to 21.19 after %.2f an 21.195 in double expands to 21.1950000000000001 and hence reduces to 21.20.
Hope it helps!
I'm confused about the behavior of printf("%f", M_PI). It prints out 3.141593, but M_PI is 3.14159265358979323846264338327950288. Why does printf do this, and how can I get it to print out the whole float. I'm aware of the %1.2f format specifiers, but if I use them then I get a bunch of unused 0s and the output is ugly. I want the entire precision of the float, but not anything extra.
Why does printf do this, and how can I get it to print out the whole
float.
By default, the printf() function takes precision of 6 for %f and %F format specifiers. From C11 (N1570) ยง7.21.6.1/p8 The fprintf function (emphasis mine going forward):
If the precision is missing, it is taken as 6; if the precision is
zero and the # flag is not specified, no decimal-point character
appears. If a decimal-point character appears, at least one digit
appears before it. The value is rounded to the appropriate number
of digits.
Thus call is just equivalent to:
printf("%.6f", M_PI);
The is nothing like "whole float", at least not directly as you think. The double objects are likely to be stored in binary IEEE-754 double precision representation. You can see the exact representation using %a or %A format specifier, that prints it as hexadecimal float. For instance:
printf("%a", M_PI);
outputs it as:
0x1.921fb54442d18p+1
which you can think as "whole float".
If all what you need is "longest decimal approximation", that makes sense, then use DBL_DIG from <float.h> header. C11 5.2.4.2.2/p11 Characteristics of floating types :
number of decimal digits, q, such that any floating-point number with
q decimal digits can be rounded into a floating-point number with p
radix b digits and back again without change to the q decimal digits
For instance:
printf("%.*f", DBL_DIG-1, M_PI);
may print:
3.14159265358979
You can use sprintf to print a float to a string with an overkill display precision and then use a function to trim 0s before passing the string to printf using %s to display it. Proof of concept:
#include <math.h>
#include <string.h>
#include <stdio.h>
void trim_zeros(char *x){
int i;
i = strlen(x)-1;
while(i > 0 && x[i] == '0') x[i--] = '\0';
}
int main(void){
char s1[100];
char s2[100];
sprintf(s1,"%1.20f",23.01);
sprintf(s2,"%1.20f",M_PI);
trim_zeros(s1);
trim_zeros(s2);
printf("s1 = %s, s2 = %s\n",s1,s2);
//vs:
printf("s1 = %1.20f, s2 = %1.20f\n",23.01,M_PI);
return 0;
}
Output:
s1 = 23.010000000000002, s2 = 3.1415926535897931
s1 = 23.01000000000000200000, s2 = 3.14159265358979310000
This illustrates that this approach probably isn't quite what you want. Rather than simply trimming zeros you might want to truncate if the number of consecutive zeros in the decimal part exceeds a certain length (which could be passed as a parameter to trim_zeros. Also โ you might want to make sure that 23.0 displays as 23.0 rather than 23. (so maybe keep one zero after a decimal place). This is mostly proof of concept โ if you are unhappy with printf use sprintf then massage the result.
Once a piece of text is converted to a float or double, "all" the digits is no longer a meaningful concept. There's no way for the computer to know, for example, that it converted "3.14" or "3.14000000000000000275", and they both happened to produce the same float. You'll simply have to pick the number of digits appropriate to your task, based on what you know about the precision of the numbers involved.
If you want to print as many digits as are likely to be distinctly represented by the format, floats are about 7 digits and doubles are about 15, but that's an approximation.
Below is the solution code for an excercise from KN King's Modern Programming approach.
#include<stdio.h>
int main(void)
{
int i;
float j,x;
scanf("%f%d%f",&x,&i,&j);
printf("i = %d",i);
printf("x = %f",x);
printf("j = %f",j);
}
Input:
12.3 45.6 789
Expected Result :
i = 45
x = 12.3
j = 0.6
Actual Result:
i = 45
x = 12.300000
j = 0.600000
Question:
Why are there extra decimal values seen for floats? Is there any default precision set for float and how can I change it (Only default - I know I can use formatting strings to control precision values in printf). I am using gcc (Mingw) on windows7.
The floating-point formats record only a mathematical value. They do not record how much precision the value had when scanned (or otherwise obtained). (For that matter, this is true of the integer formats too.)
When you display a floating-point value, you must specify how many digits to display. The C standard defines a default of six digits for the %f specifier:1
A double argument representing a floating-point number is converted to decimal notation in the style [โ]ddd.ddd, where the number of digits after the decimal-point character is equal to the precision specification. If the precision is missing, it is taken as 6; if the precision is zero and the # flag is not specified, no decimal-point character appears. If a decimal-point character appears, at least one digit appears before it. The value is rounded to the appropriate number of digits.
You specify the precision by writing the number of digits after a period in the format specifications, such as %.2f:2
The precision takes the form of a period (.) followed either by an asterisk * (described later) or by an optional decimal integer; if only the period is specified, the precision is taken as zero.
(The asterisk is used to specify the number of digits in a int parameter passed to printf.)
Notes
1 C 2011 (N1570) 7.21.6.1 8.
2 C 2011 (N1570) 7.21.6.1 4.
You can't change the precision of a float, but (as it sounds like you know) you can change the precision of the display of a float.
Why are there extra decimal values seen for floats?
That's why floats are floats.By default %f lets you display 6 digits after decimal.
That's nothing do do with the precision of the number stored.Numbers are stored according to the IEEE 754 FLOATING POINT representation in most systems.And numbers are not stored with decimal points. So, since you do not control how you store numbers, you can't change the precision.Precision is fixed.
Is there any default precision set for float and how can I change it.
Again , precision is not default its not how it is stored. Check its representation for 32 bit or 64 bit.Youwould like to print more/less digits after decimal.You can do this :
float i=2.89674534423;
printf("%.10f",i); Prints 10 digits after decimal.
A double is not infinitely accurate, and it does not store numbers in decimal, so it cannot precisely store 0.085. If you want to print a number to two significant figures, use the precision format specifier - see http://www.cprogramming.com/tutorial/printf-format-strings.html for examples.
double value = 0.085;
NSLog(#"%.2g", value);
This will print "0.085"
Be aware that using the precision specifier normally controls the number of digits displayed after the decimal point - but in the case of a double, it controls significant figures.
float value = 0.085;
NSLog(#"%.2f", value);
Will print "0.09"
I have an ascii "15605632.68128593" and I wish to convert
it to a double without losing accuracy
double d;
d=(double)atof("15605632.68128593");
printf("%f",d);
printed result is 15605632.681286
Any ideas?
It's likely you're not getting all the trailing decimal places. Try printf("%.8f", d).
You might also try sscanf("15605632.68128593", "%lf", &d) in place of the atof call.
It's also not necessary to cast the result of atof to double. It's already a double. But the cast does no harm.
Note that - at least about 6 years ago when I looked at this in detail - many printf and scanf implementations were buggy in the sense that they didn't function as perfect inverses as you'd assume. Visual C/C++ and gcc both had problems in their native implementations. This paper is a useful reference.
Cygwin with gcc 4.3.4:
#include <stdio.h>
int main(void)
{
double x;
sscanf("15605632.68128593", "%lf", &x);
printf("%.8f\n", x);
return 0;
}
And then:
# gcc foo.c
# ./a
15605632.68128593
Goal: Convert "15605632.68128593" to a double without losing accuracy.
atof() accomplished that to best the program could do. But since "15605632.68128593" (a 16-digit number) is not exactly representable as a double in your C, it was approximated to 1.560563268128593080...e+07. Thus accuracy was lost, albeit a small loss.
Typical double can represent about 264 different numbers. The nearby candidates and OP's string are shown below for reference.
15605632.68128 592893... previous double
"15605632.68128 593" code's string
15605632.68128 593080... closest double
15605632.68128 6 output
The grief comes when attempting to print, thinking that what printed was the exact value of x. Instead the nearby double value was printed. Printout is also rounded. Using the %f specifier defaults to 6 places to the right of the '.' giving the reported 15605632.681286, a 14 digit number.
A better way to see all the significant digits for all double is to use the %e format with DBL_DIG or DBL_DECIMAL_DIG. DBL_DIG is the most number of digits to the right of the '.', in decimal exponential notation %e, to show all the digits needed to "round-trip" a double (string to double to string without a string difference). Since %e always shows 1 digit to the left of '.', the print below shows 1 + DBL_DIG significant digits. DBL_DECIMAL_DIG is 17 on my mine and many C environments, but it vary.
If you wish to show all the significant digits, you need to qualify what is significant. The nextafter() function shows the next representable double. So we might want to show at least enough digits to distinguish x and the next x. I recommend DBL_DECIMAL_DIG. Details
The exact value the program used for your "1.560563268128593e+07" is 15605632.68128593079745769500732421875. There are few situations where you need to see all those digits. Even is you request lots of digits, at some point, printf() just gives you zeros.
#include <stdio.h>
#include <float.h>
#include <tgmath.h>
int main(int argc, char *argv[]) {
double x;
x = atof("15605632.68128593");
printf("%.*le\n",DBL_DIG, x); // All digits "round-trip" string-to-double-string w/o loss
printf("%.*le\n",DBL_DIG + 1, x); // All the significant digit "one-way" double-string
printf("%.*le\n",DBL_DIG + 1, nextafter(x, 2*x)); // The next representable double
printf("%.*le\n",DBL_DIG + 3, x); // What happens with a few more
printf("%.*le\n",DBL_DIG + 30, x); // What happens if you are a bit loony
return 0;
}
1.560563268128593e+07
1.5605632681285931e+07
1.5605632681285933e+07
1.560563268128593080e+07
1.560563268128593079745769500732421875000000000e+07
double does not have that much precision. It can only round-trip 15 (DBL_DIG from float.h) decimal places from decimal string to double back to decimal string.
Edit: While, in general, my claim is true, it doesn't seem to be your problem here. While there exist 16-decimal-place numbers which can't be round-tripped, this particular input can.
Can someone explain me how to choose the precision of a float with a C function?
Examples:
theFatFunction(0.666666666, 3) returns 0.667
theFatFunction(0.111111111, 3) returns 0.111
You can't do that, since precision is determined by the data type (i.e. float or double or long double). If you want to round it for printing purposes, you can use the proper format specifiers in printf(), i.e. printf("%0.3f\n", 0.666666666).
You can't. Precision depends entirely on the data type. You've got float and double and that's it.
Floats have a static, fixed precision. You can't change it. What you can sometimes do, is round the number.
See this page, and consider to scale yourself by powers of 10. Note that not all numbers are exactly representable as floats, either.
Most systems follow IEEE-754 floating point standard which defines several floating point types.
On these systems, usually float is the IEEE-754 binary32 single precision type: it has 24-bit of precision. double is the binary64 double precision type; it has 53-bit of precision. The precision in bit numbers is defined by the IEEE-754 standard and cannot be changed.
When you print values of floating point types using functions of the fprintf family (e.g., printf), the precision is defined as the maximum number of significant digits and is by default set to 6 digits. You can change the default precision with a . followed by a decimal number in the conversion specification. For example:
printf("%.10f\n", 4.0 * atan(1.0)); // prints 3.1415926536
whereas
printf("%f\n", 4.0 * atan(1.0)); // prints 3.141593
It might be roughly the following steps:
Add 0.666666666 with 0.0005 (we get 0.667166666)
Multiply by 1000 (we get 667.166666)
Shift the number to an int (we get 667)
Shift it back to float (we get 667.0)
Divide by 1000 (we get 0.667)
Thank you.
Precision is determined by the data type (i.e. float or double or long double).
If you want to round it for printing purposes, you can use the proper format specifiers in printf(), i.e.
printf("%0.3f\n", 0.666666666) //will print 0.667 in c
Now if you want to round it for calculating purposes you have to first multiply the float by 10^number of digits then typecast to int , do the calculation and then again typecast to float and divide by same power of 10
float f=0.66666;
f *= 1000; // 666.660
int i = (int)f; // 666
i = 2*i; // 1332
f = i; // 1332
f /= 1000; // 1.332
printf("%f",f); //1.332000