Jump to content


Float to int casting consistency


4 replies to this topic

#1 Nick

    Senior Member

  • Members
  • PipPipPipPip
  • 1225 posts

Posted 17 January 2007 - 04:50 PM

Hi all,

How should C++ handle overflow when casting large floating-point numbers to integers? I'm asking this because the code below shows some inconsistency when compiled with Visual C++ 2005:

void main()

{

    float x = 1e20;

    float y = 1e10;

    float z = 1e5;


    __int64 a = x;

    __int64 b = y;

    int c = y;

    short d = y;

    short e = z;

}

On my system:
a = -9223372036854775808 (= 0x8000000000000000)
b = 10000000000
c = 2147483648 (= 0x80000000)
d = 0
e = -31072 (= 0x86A0)

Looking at the assembly code, the last three casts use SSE2 (cvtpd2si). It is defined to return 0x80000000 on overflow. But for the short int it just takes the lower 16-bit of this value. I've tried to look for a detailed C++ reference about float to int casting but couldn't find anything so far. My best guess is that this should cause an exception, but this exception is typically masked, so the resulting value is undefined. :surrender

Thoughts?

Nick

#2 .oisyn

    DevMaster Staff

  • Moderators
  • 1810 posts

Posted 17 January 2007 - 11:03 PM

Quote

4.9 Floating-integral conversions

-1- An rvalue of a floating point type can be converted to an rvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type

So your results are correct, but it may just as well format your harddrive ;)
C++ addict
-
Currently working on: the 3D engine for Tomb Raider.

#3 SmokingRope

    Valued Member

  • Members
  • PipPipPip
  • 210 posts

Posted 18 January 2007 - 12:33 AM

Do you think the undefinedness of such situations is simply to provide the greatest amount of leniency (to compiler developers) when optimizing?

#4 .oisyn

    DevMaster Staff

  • Moderators
  • 1810 posts

Posted 18 January 2007 - 12:46 AM

Most probably, you can easily code the check yourself (if (floatValue > (float)INT_MAX || floatValue < (float)INT_MIN) throw myfloatexception();).

Worth noting might be that C99 does in fact scpecify that a floating point exception has to be raised in such occasions. I can't seem to find any C90 docs (where C++98 is based upon), so I don't know if that's the way it used to be.
C++ addict
-
Currently working on: the 3D engine for Tomb Raider.

#5 Nick

    Senior Member

  • Members
  • PipPipPipPip
  • 1225 posts

Posted 18 January 2007 - 10:26 AM

Thanks for the information!

The most elegant way to deal with this is probably to write a class that properly handles the overflow situation:

class sshort   // Saturating short

{

public:

    sshort(float f)

    {

        if(f >= 32768.0f)

        {

            i = 32767;

        }

        else if(f <= -32769.0f)

        {

            i = -32768;

        }

        else

        {

            i = short(f);

        }

    }


    sshort operator+(sshort ss)

    {

        // Saturating add

    }


    // ...


private:

    short i;

};







1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users