Problem converting from int to float

前端 未结 6 1825
[愿得一人]
[愿得一人] 2021-01-02 00:27

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

相关标签:
6条回答
  • 2021-01-02 00:38

    Try converting float to double in your second example:

    double flo = 195.95F * 100;
    int num = (int) flo;
    

    I'm guessing in your first example the compiler is using double to hold the intermediate result, and so in the float case you're losing precision.

    0 讨论(0)
  • 2021-01-02 00:39

    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.

    0 讨论(0)
  • 2021-01-02 00:42

    When you multiply by 100, that is an integer, so it is doing an implicit conversion at that step. If you put an "F" behind the 100, I'll bet they'd be the same.

    I typically use boxing/unboxing with the parentheses when it is a reference type. When it is a value type, I try to use the Convert static methods.

    Try Convert.ToSingle(YourNumber); for a more reliable conversion.

    HTH

    0 讨论(0)
  • 2021-01-02 00:49

    Mark's answer is correct in that it is the conversion between nativefloat and float32/float64.

    This is covered in the CLR ECMA spec but David Notario explains this far better than I could.

    0 讨论(0)
  • 2021-01-02 00:50

    this code...

    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                float result = 195.95F*100;
                int intresult = (int)(195.95F * 100);
            }
        }
    }
    

    give this IL

    .method private hidebysig static void  Main(string[] args) cil managed
    {
      .entrypoint
      // Code size       14 (0xe)
      .maxstack  1
      .locals init ([0] float32 result,
               [1] int32 intresult)
      IL_0000:  nop
      IL_0001:  ldc.r4     19595.
      IL_0006:  stloc.0
      IL_0007:  ldc.i4     0x4c8a
      IL_000c:  stloc.1
      IL_000d:  ret
    } // end of method Program::Main
    

    look at IL_00001 -> the compier has done the calc.. Otherwise there are the decimal -> binary conversion problem

    0 讨论(0)
  • 2021-01-02 00:53

    I can't answer why the second one works and the first one doesn't. However, I can tell you that 195.95 is a non-terminating decimal in binary, and as such round off errors like this one are bound to happen.

    Try converting to a double rather than float. You could also use a money or a decimal type rather than a float. That will store the number differently and more accurately.

    For more on floating point numbers and the IEEE representation, go here:

    http://en.wikipedia.org/wiki/IEEE_754

    0 讨论(0)
提交回复
热议问题