How do I restrict a float value to only two places after the decimal point in C?

916,949

Solution 1

If you just want to round the number for output purposes, then the "%.2f" format string is indeed the correct answer. However, if you actually want to round the floating point value for further computation, something like the following works:

#include <math.h>

float val = 37.777779;

float rounded_down = floorf(val * 100) / 100;   /* Result: 37.77 */
float nearest = roundf(val * 100) / 100;  /* Result: 37.78 */
float rounded_up = ceilf(val * 100) / 100;      /* Result: 37.78 */

Notice that there are three different rounding rules you might want to choose: round down (ie, truncate after two decimal places), rounded to nearest, and round up. Usually, you want round to nearest.

As several others have pointed out, due to the quirks of floating point representation, these rounded values may not be exactly the "obvious" decimal values, but they will be very very close.

For much (much!) more information on rounding, and especially on tie-breaking rules for rounding to nearest, see the Wikipedia article on Rounding.

Solution 2

Using %.2f in printf. It only print 2 decimal points.

Example:

printf("%.2f", 37.777779);

Output:

37.77

Solution 3

Assuming you're talking about round the value for printing, then Andrew Coleson and AraK's answer are correct:

printf("%.2f", 37.777779);

But note that if you're aiming to round the number to exactly 37.78 for internal use (eg to compare against another value), then this isn't a good idea, due to the way floating point numbers work: you usually don't want to do equality comparisons for floating point, instead use a target value +/- a sigma value. Or encode the number as a string with a known precision, and compare that.

See the link in Greg Hewgill's answer to a related question, which also covers why you shouldn't use floating point for financial calculations.

Solution 4

How about this:

float value = 37.777779;
float rounded = ((int)(value * 100 + .5) / 100.0);

Solution 5

printf("%.2f", 37.777779);

If you want to write to C-string:

char number[24]; // dummy size, you should take care of the size!
sprintf(number, "%.2f", 37.777779);
Share:
916,949

Related videos on Youtube

Sakib Arifin
Author by

Sakib Arifin

CS Freshman.

Updated on March 07, 2020

Comments

  • Sakib Arifin
    Sakib Arifin about 4 years

    How can I round a float value (such as 37.777779) to two decimal places (37.78) in C?

    • Pavel Minaev
      Pavel Minaev almost 15 years
      You cannot properly round the number itself, because float (and double) aren't decimal floating-point - they are binary floating-point - so rounding to decimal positions is meaningless. You can round the output, however.
    • Brooks Moses
      Brooks Moses almost 15 years
      It's not meaningless; it's inexact. There's quite a difference.
    • Truthseeker Rangwan
      Truthseeker Rangwan almost 10 years
      What kind of rounding you're expecting? Half-up or Rounding to nearest even?
  • Pavel Minaev
    Pavel Minaev almost 15 years
    This truncates at decimal point (i.e. will produce 37), and he needs to round to two places after the decimal point.
  • Brooks Moses
    Brooks Moses almost 15 years
    Rounding to two places after the decimal point is a trivial variation, though (but still should be mentioned in the answer; ZeroCool, want to add an edit?): float roundedValue = ceilf(valueToRound * 100.0) / 100.0;
  • Brooks Moses
    Brooks Moses almost 15 years
    This is no different from saying "there's no way to divide two floats and get a float, because the divided result may not be representable," which may be precisely true but is irrelevant. Floats are always inexact, even for something as basic as addition; the assumption is always that what you actually get is "the float that most closely approximates the exact rounded answer".
  • Brooks Moses
    Brooks Moses almost 15 years
    Upvoted for addressing what may be the question behind the question (or the question that should have been behind the question!). That's a rather important point.
  • Andrew Keeton
    Andrew Keeton almost 15 years
    What I meant is that you cannot round a float to n decimal places and then expect the result always have n decimal places. You will still get a float, just not the one you expected.
  • John Carter
    John Carter almost 15 years
    -1: a) this won't work for negative numbers (ok, the example is positive but still). b) you don't mention that it's impossible to store the exact decimal value in the float
  • Daniil
    Daniil almost 15 years
    @therefromhere: (a) You're right (b) What is this? A high school test?
  • aib
    aib almost 15 years
    @Sinan: Why the edit? @AraK: No, you should take care of the size :). Use snprintf().
  • Michael Haren
    Michael Haren almost 15 years
    @aib: I would guess because /**/ are C style comments and the question is tagged for C
  • oneAday
    oneAday over 14 years
    C89 only allowed /**/-style, C99 introduced support for //-style. Use a lame/old compiler (or force C89 mode) and you'll be unable to use //-style. Having said that, it's 2009, let's consider them both C and C++ style.
  • Anonymous White
    Anonymous White over 11 years
    Actually 37.78 can be presented exactly by floating point. Float has 11 to 12 digit for precission. That should be enough to address 3778 377.8 or all kind of 4 decimal digit.
  • John Carter
    John Carter over 11 years
    @HaryantoCiu yeah fair enough, I've editted my answer a little.
  • Andy
    Andy over 10 years
    How come this solution isn't more popular? This works exactly how it should with minimal code. Is there some caveat with it?
  • albert
    albert over 10 years
    This way is better because there is no loss of precision.
  • Admin
    Admin about 10 years
    Can it be modified to support rounding to arbitrary precision?
  • Dale Hagglund
    Dale Hagglund about 10 years
    @slater When you say 'arbitrary precision', are you asking about rounding to, eg, three instead of two decimal places, or using libraries that implement unbounded precision decimal values? If the former, make what I hope are obvious adjustments to the constant 100; otherwise, do the exact same calculations shown above, just with whatever multi precision library you're using.
  • Admin
    Admin about 10 years
    @DaleHagglung The former, thank you. Is the adjustment to replace 100 with pow(10, (int)desiredPrecision)?
  • Dale Hagglund
    Dale Hagglund about 10 years
    Yep. To round after k decimal places, use a scale factor of 10^k. This should be really easy to see if you write out some decimal values by hand and play around with multiples of 10. Suppose you're working with the value 1.23456789, and want to round it to 3 decimal places. The operation available to you is round to integer. So, how do you move the first three decimal places so that they're left of the decimal point? I hope it's clear that you multiply by 10^3. Now you can round that value to an integer. Next, you put the three low order digits back by dividing by 10^3.
  • Ms. Nobody
    Ms. Nobody almost 10 years
    Can I make this work with doubles too somehow? Doesn't seem to do the job I want :( (using floor and ceil).
  • Dale Hagglund
    Dale Hagglund almost 10 years
    It ought to work fine, even if all you do is change 'float' to 'double'. Can you describe what problems your having?
  • chux - Reinstate Monica
    chux - Reinstate Monica almost 10 years
    @albert This also has the advantage of no loss of float range as val * 100 could overflow.
  • Dale Hagglund
    Dale Hagglund almost 10 years
    You're quite right that it fails for negative numbers. I wasn't aware of 'roundf', though, so thanks.
  • Apeiron
    Apeiron over 9 years
    would there any any advantage of doing roundf(val*100)/100 vs round(val / 1e-2) * 1e-2 ?
  • Dale Hagglund
    Dale Hagglund over 9 years
    @Apeiron: I think they'll be exactly the same after the compiler converts the integer constant 100 to a floating point value. However I'd argue the former is simpler to read.
  • Muhammad Adnan
    Muhammad Adnan almost 9 years
    :D @Danil nice reply :)
  • smileyborg
    smileyborg about 8 years
    Here's your generic macro that will work for arbitrary decimal places: #define ROUND_TO_DECIMAL_PLACES(x, decimal_places) (roundf(x * 1e##decimal_places) / 1e##decimal_places)
  • muhammad tayyab
    muhammad tayyab almost 8 years
    why you added 0.5?
  • Daniil
    Daniil almost 8 years
    It's necessary to follow rounding rules.
  • Ken
    Ken over 7 years
    what's the difference between roundf and round?
  • Parag Bafna
    Parag Bafna about 7 years
    @Ken float roundf(float); double round(double);
  • Shmil The Cat
    Shmil The Cat about 7 years
    rounding rules in the context of @Daniil comment are round to nearest
  • Eric Postpischil
    Eric Postpischil over 5 years
    This truncates, but the question requests rounding. Additionally, it is subject to rounding errors in floating-point operations.
  • Mark Amery
    Mark Amery almost 5 years
    This can return wrong results if the number you're trying to round is very close to the threshold where the result changes, because the multiplication by 100 can change whether it should round up or down. For instance, the number 0.01499999999999999944488848768742172978818416595458984375 can be exactly represented as a double, and the mathematically correct result if you round it to 2 dp using to-nearest rounding is 0.01, but if you round it in the way shown here, you'll get 0.02, because 0.01499999999999999944488848768742172978818416595458984375 * 100 gives exactly 1.5 which rounds upwards.
  • Mark Amery
    Mark Amery almost 5 years
    -1 for four reasons: 1) the lack of explanation, 2) the vulnerability to buffer overflow - this will overflow, and therefore quite possibly crash, if dval is huge 3) the weird if / else block where you do exactly the same thing in each branch, and 4) the overcomplicated use of sprintf to build the format specifier for a second sprintf call; it's simpler to just use .* and pass the double value and number of decimal places as arguments to the same sprintf call.
  • Dale Hagglund
    Dale Hagglund almost 5 years
    @MarkAmery Thanks for the very interesting example. In hindsight, given all the vagaries of floating point arithmetic I shouldn't be surprised. Do you happen to know if accurate rounding is provided in IEEE floating point?
  • Mark Amery
    Mark Amery almost 5 years
    @DaleHagglund It's provided by snprintf, and so in my answer I suggest that the only easy way to solve this problem correctly is to convert to a string with snprintf and then parse the string.
  • Dale Hagglund
    Dale Hagglund almost 5 years
    +1 for a concrete example of what goes wrong with my answer and those similar to it, thanks to the weirdness of IEEE floating point, and providing a straightforward alternative. I was peripherally aware, quite a long time back, of lot of effort put into print and friends to me them safe for round-tripping floating point values. I would guess that the work done then might be showing up here.
  • Dale Hagglund
    Dale Hagglund almost 5 years
    @MarkAmery Very nice. Now, if you'll permit me a moment of silence for this answer which has been, one might say, a steady earner for a long time.
  • Dale Hagglund
    Dale Hagglund almost 5 years
    Ahem... Sorry for the word salad near the end there, which it's now too late to edit. What I meant to say was "... a lot of effort put into printf and friends to make them safe ..."
  • Minhas Kamal
    Minhas Kamal over 4 years
    dynamic precision: printf("%.*f", (int)precision, (double)number);
  • user207421
    user207421 over 3 years
    This technique doesn't work at all in 90% of cases. Try it.
  • Raleigh L.
    Raleigh L. over 2 years
    Your first statement might sound true initially, but many languages do allow you to round one float into another. Consider Python's round() function for example: pythontutorial.net/advanced-python/python-rounding It's genuinely surprisingly that something as basic as this was omitted from C++.