-5

I want to round a float/double number to n decimal places. But not in printing, but in general.
e.g: User's input is: 2.3891 3, so the output should be 2.389
or if the user's input 5.98441 4, the output should be: 5.9844

#include <stdio.h>
#include <math.h>

int main () {

float num;
int decimals;

scanf("%f%d", &num, &decimals); //5.2381 2

int res = num; // res = 5

int power = 1;
int i = 0;
for(i = 0; i < decimals; i++)
    power*=10; // 1 * 10 * 10

int num3 = num * power; // num3 = 523
int num2 = num3 % power;//

float a = num2*1.0 / power*1.0;
// float a = 23*1.0/13.0;
printf("%f %d\n", a, power);

a = res + a;

printf("%f", a);

return 0;
}

As the output here i get: 2.390000. I don't want to have these zeros and i don't want to use fixed %.2f. What am I missing?

Strahinja
  • 440
  • 9
  • 26
  • 2
    What you're asking for is impossible. Floating point numbers don't have decimal places. – melpomene Oct 07 '18 at 07:58
  • 2
    @melpomene "Binary floating point numbers" to be precise, because [decimal floating point numbers](https://en.wikipedia.org/wiki/Decimal_floating_point) do exist. But you are correct. –  Oct 07 '18 at 08:07
  • 4
    You can use `printf("%g", a);` which will [remove trailing zeroes](https://stackoverflow.com/a/277779/7501501). – Yonlif Oct 07 '18 at 08:10
  • 2
    Always use `double` (forget `float` exists). `double roundn(double x, int n) { double b = pow(10, n); int c = (x + 0.5) * b; /*mind overflow*/ return c / b; }` – pmg Oct 07 '18 at 08:22
  • @pmg, why not use `float`? – Ulrich Eckhardt Oct 07 '18 at 08:23
  • 2
    @UlrichEckhardt: the only thing `float` is better than `double` is space requirement. `double` is more precise, `double` is (usually) faster, `double` avoids auto conversions to `double` all over the place. And 4 extra bytes per floating-point variable will not make an impact in your executable (unless, of course, you need huge array(s)). In `float x = 42, y; y = x * 2;` there are 2 auto conversions: first, before the multiplication, x is converted to double; afterwards the result is converted to float. – pmg Oct 07 '18 at 08:33
  • @pmg: why would `double` be faster than `float`? It is quite the contrary. Especially when you have SIMD. In `y = x * 2;`, there are no `double` conversions. `2` is converted to `float` (it's a no-op, as `2.0f` will be used by the compiler), and then the multiplication will be done in `float`, not in `double`. Your recommendation "forget float exists") is wrong in my opinion. `double` should only be used when the extra precision is needed, otherwise use `float`. – geza Oct 07 '18 at 09:05
  • 1
    @geza I am with "pmg", `float` is so 20th century: never use `float` unless system constraints dictate it. Always work to the best precision available, and truncate or round only for output. You don't work with `short` unless there is a very good reason there too. I think the main reason people work with `float` is because of antiquated teaching material. – Weather Vane Oct 07 '18 at 09:37
  • @geza: https://stackoverflow.com/questions/5738448/is-float-slower-than-double-does-64-bit-program-run-faster-than-32-bit-program – pmg Oct 07 '18 at 09:58
  • @pmg: where does that answer say that double is faster? float has the same speed, or faster. Two main factors: cache, and SIMD. `double` needs twice as much memory bandwidth, and if your calculation gets autovectorized, it will be slower with the double version. – geza Oct 07 '18 at 10:16
  • @WeatherVane: `float` is adequate for most purposes. There is nothing antiquated with it. As I've said, one should use `double`, when the extra precision is needed. And indeed, if I have to store a lot of numbers, which surely fits in the range of -32768-32767, I'll use `short`. Why should I use `int`? Choose your types properly. – geza Oct 07 '18 at 10:20
  • @geza because `int` is the natural size of the machine, and a `short` will likely use the same storage space as `int` anyway. With embedded software of course you often do need to be tight with memory use. – Weather Vane Oct 07 '18 at 10:29
  • @WeatherVane: no. `short` usually takes 2 bytes, while `int` takes 4. – geza Oct 07 '18 at 10:31
  • @geza not if it is aligned. On my system two local `short` variables have `sizeof` 2 but consume 4 bytes on the stack each. So you might as well stick to `int`. That is with an alignment of `4`. If the alignment is `8` then `float` will take the same amount of memory as `double`. – Weather Vane Oct 07 '18 at 10:33
  • @WeatherVane: `short` needs only an alignment of 2. Which compiler do you use? `float` has an alignment of 4 usually. For fundamental types, alignment is usually the same/less than the sizeof. – geza Oct 07 '18 at 10:40
  • @pmg: not to mention, that for a quality implementation, with SSE, transcendental functions are definitely slower with `double`. I've just done a little benchmark of `sin`: it is 2.4x slower with double than float. (And the linked answer isn't quite right: x87 precision can be set to 32-bit/64-bit, and for certain operations (sqrt, division), it will be faster). – geza Oct 07 '18 at 10:45
  • @geza bear in mind too that the C library does not provide a function to output `float`. In variadic functions such as `printf`, a `float` is promoted to `double` which is also the natural default size used by the compiler for a numeric constant such as `4.2` which, without qualifying, is of type `double`. – Weather Vane Oct 07 '18 at 10:51
  • @WeatherVane: Yes. It needs a little attention to write `4.2f`. When I learned this stuff, it was strange to me, that I always have to put that extra `f` after a floating-point constant. Now, I get used to it, I automatically put it. And there are helpful warnings here, like `-Wdouble-promotion`. – geza Oct 07 '18 at 10:56

3 Answers3

2

In general, this task is impossible, because the IEEE 754 conversion is the representation of a float in binary either float or double. So the upper line scanf("%f%d", &num, &decimals); //5.2381 2 does transform a decimal (base 10) number convert to a binary floating point number and this transformation is not exaxt in general, because you have only a limit number of bits. You may reduce the amount of bits (binary) but this is not defined in decimal system. Printing a floating (double) precision number, there is a second imprecision because of converting binary to decimal floating-point calculation.

Tom Kuschel
  • 695
  • 8
  • 19
1

There's two things here you're doing: 1) calculating a rounded value of a number, and 2) printing that number.

Calculating the rounded value

You're pretty much doing this right. Be aware that when implictly converting a float to an int, C does a truncation, not a rounding so:

float f = 1.9;
int i = f;

sets i to 1, not 2. In your case, if your input is "1.229 2" you're calculating a value of 1.22, rather than 1.23. This may be what you want, but may not. If you want to round off instead of towards zero you might want to change this:

int num3 = num * power;

to:

int num3 = 0.5 + num * power;

Printing the rounded value

Once you've calculated the value, you're printing it. If you want to print only the number of decimal placed you've rounded to, you can use the precision field of printf() like this:

printf("%.*f\n", decimals, a);
Tim
  • 9,171
  • 33
  • 51
  • 1
    In fact, if it is only the output representation that needs to be rounded, then use the printing technique you correctly espoused; the `printf()` function will round correctly. – Jonathan Leffler Oct 07 '18 at 18:07
0

In general, this is not possible. Floating point in C and C++ ultimately is specified in terms of a base, mantissa, sign, and exponent.

Decimal floating point is base 10. It is exceedingly rare in practice on modern hardware. Some early computing hardware (like ENIAC, created in 1946) supported decimal floating point. However, such a representation is quite rare in modern hardware.

The most common floating point representations on modern hardware use a base of 2 (i.e. binary). Binary floating point cannot represent all decimal fractions. Try to represent the decimal value 0.1 using a sum of negative powers of 2 (like 1/2, 1/4, 1/8, etc). You will find that the representation of 0.1 involves an infinite series in decimal. The reason is analogous to the fact that the fraction 1/3 cannot be represented in a finite number of decimal places (i.e. 0.33333.... where the digit 3 repeats forever).

Irrational values (like sqrt(2.0), pi, and others) also cannot be represented exactly in any number base with a finite number of digits. So it is not possible to design a floating point type of fixed and finite size which can hold such values exactly.

Peter
  • 35,646
  • 4
  • 32
  • 74
  • 2
    Decimal is not “exceedingly” rare in modern hardware. It is not present in common personal-use computers. IBM, for example, makes decimal hardware for commercial/industrial use. – Eric Postpischil Oct 07 '18 at 11:52