Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why lua_tonumber() has different behavior from lua_tointeger() when dealing with big integer?

Tags:

c

lua

I tried to convert a string from Lua(5.1.5) to an integer, and check if the number is a valid integer(0~99999). However, I found lua_tonumber() has different behavior from lua_tointeger() when dealing with big integer.

int main()
{
    int in;
    double db;

    lua_State* Lua = luaL_newstate();
    luaL_openlibs(Lua);

    lua_pushstring(Lua, "213232127162767162736718238168263816873");
    db = lua_tonumber(Lua, -1);
    in = lua_tointeger(Lua, -1);
    printf("DOUBLE:%f\n", db); // DOUBLE:213232127162767176000119210017101447168.000000
    printf("INT:%d\n", in);    // INT:0
};

If I use lua_tointeger(), it returns 0 and will pass my checking.

I check both API description, but I still don't know why they have different behaviors. Are these behaviors machine-independent? Is using lua_tonumber() a better way?

Can I use the following code to check the result? (cross-platform)

if (!lua_isnumber(Lua, -1)) { //error }
result = lua_tonumber(Lua, -1);
if (result < 0 || result > 99999) { // error2 }
// pass
like image 271
Yalieee Avatar asked Sep 04 '13 08:09

Yalieee


1 Answers

From the manual reference of lua_tointeger:

Converts the Lua value at the given acceptable index to the signed integral type lua_Integer. The Lua value must be a number or a string convertible to a number (see §2.2.1); otherwise, lua_tointeger returns 0

The same is with lua_tonumber. So when you get the return value of 0 means you are passing a string that is non-convertible. The number 213232127162767162736718238168263816873 is too big for an lua_Integer(the same as ptrdiff_t by default) type.

Are these behaviors machine-independent? Is using lua_tonumber() a better way?

In a way, it is machine-dependent, because the type lua_Integer is machine-dependent. Again, the number 213232127162767162736718238168263816873 is too big for any normal integer type. Whether using lua_tonumber or using lua_tointeger is up to your need. If converting an integer that is less than 32-bit, for example, 0~99999 in your question, lua_tointeger is your choice. It is very fast in a IEEE-754 compatible machine. The disadvantage of using lua_tonumber is that it may mis-convert non-integer values.

Reference: A fast method to round a double to a 32-bit int explained

like image 72
Yu Hao Avatar answered Nov 06 '22 07:11

Yu Hao