Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem converting from int to float

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?

like image 329
CodeClimber Avatar asked Jun 19 '09 14:06

CodeClimber


People also ask

Can we convert int to float in C?

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.

What happens when float is converted to 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.

How do you convert int to floating-point?

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.

Can int be converted to float?

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.


1 Answers

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.

like image 104
Marc Gravell Avatar answered Nov 10 '22 03:11

Marc Gravell