C adalah huruf ketiga dalam alfabet Latin. Dalam bahasa Indonesia, huruf ini disebut ce (dibaca [tʃe]).
Meskipun C dibuat untuk memprogram sistem dan jaringan komputer namun bahasa ini juga sering digunakan dalam mengembangkan software aplikasi. C juga banyak dipakai oleh berbagai jenis platform sistem operasi dan arsitektur komputer, bahkan terdapat beberepa compiler yang sangat populer telah tersedia.
Bahasa pemrograman C ini dikembangkan antara tahun 1969 – 1972 oleh Dennis Ritchie. Yang kemudian dipakai untuk menulis ulang sistem operasi UNIX. Selain untuk mengembangkan UNIX, bahasa C juga dirilis sebagai bahasa pemrograman umum.
First of all, I assume that you know that 6.2f * 10
is not exactly 62 due to floating point rounding (it's actually the value 61.99999809265137 when expressed as a double
) and that your question is only about why two seemingly identical computations result in the wrong value.
The answer is that in the case of (int)(6.2f * 10)
, you are taking the double
value 61.99999809265137 and truncating it to an integer, which yields 61.
In the case of float f = 6.2f * 10
, you are taking the double value 61.99999809265137 and rounding to the nearest float
, which is 62. You then truncate that float
to an integer, and the result is 62.
Exercise: Explain the results of the following sequence of operations.
double d = 6.2f * 10;
int tmp2 = (int)d;
// evaluate tmp2
Update: As noted in the comments, the expression 6.2f * 10
is formally a float
since the second parameter has an implicit conversion to float
which is better than the implicit conversion to double
.
The actual issue is that the compiler is permitted (but not required) to use an intermediate which is higher precision than the formal type (section 11.2.2). That's why you see different behavior on different systems: In the expression (int)(6.2f * 10)
, the compiler has the option of keeping the value 6.2f * 10
in a high precision intermediate form before converting to int
. If it does, then the result is 61. If it does not, then the result is 62.
In the second example, the explicit assignment to float
forces the rounding to take place before the conversion to integer.
Floating numbers a rarely exact. 6.2f
is something like 6.1999998...
.
If you cast this to an int it will truncate it and this * 10 results in 61.
Check out Jon Skeets DoubleConverter
class. With this class you can really visualize the value of a floating number as string. Double
and float
are both floating numbers, decimal is not (it is a fixed point number).
DoubleConverter.ToExactString((6.2f * 10))
// output 61.9999980926513671875
Look at the IL:
IL_0000: ldc.i4.s 3D // speed1 = 61
IL_0002: stloc.0
IL_0003: ldc.r4 00 00 78 42 // tmp = 62.0f
IL_0008: stloc.1
IL_0009: ldloc.1
IL_000A: conv.i4
IL_000B: stloc.2
The compiler reduces compile-time constant expressions to their constant value, and I think it makes a wrong approximation at some point when it converts the constant to int
. In the case of speed2
, this conversion is made not by the compiler, but by the CLR, and they seem to apply different rules...
My guess is that 6.2f
real representation with float precision is 6.1999999
while 62f
is probably something similar to 62.00000001
. (int)
casting always truncates the decimal value so that is why you get that behavior.
EDIT: According to comments I have rephrased the behavior of int
casting to a much more precise definition.
I compiled and disassembled this code (on Win7/.NET 4.0). I guess that compiler evaluates floating constant expression as double.
int speed1 = (int)(6.2f * 10);
mov dword ptr [rbp+8],3Dh //result is precalculated (61)
float tmp = 6.2f * 10;
movss xmm0,dword ptr [000004E8h] //precalculated (float format, xmm0=0x42780000 (62.0))
movss dword ptr [rbp+0Ch],xmm0
int speed2 = (int)tmp;
cvttss2si eax,dword ptr [rbp+0Ch] //instrunction converts float to Int32 (eax=62)
mov dword ptr [rbp+10h],eax
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With