0

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);

}
  • Store the float as two integers, as integer and fractional part or as integer part and exponent. You may interest yourself in [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken). – KamilCuk Nov 13 '18 at 13:55
  • 4
    Scanf with `%f` reads float. With `%lf` it reads a double. Also, `double` has higher precision and range than `float` so it doesn't make sense to talk about floats being "rounded down" to doubles. – interjay Nov 13 '18 at 13:56
  • 2
    By the way, `number` is uninitialized in your code. – interjay Nov 13 '18 at 13:56
  • @KamilCuk This works but you need special functions as soon as you start computing them. – Jean-Marc Zimmer Nov 13 '18 at 13:56
  • How can I do it? I don't know how many digits the user is exactly going to input, so like he could write just 60 or 60.1 or 60.4591 @KamilCuk –  Nov 13 '18 at 13:57
  • @interjay well if the value scanned is like 99.2, it gets "rounded down" to 99.1999etc I know that it does this because of something related to the values representable by the power or 2 or something like this –  Nov 13 '18 at 13:59
  • 1
    Neither 60.4591 nor 99.2 can be represented exactly with IEEE 754 floats. There is no rounding involved. Make sure to read the answers to the question linked in the very first comment. – Swordfish Nov 13 '18 at 14:02
  • @Swordfish I get why that happens but I still don't get how to print out exactly the value that gets scanned –  Nov 13 '18 at 14:04
  • @FoxyIT I would handle all the cases and would use a function like `getchar()` or similar to read char by char. You can even get away with scanf, using like `if (sscanf(line, "%d\n", &decimal) == 1) { ... } else if (sscanf(line, "%d.\n", &decimal) == 1) { ... } else if (sscanf(line, "%d.%d\n", &decimal, &fractional) == 2) { .. }` and so on. `%f` also supports strings like `nan` or `infinity`, you can handle that too. – KamilCuk Nov 13 '18 at 14:06
  • @FoxyIT if you want to print exactly what gets scanned, save that to a string (char array). That's the only way. – KamilCuk Nov 13 '18 at 14:06
  • It sounds like you have things backwards. A float doesn't get "rounded up or down" to a double. The opposite is sometimes true. Doubles are bigger than floats, hence the name. – Lightness Races in Orbit Nov 13 '18 at 14:08
  • @FoxyIT If you want an exact representation you have to use a data type that is capable of providing that. `float` and `double` do not. If your program is not only about reading and writing which can be achieved by storing the "number" in a string, you might want to look into libraries like [GNU MP](https://gmplib.org/). – Swordfish Nov 13 '18 at 14:12

1 Answers1

0

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.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Thanks for the further clarification! Also the g format worked perfectly. One more question: if the printf automatically promotes all float to doubles once it prints them out, isn't there a way to cast the variable into a float before it gets printed out? Also, is it correct to say that "float a = 4.21" is treated as a double by the computer while "float a = 4.21f" is treated as a float? –  Nov 13 '18 at 17:39
  • @FoxyIT, your variable `a` **is** a `float`, regardless of the type of the value with which you initialize it, or the type of any value you later assign to it. It stores `float`s and only `float`s, and conversion to type `float` upon initialization or assignment is automatic. But when you specify that variable as an argument to `printf()`, the value read from it is promoted to type `double` for delivery to the function. The same would happen to the result of a redundant cast. But that conversion is value-preserving; I don't understand why you're fixating on it. – John Bollinger Nov 13 '18 at 18:00
  • Then why is it better to specify "f" at the end of the value of a float? What's its purpose? –  Nov 13 '18 at 18:37
  • 1
    @FoxyIT, a floating-point constant ending in `f` or `F` has type `float`, whereas one without a suffix has type `double`. The only reason to prefer the former for initializing a variable of type `float` is to silence compiler warnings about loss of precision. But using `float` literals instead in such contexts does not improve precision; it just demonstrates to the compiler's satisfaction that you really do want the lesser precision of a `float` rather than the greater precision of a `double`. – John Bollinger Nov 13 '18 at 18:51