Ultra fast float/double -> int conversions - Follow up
  • ninseineonninseineon November 2007
    Greetings,

    I came across this post here in the forum http://www.relishgames.com/forum/viewtopic.php?t=280, but couldn't reply there - don't know why.

    Basically the author of the post raised the issue of the lack of optimization in doing float to int conversions and posted a solution for that, that involved using some assembly. This is original solution:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    inline int double2int(double flt)
    {
    int intgr;
     
    _asm fld flt
    _asm fistp intgr
     
    return intgr ;
    }
     
    inline int float2int(float flt)
    {
    int intgr;
     
    _asm fld flt
    _asm fistp intgr
     
    return intgr;
     
    }


    Since I'm using Code::Blocks and gcc, _asm doesn't work. The following code is used in my game framework and compiles ok in my environment, but when I'm linking a small test program with the game framework's lib, the compiler spits out a complain about not knowing flt and intgr... Following is the code that I got to compile ok with the game framework, and after that the compiler's complaints in the test application. What I'm doing in my test application is just call float2int() from it's namespace (you can't see that here).
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    /*
    ** http://relishgames.com/forum/viewtopic.php?t=280
    ** http://mega-nerd.com/FPcast/
    */

    inline int double2int(double flt)
    {
    int intgr;
    asm("fld flt");
    asm("fistp intgr");
    return intgr ;
    }
     
     
    /*
    ** http://relishgames.com/forum/viewtopic.php?t=280
    ** http://mega-nerd.com/FPcast/
    */

    inline int float2int(float flt)
    {
    int intgr;
    asm("fld flt");
    asm("fistp intgr");
    return intgr;
    }
    1
    2
    3
    4
    5
    C:\Dev\hge17\include\hgeresource.h:30: warning: `struct ResDesc' has virtual functions but non-virtual destructor
    obj\Debug\main.o:: In function `ZSt9make_pairISsP12hgeAnimationESt4pairIT_T0_ES3_S4_'
    :
    C:\Dev\MinGW\bin\..\lib\gcc\mingw32\3.4.5\..\..\..\..\include\c++\3.4.5\bits\stl_pair.h:(.text$_ZN8AE_Tools9float2intEf[AE_Tools::float2int(float)]+0x8):: undefined reference to `flt'
    C:\Dev\MinGW\bin\..\lib\gcc\mingw32\3.4.5\..\..\..\..\include\c++\3.4.5\bits\stl_pair.h:(.text$_ZN8AE_Tools9float2intEf[AE_Tools::float2int(float)]+0xe):: undefined reference to `intgr'

    :: === Build finished: 2 errors, 1 warnings ===


    Can anyone see what's wrong please?
    Thank you.
  • ProfEclipseProfEclipse November 2007
    Change your assembler to:
    1
     __asm__ __volatile__ ("fld %1; fistp %0;" : "=m" (intgr) : "m" (flt));

    or
    1
     __asm__ __volatile__ ("flds %1; fistpl %0;" : "=m" (intgr) : "m" (flt));

    depending on your integer size (I think). I had to use the second one on a linux box to get the expected results.

    The 'm' says we're using memory for input and output. The '=' says this is the output variable. Basically, we're saying get your input from 'flt' and store the result in 'intgr'.
  • ninseineonninseineon November 2007
    Thank you for the info! It works like a charm now.
  • ninseineonninseineon November 2007
    Errr... Actually, I came to see that it's not working like a charm at all... This is probably my fault, somewhere along the line, but following this topic here http://www.relishgames.com/forum/viewtopic.php?t=2885 you can see that I had some issues in rendering more than one sprite/animation to the screen, using this assembly coding method.

    It seems that if I use this to cast the object's coordinates from float into int, before it gets rendered, only the first object who calls its Render() method (on the State class) gets actually rendered on screen... This is very weird, like if by any chance in two consecutive calls to the float2int() method, the second one is completely ignored...

    This is pretty hermetic stuff to me, since I don't know my assembly that well... Anyone even remotely suspects what could be the problem with this?
  • mosmos November 2007
    Here's what I would do: take out the fast conversion code. Just do it normally. Later, when it comes time to optimize your code, find out just how much of your time could actually be saved by implementing a fast convert operator. You might find that you're wasting a lot of time trying to fix something that you wouldn't really miss. You're more interested in writing your game anyway, right?

    "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil." - Donald Knuth
  • ninseineonninseineon November 2007
    [quote="mos"]premature optimization is the root of all evil.

    Couldn't agree more... :) In the meantime, if someone can grasp what could be causing this issue, I'd appreciate to know...

    Thanks everyone.
  • ProfEclipseProfEclipse November 2007
    I don't think you've given us enough code to tell you why that may be happening.

    I suspect the problem is not in the asm functions, but elsewhere. I've tested the asm functions, making multiple calls to functions with calls to the asm as parameters and have not seen any strange execution issues.

    Since we both agree with mos (and Knuth), this is purely an intellectual exercise, but it's still comforting to know why something happens even if you don't intend to use it.
  • SantalLicanSantalLican October 2012
    No need to optimize. Default conversion method is very good. (???)
    (However, I'm not sure. Default method only does fast-calling floor() for float values. It's better to use the follow functions ('macros' is more accurate) in the main post instead of floor(), round() functions (In some proper cases). Because it's faster, I guess.)

    I tested between regular int conversion and all other inline ultra float->int converting. I want to know the final calculation time of two methods then compare them. Here are testing algorithms (I put them into the FrameFunc()):
    Start with :
    1
    2
    3
    4
    5
    6
    7
    8
    #include <time.h>
    float f = 6.35f;
    int nResult;
    [...]
    //FrameFunc()
    [...]
    //Init
    hge->System_Log("Output time after a billion of float -> int converting commands :");


    Now, two players start !


    Popular method :

    1
    2
    3
    4
    5
    int nStart = clock();
    for(int i = 0;i < 1000000000; i++)nResult = int(f); //Look !
    int nEnd = clock();
    hge->System_Log
    ("Popular method : Time : %.3f - Value : %d",(nEnd - nStart) / 1000.0f, nResult);


    Super-fast method :
    1
    2
    3
    4
    5
    int nStart = clock();
    for(int i = 0;i < 1000000000; i++)nResult = float2int(f); //Look !
    int nEnd = clock();
    hge->System_Log
    ("Super-fast method : Time : %.3f - Value : %d",(nEnd - nStart) / 1000.0f, nResult);


    And Output (Test with float number 6.35f) - 3 Frames :


    Ultra-fast method :
    Output time after a billion of float -> int converting commands :
    Super-fast method : Time : 1.465 Value : 6
    Super-fast method : Time : 1.512 Value : 6
    Super-fast method : Time : 1.486 Value : 6

    Regular method :
    Output time after a billion of float -> int converting commands :
    Popular method : Time : 0.000 Value : 6
    Popular method : Time : 0.000 Value : 6
    Popular method : Time : 0.000 Value : 6

    Window screen : 800 x 600
    Computer speed : 2.7 GHz
    Frames per second : (Ultra-fast vs Regular method) : 1 < (500 +- 20) FPS -> (?????????????)


    Final result : Ultra-fast method lose !!!
    Use simple (int) method is faster than the super super fast one by thousands thousands of times !

    -> No need to make it more complex. Try and keep using the simple one !
    (...3-character 'int' method becomes fast as light, and otherwise, they are just garbage. (As turtles))
    ...
    Hey ! Why this caused ? Negative result ? Please explain this ? We're wrong ? :(
    Or what's wrong in my code ?
    OR IS THIS ONLY A JOKE ???? :)

    ...?!??!?
  • kvakvskvakvs October 2012
    Zero time is a joke. You got your billion loop optimized out by the compiler.
    Try forcing optimization off by adding "volatile" before int nResult.
  • SantalLicanSantalLican October 2012
    kvakvs said:

    Zero time is a joke. You got your billion loop optimized out by the compiler.
    Try forcing optimization off by adding "volatile" before int nResult.


    Wow ! You're right ! The result should be more accurate.

    I updated my new result :


    Ultra-fast method :
    Output time after a billion of float -> int converting commands :
    Super-fast method : Time : 1.485 Value : 6
    Super-fast method : Time : 1.521 Value : 6
    Super-fast method : Time : 1.476 Value : 6

    Regular method :
    Output time after a billion of float -> int converting commands :
    Popular method : Time : 0.752 Value : 6
    Popular method : Time : 0.743 Value : 6
    Popular method : Time : 0.747 Value : 6



    And finally, 'int' conversion method is still faster than the super-ultra-fast-calling conversion method one ! By 2x !!!!!! (Note : No any optimization)
    Haha... Everyone should not try the ultra float->int conversion anymore ! (Unless you know what you have to do with it...)

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In Apply for Membership

In this Discussion

Who's Online (2)