相关文章推荐
心软的柿子  ·  visual studio - Do I ...·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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?

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? – Blastfurnace Mar 14, 2012 at 3:03 You can use this preprocessor definition: #define ROUND_2_INT(f) ((int)(f >= 0.0 ? (f + 0.5) : (f - 0.5))) – c00000fd May 1, 2014 at 1:41 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. – Ruslan Jul 15, 2016 at 12:07 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. – DragonLord Aug 13, 2016 at 22:37

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.

I wouldn't use the phrase "round down", because that could be interpreted as rounding -0.5 to -1. – user1084944 Mar 14, 2012 at 3:16 -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. – Henry Henrinson Oct 2, 2014 at 14:33 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. – Ruslan Jul 15, 2016 at 12:03 This is inaccurate & possibly slow. See clang-tidy for an explanation : clang.llvm.org/extra/clang-tidy/checks/… – ACyclic Nov 2, 2016 at 13:36 @Pac0 Updated link on why this is inaccurate : releases.llvm.org/5.0.2/tools/clang/tools/extra/docs/clang-tidy/… – ACyclic Nov 16, 2018 at 18:47 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. – MK. Mar 14, 2012 at 3:10 @Steve #include <math.h>, STANDARDS The round() , lround() , and llround() functions conform to ISO/IEC 9899:1999(E). – MK. Mar 14, 2012 at 3:14 @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? – Keith Thompson Mar 14, 2012 at 6:23 In both C99 and C++11, double round (double x); Therefore, the cast is indeed necessary. Link:cplusplus.com/reference/cmath/round – Qiangzini Jan 2, 2020 at 23:00 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 Aug 14, 2013 at 10:54

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.

Thank you, actually I only just realised I even need to round (I am using only integers in my program) – midnightBlue Mar 14, 2012 at 3:11 double x=54.999999999999943157; int y=ceil(x);//The ceil() function returns the smallest integer no less than x return 0;