#Nan And Other Strange Float Values

Started by
3 comments, last by Adam_42 13 years, 3 months ago
So, I recently added a lua interpreter to a project of mine, and set up a binding between it, and my message dispatcher. It seems to work perfectly in all cases I've tried so far, except when one of the arguments passed to the function is a non-zero whole numbered float (1.0, 2.0, 3.0, etc). These arguments work fine in the direct message dispatcher function, so somewhere between lua and there the value must be getting corrupted (gets turned into something like 1.#nan or some silly randomish value (2.[somethinghere]e[somethingrandom]). Any idea what I'm doing wrong? (alternatively, any idea how to do it better?) Thanks!

Here's the code for the binding function:
static int luabind_DispatchMessage(lua_State *L)
{
// Step one, figure out how many arguments I was called with
int argc = lua_gettop(L);
int i;

int type;
int temp1 = 0;
float temp2 = 0;

void *args[] = {NULL, NULL, NULL, NULL, NULL};

for(i = 1; i <= argc; ++i)
{
if(i == 1) // If this is the first argument, it must be the TYPE argument
{
type = (int)lua_tonumber(L, i);
}
else
{
if(lua_isnumber(L, i) == 1) // If this is a number
{
temp2 = lua_tonumber(L, i);
if(fmod(temp2, 1) == 0) // If this looks like an integer
{
temp1 = (int)temp2;
args[i-2] = (void *)temp1;
}
else // If this is actually a float
{
args[i-2] = ftov(temp2);
}
}
else if(lua_isstring(L, i) == 1) // If this is a char or a string
{
args[i-2] = (void *)lua_tostring(L, i);
}
}
}

Dispatch_Message(type, args[0], args[1], args[2], args[3], args[4]);

return 0;
}
There was a saying we had in college: Those who walk into the engineering building are never quite the same when they walk out.
Advertisement
#nan = Not-A-Number

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

or some silly randomish value (2.[somethinghere]e[somethingrandom]).
Sounds like E-Notation (or 'Scientific notation'). It may not be corrupt, just displayed in a format you aren't used to. (But it could ofcourse be corrupt AND displayed in a format you aren't used to).

http://en.wikipedia.org/wiki/E_notation#E_notation

I'm not familiar enough with E-Notation to help you beyond that.
I suspect the problem is in one of two places:

Possibility 1) Mathematically, 1.0/2.0 and the like are integers and so probably trigger the integer condition in the code I posted. On the receiving end of the messaging system, this is converted (for messages that expect a float in a given position) to a float via a (float &) cast. Maybe that is unsafe?

Possibility 2) the return value of lua_tonumber (which is a lua_number which is a typedef of double) perhaps doesn't like being cast to a float?

Here is the code for ftov(), in case anyone finds it suspect.
void* ftov(float val)
{
DWORD tmp = *(DWORD *)&val;
return (void *)tmp;
}
There was a saying we had in college: Those who walk into the engineering building are never quite the same when they walk out.
Through a little strlen trickery, I have made it such that the code now handles numbers like 1.0/2.0/3.0 properly if they are quoted in the lua script (because otherwise they would be truncated by lua_tostring. Not a perfect solution, but good enough for now.
There was a saying we had in college: Those who walk into the engineering building are never quite the same when they walk out.
One obvious issue you'll run into is that in your Dispatch_Message function you'll need to interpret those void* elements as either a float or an integer, presumably based on the type. If your floating point value that you want to pass happens to end up as say 1.0 it'll be passed as an integer and handled the other end as a float, which probably isn't what you want and could be the source of those NaNs.

There's two obvious ways round that:

1. Pass all numbers as doubles like lua does. Not very convenient but should work. You'll have to change the argument types from void* to 64-bit ones to make that work.
2. Add a format string of some kind so you can use the proper argument types. This could be looked up based on the type parameter. For example:


static const char *dispatch_message_format_strings[NUM_TYPES] = { "iifsi", "siiii", ....};

switch (dispatch_message_format_strings[type][i-2])
{
case 'f': args[i-2] = ftov(lua_tonumber(L, i)); break;
case 'i': args[i-2] = (void*)((int)lua_tonumber(L, i)); break;
case 's': args[i-2] = (void *)lua_tostring(L, i); break;
default: assert(0); break; // Invalid format string
}

This topic is closed to new replies.

Advertisement