C++: How to round a double to an int?

488,674

Solution 1

add 0.5 before casting (if x > 0) or subtract 0.5 (if x < 0), because the compiler will always truncate.

float x = 55; // stored as 54.999999...
x = x + 0.5 - (x<0); // x is now 55.499999...
int y = (int)x; // truncated to 55

C++11 also introduces std::round, which likely uses a similar logic of adding 0.5 to |x| under the hood (see the link if interested) but is obviously more robust.

A follow up question might be why the float isn't stored as exactly 55. For an explanation, see this stackoverflow answer.

Solution 2

Casting is not a mathematical operation and doesn't behave as such. Try

int y = (int)round(x);

Solution 3

Casting to an int truncates the value. Adding 0.5 causes it to do proper rounding.

int y = (int)(x + 0.5);

Solution 4

It is worth noting that what you're doing isn't rounding, it's casting. Casting using (int) x truncates the decimal value of x. As in your example, if x = 3.9995, the .9995 gets truncated and x = 3.

As proposed by many others, one solution is to add 0.5 to x, and then cast.

Share:
488,674
midnightBlue
Author by

midnightBlue

Updated on July 11, 2022

Comments

  • midnightBlue
    midnightBlue almost 2 years

    I have a double (call it x), meant to be 55 but in actuality stored as 54.999999999999943157 which I just realised.

    So when I do

    double x = 54.999999999999943157;
    int y = (int) x;
    

    y = 54 instead of 55!

    This puzzled me for a long time. How do I get it to correctly round?

    • Blastfurnace
      Blastfurnace about 12 years
      You could add 0.5 to the number and then do your cast to let it truncate to an int. Do you need to round negative numbers?
    • c00000fd
      c00000fd almost 10 years
      You can use this preprocessor definition: #define ROUND_2_INT(f) ((int)(f >= 0.0 ? (f + 0.5) : (f - 0.5)))
    • Ruslan
      Ruslan almost 8 years
      Actually 54.999999999999943157 is 8 ULPs below exactly representable 55 if by double you mean binary64 from IEEE 754. So this is not how 55 is actually stored, it's the consequence of how imprecise your calculation of it was.
    • DragonLord
      DragonLord over 7 years
      Adding +0.5 to a negative input before turning it into an int will give the wrong answer. The correct quick-and-dirty way is to test the input sign for <0, and then SUBTRACT 0.5 from the negative inputs before turning them into an int. Most of the following answers do not explain this properly. Note high-accuracy procedures should use the new slower "round()" function.
    • Vadzim
      Vadzim over 7 years
    • plafratt
      plafratt over 7 years
      For me, the program to below prints "55". Am I doing something differently than you? #include<iostream> using namespace std; int main() { float x = 55; int y = (int) x; cout << y; }
    • midnightBlue
      midnightBlue over 7 years
      @plafratt It may be possible that your system's implementation of float is such that float x = 55 is stored as a value slightly greater than 55 instead. In this case (int) x would seem to 'round down' correctly to 55, and not 54, as in my case.
    • plafratt
      plafratt over 7 years
      Oh ok. For reference, the code below gives this output: "55 55.00000000000000000000". #include<iostream> #include<iomanip> using namespace std; int main() { float x = 55; int y = (int) x; cout << y << " " << fixed << setprecision(20) << x << "\n"; } Changing the "float x = 55;" to "float x = 55.1;" gives me the output "55 55.09999847412109375000"
    • raaj
      raaj about 4 years
    • hgrey
      hgrey almost 4 years
      the question in not equivalent to referenced question as it asking for type conversion as well
  • Keith Thompson
    Keith Thompson about 12 years
    The cast is unnecessary; the result will be implicitly converted to int.
  • midnightBlue
    midnightBlue about 12 years
    it would work equally as well with just int y=x+0.5; though right?
  • MK.
    MK. about 12 years
    I could never remember the C type promotion rules and I think that it doesn't hurt to state type casts explicitly everywhere, them being such a sticky issue.
  • midnightBlue
    midnightBlue about 12 years
    Thank you, actually I only just realised I even need to round (I am using only integers in my program)
  • Steve Fallows
    Steve Fallows about 12 years
    What library is round part of? AFAIK it's not in the C++ standard library. ceil and floor are available.
  • MK.
    MK. about 12 years
    @Steve #include <math.h>, STANDARDS The round() , lround() , and llround() functions conform to ISO/IEC 9899:1999(E).
  • Admin
    Admin about 12 years
    I wouldn't use the phrase "round down", because that could be interpreted as rounding -0.5 to -1.
  • Steve Fallows
    Steve Fallows about 12 years
    @MK - Well that's actually C not C++ right? I referred to this: cplusplus.com/reference/clibrary/cmath
  • GManNickG
    GManNickG about 12 years
    @SteveFallows: It exists in C++11.
  • Keith Thompson
    Keith Thompson about 12 years
    @MK.: It's not a promotion, it's just an implicit conversion. An assignment, initialization, or parameter passing will implicitly convert any numeric type to any other numeric type. Unnecessary casts can be harmful. For example, n = (int)round(x); looks ok -- but what if n is of type long?
  • Verax
    Verax almost 11 years
    -1 This method does not take into consideration negative numbers.
  • mehfoos yacoob
    mehfoos yacoob over 10 years
    not valid for negative numbers, as mentioned in one of the comments above. Can use 'floor' instead of cast if you are doing this.
  • mehfoos yacoob
    mehfoos yacoob over 10 years
    As @Verax mentioned, this does not work for negative numbers as cast truncates toward 0. You may use the same logic with 'floor' instead as it truncates towards -infinity.
  • Nick X Tsui
    Nick X Tsui almost 10 years
    This answer is wrong. It will give you wrong answer if the number is negative.
  • Moritz
    Moritz almost 10 years
    @NickXTsui did you see the last sentence? "Note that this will not work for negative numbers."
  • Nick X Tsui
    Nick X Tsui almost 10 years
    @Moritz; Oh sorry, I will upvote you. My apologies.
  • Albert Renshaw
    Albert Renshaw over 9 years
    This forces numbers up though... 54.000000000000001 will become 55.
  • Henry Henrinson
    Henry Henrinson over 9 years
    -1 this is a hacky solution at best. zik's answer is much better as it uses a library function: works on negative numbers, doesn't do weird casting and it's explicit about it's intention.
  • Moritz
    Moritz over 9 years
    @HenryHenrinson ceil()/floor() also adds another level to the call stack (although I suspect that a modern compiler will inline it for you,) makes you include a library header and generally introduces more overhead. I don't think one is necessarily worse than the other without knowing what the OP is trying to accomplish. Also, I don't think casting from floating-point to int explicitly is that "weird"...whether you see it or not, that type conversion has to happen somewhere along the line :)
  • Henry Henrinson
    Henry Henrinson over 9 years
    @Moritz One can perform rounding and still return a double. Regardless, the point here is that the code is not explicit about what sort of casting it does. Does it take floor, ceil, rounds it, or does it just interpret the bits at the memory location referenced by the double as ints? Writing the code like this needlessly makes the reader remember what the conversion rules are. I agree that there are places where this code makes sense, but imagine someone googles "how to round c++" and ends on this page. IMO, the best answer for that situation is the one below.
  • cp.engr
    cp.engr over 8 years
    @AlbertRenshaw, right - which means this answer is wrong.
  • jacknad
    jacknad about 8 years
    I prefer positive numbers
  • Ruslan
    Ruslan almost 8 years
    What do you mean by stored as stored as 54.999999...? 55 is exactly representable in binary32 from IEEE 754. Its representation is 0x425c0000. As you can see, it's more than exact: It has plenty of digits to store some fractional part you add to it. And it's especially true of 0.5, which is a power of two.
  • ACyclic
    ACyclic over 7 years
    This is inaccurate & possibly slow. See clang-tidy for an explanation : clang.llvm.org/extra/clang-tidy/checks/…
  • Pac0
    Pac0 over 5 years
    @ACyclic unfortunately, the link you provided is dead.
  • ACyclic
    ACyclic over 5 years
    @Pac0 Updated link on why this is inaccurate : releases.llvm.org/5.0.2/tools/clang/tools/extra/docs/clang-t‌​idy/…
  • markokstate
    markokstate almost 5 years
    @ACyclic That link just states it's bad but doesn't provide any suggestions to the problem.
  • Qiangzini
    Qiangzini over 4 years
    In both C99 and C++11, double round (double x); Therefore, the cast is indeed necessary. Link:cplusplus.com/reference/cmath/round
  • simplename
    simplename about 2 years
    if you use std::round(double arg) cast is necessary; but if you use std::lround(double arg) cast is not needed