There is a strange behavior I cannot understand. Agreed that float point number are approximations, so even operations that are obviously returning a number without decimal numbers can be approximated to something with decimals.
I'm doing this:
int num = (int)(195.95F * 100);
and since it's a floating point operation I get 19594 instead of 19595.. but this is kind of correct.
What puzzles me is that if I do
float flo = 195.95F * 100;
int num = (int) flo;
I get the correct result of 19595.
Any idea of why this happens?
Once you've created a variable of a certain type, it is locked in as that type forever. So in your case, you created i as an int. You can't reassign i as a float after that. An int is always an int and will remain an int as long as it was declared as an int and will never be able to change into anything but an int.
Method 1: Conversion using int(): To convert a float value to int we make use of the built-in int() function, this function trims the values after the decimal point and returns only the integer/whole number part. Example 1: Number of type float is converted to a result of type int.
When converting an integer to a floating point number, it's just shifted until the mantissa is within the right range, i.e. 1 < m < 2, and the exponent is just how many steps it shifts. The number 1010 for example is shifted until it is 1.010 and the exponent is 3 as that is how many bits it was shifted.
To convert an integer data type to float you can wrap the integer with float64() or float32. Explanation: Firstly we declare a variable x of type int64 with a value of 5. Then we wrap x with float64(), which converts the integer 5 to float value of 5.00.
I looked to see if this was the compiler doing the math, but it behaves this way even if you force it out:
static void Main()
{
int i = (int)(GetF() * GetI()); // 19594
float f = GetF() * GetI();
int j = (int)f; // 19595
}
[MethodImpl(MethodImplOptions.NoInlining)]
static int GetI() { return 100; }
[MethodImpl(MethodImplOptions.NoInlining)]
static float GetF() { return 195.95F; }
It looks like the difference is whether it stays in the registers (wider than normal r4) or is forced to a float
variable:
L_0001: call float32 Program::GetF()
L_0006: call int32 Program::GetI()
L_000b: conv.r4
L_000c: mul
L_000d: conv.i4
L_000e: stloc.0
vs
L_000f: call float32 Program::GetF()
L_0014: call int32 Program::GetI()
L_0019: conv.r4
L_001a: mul
L_001b: stloc.1
L_001c: ldloc.1
L_001d: conv.i4
L_001e: stloc.2
The only difference is the stloc.1
/ ldloc.1
.
This is supported by the fact that if you do an optimised build (which will remove the local variable) I get the same answer (19594) for both.
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