[SOLVED] Double to Int
-
Hello
If I try to cast a double with one decimal place to an int like this,
@intVariable = (int)(doubleVariable100);@ or
@intVariable = static_cast<int>(doubleVariable100);@I get from time to time an error with the cast. E.g. if I want to cast the double 4.2 into the int 420, I get 419 with this method. One solution would be to add 0.001 to every double, but I think this isn't really proper. Is there some other possibility to avoid this error.
Thx for help.
-
try this: @intVariable = static_cast<int>(doubleVariable + .5f) * 100@
In other words (int)1.1f = 1 and (int)1.9f = 1
http://www.cs.tut.fi/~jkorpela/round.html -
[quote author="cincirin" date="1306928926"]try this: @intVariable = static_cast<int>(doubleVariable + .5f) * 100@
In other words (int)1.1f = 1 and (int)1.9f = 1[/quote]I think this piece of code will give you 400 with an input value of 4.2... The multiplication has to be inside the static_cast as well. I'd rather try :
@intVariable = static_cast<int>(doubleVariable * 100. + .5) @
Note that I also changed .5f into .5, since doubleVariable is (I think) a double and not a float.
-
As Johan Solo said:
4.2 -> int = 4 *100 = 400;
Correctly arranged it comes to this:
@intVariable = static_cast<int>(doubleVariable *100 + .5)@
That looks like the same solution as to add 0.001. The question is why does it cast a double like 420.0 to the int 419? And how can this cast error else be resolved instead of adding half or a bit of an int?
-
The problem is because of floating point representation in any programming language. The conversion from double to int is just truncating without rounding.
-
[quote author="luggi" date="1306929905"]That looks like the same solution as to add 0.001. The question is why does it cast a double like 420 to the int 419? And how can this cast error else be resolved instead of adding half or a bit of an int?[/quote]
It's a bit more clever that just adding .001, it ensures that the rounding will be done properly. When you cast a double / float value into a integer, no rounding is performed, the biggest integer value smaller than your floating point value is returned (the "floor function":http://www.cplusplus.com/reference/clibrary/cmath/floor/). Another complication is that some numbers don't have an exact representation on a float / double. For instance 0.1 is 0.00011001100110011… (see "here":http://www.learncpp.com/cpp-tutorial/25-floating-point-numbers/).
-
Okay thx. So finally I can assume that to add 0.5 is the best method to solve this problem.
-
[quote author="luggi" date="1306930544"]Okay thx. So finally I can assume that to add 0.5 is the best method to solve this problem.[/quote]
You might want to be careful. Just adding 0.5 is not always the solution. For negative numbers you run into the opposite problem.
A typical solution for rounding is:
@
inline double nint (double x)
{
return x < 0 ? ceil (x - 0.5) : floor (x + 0.5);
}
@ -
Isn't there any method in Qt that does exactly this? I use this quiet a lot and it would be useful if I can apply it directly to the double.
-
I cannot tell whether such a function exists in Qt, but I think you should just define a function which uses koahnig's code, maybe you want the function to return an int directly.
-
Not to my knowledge. I guess a lot of programmers are using the line directly or have it somewhere in there headers. Rounding is nothing Qt specific. It is more basic programming in any programming language.
-
Look at qRound() and qRound64() in qglobal.h.
-
That's it, thx!
-
I don't think the (int) type conversion behavior was adequately explained. I ran into a similar problem converting an old C++ project into Qt.
The original code also had an equation similar to
@intVariable = (int)(doubleVariable*100);@This worked as expected in my old project: it truncated doubleVariable*100 to a whole number without changing the value in the ones place. That is also what all of the documentation I've read says it will do.
However, in my Qt project the behavior varies depending on the value of doubleVariable (see below). I don't understand why it thinks 1.55 * 100 = 155 but 2.55 * 100 < 255. I can do a workaround usng qRound but I don't get why a formerly reliable type conversion is no longer so. Can anyone help me understand this?<table>
<tr>
<td>doubleVariable</td>
<td>integerVariable</td>
</tr>
<tr>
<td>0.55</td>
<td>55</td>
</tr>
<tr>
<td>1.55</td>
<td>155</td>
</tr>
<tr>
<td>2.55</td>
<td>254</td>
</tr>
<tr>
<td>3.55</td>
<td>354</td>
</tr>
<tr>
<td>4.55</td>
<td>454</td>
</tr>
<tr>
<td>5.55</td>
<td>554</td>
</tr>
<tr>
<td>6.55</td>
<td>654</td>
</tr>
<tr>
<td>7.55</td>
<td>754</td>
</tr>
<tr>
<td>8.55</td>
<td>855</td>
</tr>
<tr>
<td>9.55</td>
<td>955</td>
</tr>
</table> -
Hey tanquist
The explanation why it happens is how a double is stored. E.g. the value 1.55 is not possible to be represented by a double. Therefore, if you write it into a double, the value is rounded to the next possible double value, which is 1.55000000000000004440892098501. Multiplied by 100 resolves in 155.000000000000004440892098501 stored in a double will be 155. That casted to an integer yields 155, which is expected.
But 2.55 will be rounded to the next double value 2.54999999999999982236431605997. Multiplied by 100 is 254.999999999999982236431605997 stored in a double will be 254.999999999999971578290569596. That casted to an integer results in 254. That is the experienced behaviour and the reason why rounding should be used.
I tested your numbers also in a float format. At this point every number converts to the expected value because the representation is different.
Maybe your old project used 32-bit for double values, this could be one explanation or you used float variables.
Nevertheless, the fact that exact these values converted right is coincidence in my opinion and rounding should always be necessary.
By the way, this script converts decimals to binaries and shows their "real" value if floating point is used: "BinaryConvert":http://www.binaryconvert.com/convert_double.html ( October 2014 ).
-
Thank you luggi for that excellent explanation and the conversion resource. This understanding makes the problem much less frustrating.
I've replaced all of my (int) and (long) conversions with variations on the function koahnig provided:
@int nint(double x) // provided by koahnig at qt-project.org
{// avoids binary rounding error in (int) conversion
return x < 0 ? (int)ceil(x) : (int)floor(x);
}@@long nlong(double x)
{// avoids binary rounding error in (long) conversion
return x < 0 ? (long)ceil(x) : (long)floor(x);
}@If anyone sees problems with my method please let me know.