Pages

Sunday, November 1, 2009

Double to Int

We all know how to convert a double value to integer. Google "double to int C++". You will find exactly what you usually use:
double pi = 3.14159;
int x = int (pi);
C++ does not perform this converting from double to it automatically, because it requires the rounding off and you should be aware that you lost the fractial part of the number.

So? In a library that works with OpenGL I see this strange code:
__inline GLfixed
Fixedf(GLfloat a)
{
GLfloat b = a;
GLuint d = *((GLuint*)&b) + 0x08000000;
return (GLfixed)(*((GLfloat*)&d));
}
Why this line with *((GLuint*)&b) should be so complicated?

In order to see what's going on I wrote few lines:

int main()
{
double x1 = 123.456;
double x2 = 321.654;

int y1 = (int)x1;
int y2 = static_cast<int>(x1);
int y3 = *(int*)&x2;
int y4 = *reinterpret_cast<int*>(&x2);
return 0;
}

In the debug mode I switched to the disassember:

I'm not a guru in such things, but looks like this line:

int y3 = *(int*)&x2;
seems "complicated" only in C++. In Assembler it looks trivial:
mov         eax,dword ptr [x2] 
mov dword ptr [y3],eax
You can compare it with:
fld         qword ptr [x1] 
call @ILT+215(__ftol2_sse) (4110DCh)
mov dword ptr [y1],eax
generated from usual:
int y1 = (int)x1;

But the result is absolutely different:

That's not what I need.
In Anti-Grain Geometry Library I found:
#pragma warning(push)
#pragma warning(disable : 4035) //Disable warning "no return value"
inline int iround(double v) //-------iround
{
int t;
__asm fld qword ptr [v]
__asm fistp dword ptr [t]
__asm mov eax, dword ptr [t]
}

inline unsigned uround(double v) //-------uround
{
unsigned t;
__asm fld qword ptr [v]
__asm fistp dword ptr [t]
__asm mov eax, dword ptr [t]
}
#pragma warning(pop)

So it is possible to use:

int y5 = iround(x1);

The result will be correct:

No comments:

Post a Comment