How do I restrict a float value to only two places after the decimal point in C?
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);
Related videos on Youtube
Comments
-
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 almost 15 yearsYou cannot properly round the number itself, because
float
(anddouble
) 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 almost 15 yearsIt's not meaningless; it's inexact. There's quite a difference.
-
Truthseeker Rangwan almost 10 yearsWhat kind of rounding you're expecting? Half-up or Rounding to nearest even?
-
-
Pavel Minaev almost 15 yearsThis truncates at decimal point (i.e. will produce 37), and he needs to round to two places after the decimal point.
-
Brooks Moses almost 15 yearsRounding 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 almost 15 yearsThis 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 almost 15 yearsUpvoted 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 almost 15 yearsWhat 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 afloat
, just not the one you expected. -
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 almost 15 years@therefromhere: (a) You're right (b) What is this? A high school test?
-
aib almost 15 years@Sinan: Why the edit? @AraK: No, you should take care of the size :). Use snprintf().
-
Michael Haren almost 15 years@aib: I would guess because /**/ are C style comments and the question is tagged for C
-
oneAday over 14 yearsC89 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 over 11 yearsActually 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 over 11 years@HaryantoCiu yeah fair enough, I've editted my answer a little.
-
Andy over 10 yearsHow come this solution isn't more popular? This works exactly how it should with minimal code. Is there some caveat with it?
-
albert over 10 yearsThis way is better because there is no loss of precision.
-
Admin about 10 yearsCan it be modified to support rounding to arbitrary precision?
-
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 about 10 years@DaleHagglung The former, thank you. Is the adjustment to replace 100 with pow(10, (int)desiredPrecision)?
-
Dale Hagglund about 10 yearsYep. 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 almost 10 yearsCan I make this work with
doubles
too somehow? Doesn't seem to do the job I want :( (usingfloor
andceil
). -
Dale Hagglund almost 10 yearsIt ought to work fine, even if all you do is change 'float' to 'double'. Can you describe what problems your having?
-
chux - Reinstate Monica almost 10 years@albert This also has the advantage of no loss of
float
range asval * 100
could overflow. -
Dale Hagglund almost 10 yearsYou're quite right that it fails for negative numbers. I wasn't aware of 'roundf', though, so thanks.
-
Apeiron over 9 yearswould there any any advantage of doing
roundf(val*100)/100
vsround(val / 1e-2) * 1e-2
? -
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 almost 9 years:D @Danil nice reply :)
-
smileyborg about 8 yearsHere'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 almost 8 yearswhy you added 0.5?
-
Daniil almost 8 yearsIt's necessary to follow rounding rules.
-
Ken over 7 yearswhat's the difference between roundf and round?
-
Parag Bafna about 7 years@Ken float roundf(float); double round(double);
-
Shmil The Cat about 7 yearsrounding rules in the context of @Daniil comment are round to nearest
-
Eric Postpischil over 5 yearsThis truncates, but the question requests rounding. Additionally, it is subject to rounding errors in floating-point operations.
-
Mark Amery almost 5 yearsThis 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 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 weirdif
/else
block where you do exactly the same thing in each branch, and 4) the overcomplicated use ofsprintf
to build the format specifier for a secondsprintf
call; it's simpler to just use.*
and pass the double value and number of decimal places as arguments to the samesprintf
call. -
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 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 withsnprintf
and then parse the string. -
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 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 almost 5 yearsAhem... 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 over 4 yearsdynamic precision:
printf("%.*f", (int)precision, (double)number);
-
user207421 over 3 yearsThis technique doesn't work at all in 90% of cases. Try it.
-
Raleigh L. over 2 yearsYour 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++.