How can I fix my floats being rounded down to doubles? - c

I know that by default in C when you declare a float it gets automatically saved as a double and that if you want it to be saved as a float you have to declare it like this
float x = 0.11f
but what if my x value comes from a scanf? How can I do so that when I print it it doesn't get rounded down or up?
Here's my code btw, thanks for the help.
#include <stdio.h>
int main() {
float number = 0;
float comparison;
do{
printf("\nEnter a number: ");
scanf("%f", &comparison);
if(comparison > number) {
number = comparison;
}
}while(comparison > 0);
printf("The largest number enteres was: %f\n\n", number);
}

what if my x value comes from a scanf? How can I do so that when I print it it doesn't get rounded down or up?
scanf with an %f directive will read the input and convert it to a float (not a double). If the matched text does not correspond to a number exactly representable as a float then there will be rounding at this stage. There is no alternative.
When you pass an argument of type float to printf() for printing, it will be promoted to type double. This is required by the signature of that function. But type double can exactly represent all values of type float, so this promotion does not involve any rounding. printf's handling of the %f directives is aligned with this automatic promotion: the corresponding (promoted) argument is expected to be of type double.
There are multiple avenues to reproducing the input exactly, depending on what constraints you are willing to put on that input. The most general is to read, store, and print the data as a string, though even this has its complications.
If you are willing to place a limit on the maximum decimal range and precision for which verbatim reproduction is supported, then you may be able to get output rounded to the same representation as the input by specifying a precision in your printf field directives:
float f;
scanf("%f", &f);
printf("%f %.2f %5.2f\n", f, f, f);
If you want to use a built-in floating-point format and also avoid trailing zeroes being appended then either an explicit precision like that or a %g directive is probably needed:
printf("%f %g\n", f, f);
Other alternatives are more involved, such as creating a fixed-point or arbitrary-precision decimal data type, along with appropriate functions for reading and writing it. I presume that goes beyond what you're presently interested in doing.
Note: "double" is short for "double precision", as opposed to notionally single-precision "float". The former is the larger type in terms of storage and representational capability. In real-world implementations, there is never any "rounding down" from float to double.

Related

C - int arithmetic calculation with float (beginner)

I have user integer input input and wanted to output the calculation with the input by division. The return had been 0 rather than decimals results. Wanted to prevent use of initialize the variable input with int rather than float to prevent possible errors in later data input with delimiter .
Is there any way to calculate float result w/ int input other than assigning float for the variable input ?
Source:
#include <stdio.h>
#include <stdlib.h>
int main() {
int input;
printf("Enter data:");
scanf("%d", &input);
printf("Output: %f", (input / 7));
return 0;
}
Return:
Input: 6
0.0000
Everything in C has a type, including constants like 7 which is type int, 7.0f which is type float or 7.0 which is type double.
Whenever mixing fixed point and floating point operands in the same operation with two operands (generally a bad idea), then the fixed point operand is converted to floating point. This is called "the usual arithmetic conversions".
Examples:
int input;, input / 7. Both operands are int, no promotion occurs, the result will be of type int. This has everything to do with the / operator and nothing to do with where you place the result. The divison will get carried out on int type, so if you wanted it to be type float, it's already too late. Something like float f = input / 7 will not affect the type used by the division in any way. It will only convert the resulting int to float.
int input;, input / 7.0f. One operand is type int, the other is type float. The usual arithmetic conversions state that the int operand will get converted to float before the division. So this would solve the problem.
However, here is a better idea: Simply never mix fixed point and floating point in the same expression, because the potential for bugs is huge. Instead do this:
scanf("%d", &input);
float f_input = (float)input;
printf("Output: %f", (f_input / 7.0f);
Now nothing goes on implicitly, all implicit conversions have been removed. The cast is not necessary, but creates self-documenting code saying: "yes I do mean to make this a float type rather than had it happen by chance/accident".
(Advanced topic detail: printf actually converts the passed float to double, but we need not worry about that.)
You need input/7 to be performed with floating point math, rather than integer math.
Like this...
printf("Output: %f", (input / 7.0));
This link explains a bit better how C/C++ deals with mixing floats/doubles/ints etc.
Does one double promote every int in the equation to double?

How do I print in double precision?

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

How to use float.h macros to enhance the floating point precision

As I understood from this answer, there is a way to extend the precision using float.h via the macro LDBL_MANT_DIG. My goal is to enhance the floating point precision of double values so that I can store a more accurate number, e.g., 0.000000000566666 instead of 0.000000. Kindly, can someone give a short example of to use this macro so that I can extend the precision stored in the buffer?
Your comment about wanting to store more accurate numbers so you don't get just 0.000000 suggests that the problem is not in the storage but in the way you're printing the numbers. Consider the following code:
#include <stdio.h>
int main(void)
{
float f = 0.000000000566666F;
double d = 0.000000000566666;
long double l = 0.000000000566666L;
printf("%f %16.16f %13.6e\n", f, f, f);
printf("%f %16.16f %13.6e\n", d, d, d);
printf("%lf %16.16lf %13.6le\n", d, d, d);
printf("%Lf %16.16Lf %13.6Le\n", l, l, l);
return 0;
}
When run, it produces:
0.000000 0.0000000005666660 5.666660e-10
0.000000 0.0000000005666660 5.666660e-10
0.000000 0.0000000005666660 5.666660e-10
0.000000 0.0000000005666660 5.666660e-10
As you can see, using the default "%f" format prints 6 decimal places, which treats the value as 0.0. However, as the format with more precision shows, the value is stored correctly and can be displayed with more decimal places, or with the %e format, or indeed with the %g format though the code doesn't show that in use — the output would be the same as the %e format in this example.
The %f conversion specification, as opposed to %lf or %Lf, says 'print a double'. Note that when float values are passed to printf(), they are automatically converted to double (just as numeric types shorter than int are promoted to int). Therefore, %f can be used for both float and double types, and indeed the %lf format (which was defined in C99 — everything else was defined in C90) can be used to format float or double values. The %Lf format expects a long double.
There isn't a way to store more precision in a float or double simply by using any of the macros from <float.h>. Those are more descriptions of the characteristics of the floating-point types and the way that they behave than anything else.
The answer you cited only mentions that the macro is equal to the number of precision digits that you can store. It cannot in any way increase precision. But the macro is for "long doubles", not doubles. You can use the long double type if you need more precision than the double type:
long double x = 3.14L;
Notice the "L" after the number for specifying a long double literal.
Floating-point types are implemented in hardware. The precision is standardized across the industry and baked into the circuits of the CPU. There's no way to increase it beyond long double except an extended-precision software library such as GMP.
The good news is that floating-point numbers don't get bogged down in leading zeroes. 0.000000000566666 won't round to zero. With only six digits, you only even need a single-precision float to represent it well.
There is an issue with math.h (not float.h), where the POSIX standard fails to provide π and e with long double precision. There are a couple workarounds: GNU defines e.g. M_PIl and M_El, or you can also use the preprocessor to paste an l onto such literal constants in another library (giving the number long double type) and hope for spare digits.

C programming floating numbers?

So, I am reading a C prog. book and I read this exercise:
Write a program which asks the user to enter a dollars-and-cents amount, then displays the amount with 5% added?
Solution :
#include <stdio.h>
int main(void) {
float original_amount;
printf("Enter an amount: ");
scanf("%f", &original_amount);
printf("With tax added: $%.2f\n", original_amount * 1.05f);
return 0;
}
I know what .3f means (there should be 3 digits after...), but what does 1.05f mean?
The 1.05f does denote a floating point number with value approximately 1.05 (which is 105% = 100% + 5%). The %.2f is a format specifier and is something very different.
The multiplication with this number actually adds 5% to the value (value * 1.05 = value * (100% + 5%) = value + value * 5%).
Format specifiers occur in the first parameter of printf-like functions and tell the function how to output the argument corresponding to its position.
1.05f is a float type that has value 1.05
The program is apparently using multiplication by 1.05f as a way to add 5% to a number. But, because of representation error 1.05f is not exactly 1.05; it's a single-precsion floating point number close† to 1.05.
The float value closest to 1.05 is 1.0499999523162841796875 (assuming the usual 32-bit float format). Since you round the results you would have to use some fairly big numbers to see the effects of the error; try entering 100000000 when the program asks for amount:
Enter an amount: 100000000
With tax added: $104999992.00
If you used double precision instead of single precision, that is, double instead of float and 1.05 instead of 1.05f, the representation error would be smaller but it would still not be exactly 1.05, since this number cannot be represented exactly as the binary floating point numbers that our computers use.
You would get a correct result for 100000000, but still "incorrect" results for astronomically big numbers.
†) How close? From the standard:
For decimal floating constants, and also for
hexadecimal floating constants when
FLT_RADIX
is not a power of 2, the result is either
the nearest representable value, or the larger or smaller representable value immediately
adjacent to the nearest representable value, chosen in an implementation-defined manner.
It's the 5% part of your exercice. It's equal to: original_amout + (original_amout * 5.0 / 100.0).
it means 1.05 as float float you can take the f away it should work
printf has the prototype as int printf(const char *restrict format, ...);, it uses the const char *restrict format string to format the data printed.
You are confused between the format specifier %.2f which is passed as the 1st parameter to printf and the 1.05f passed as part of argument list. As you point out, first one is used for formatting. The argument list 1.05f is used for calculation purposes.The f indicates to the compiler you want to use a float or else by default it will be considered double datatype and the result of original_amount * 1.05f will be stored in a double.
It is sufficient to use a float when you know the number would fit in the float range.And to indicate this, you append a f to numbers in the argument list

Pointers in C programming with double precision

Ok so this what I must do but i can't make it work:
a) Change to float instead of integers. And assign 0.3 as starting value to "u".
b) Use double precision instead of integers. Asign 0.3x10^45 as starting value for "u".
c) Use characters instead of integers. Assign starting value as 'C' for "u".
#include <stdio.h>
main ()
{
int u = 3;
int v;
int *pu;
int *pv;
pu = &u;
v = *pu;
pv = &v;
printf("\nu=%d &u=%X pu=%X *pu=%d", u, &u, pu, *pu);
printf("\n\nv=%d &v=%X pv=%X *pv=%d", v, &v, pv, *pv);
}
I'll be really grateful if anyone could modify my code to do the things above. Thanks
This question is testing a few things. First do you know your types? You are expected to know that a floating pointing number is declared with float, a double precision number with double, and a character with char.
Second you are expected to know how to assign a literal value to those different types. For the float literal you are probably expected to use 0.3f, since without that suffix it would be double precision by default (although in this context it isn't going to make any difference). For the double, you are expected to know how to use scientific notation (the literal value should be 0.3e45). The character literal I would hope is fairly obvious to you.
Finally you are expected to know the various type characters used in the printf format specification. Both single and double precision numbers use the same type characters, but you have a choice of %e, %f or %g, depending on your requirements. I tend to use %g as a good general purpose choice, but my guess is they are expecing you to use %e for the double (because that forces the use of scientific notation) and possibly %f for the float - it depends what you have been taught. For a character you use %c.
Also, note that you should only be replacing the %d type characters in the format strings. The %X values are used to output a hexadecimal representation of the pointers (&u and pu). A pointer isn't going to change into a floating point value or a character just because the type that is being pointed to has changed - an address is always an integer when you are writing it out.

Resources