7

Irrelavent justification for the question:

i'm getting an error calling Lua format:

integer overflow attempting to store -1.#IND

The variable's type(n) really is a number, and i can format it as a string (i.e. %s), but it's not a number, e.g.:

print(string.format("value=%s, type=%s", n, type(n)));

for the NaN value returns:

value=-1.#IND, type=number

i want to fix this, but i have no idea who is generating this NaN (Lua has no debugger).

So i'm left with having to throw a lot of asserts all over the code until i can pin down to the source of this intermittent NaN value.

But i can't find any condition that traps it, and Lua doesn't have isnan(x).

Question:

How can i test a number for -1.#IND in Lua?

Update:

i tried:

if (n ~= n) then
   print(string.format("NaN: value=%s, type=%s", n, type(n)));
else
   print(string.format("value=%s, type=%s", n, type(n)));
end;

and it prints

value=-1.#IND, number

Update Two: Just in case i missed something, my actual code is:

    if (oldValue ~= oldValue) then
        print(string.format("Is NaN: labelNumber=%d, formatString=\"%s\", oldValue=%s (%s)", labelNumber or 0, formatString or "nil", oldValue or "nil", type(oldValue)));
    else
        print(string.format("Is not NaN: labelNumber=%d, formatString=\"%s\", oldValue=%s (%s)", labelNumber or 0, formatString or "nil", oldValue or "nil", type(oldValue)));
    end;

And the faulty value outputs:

Is not NaN: labelNumber=4, formatString="%d", oldValue=-1.#IND (number)

Update Three

Still trying to solve this problem, i just noticed the absurdadity of reality:

function isnan(x)
   if type(x) ~= "number" then
       return false; --only a number can not be a number
   end;

   ...
end;
Ian Boyd
  • 220,884
  • 228
  • 805
  • 1,125

3 Answers3

4

n ~= n may work (with the caveats described in Mud's answer), but a more portable one may be:

function isnan(n) return tostring(n) == tostring(0/0) end

Those who are concerned about division by zero (as in Ian's comment; although I haven't seen it in practice) can use an alternative version:

function isnan(n) return tostring(n) == tostring((-1)^.5) end

Full function:

--local nanString = (tostring((-1) ^ 0.5)); --sqrt(-1) is also NaN. 
--Unfortunately, 
--  tostring((-1)^0.5))       = "-1.#IND"
--  x = tostring((-1)^0.5))   = "0"
--With this bug in LUA we can't use this optimization
local function isnan(x) 
    if (x ~= x) then
        --print(string.format("NaN: %s ~= %s", x, x));
        return true; --only NaNs will have the property of not being equal to themselves
    end;

    --but not all NaN's will have the property of not being equal to themselves

    --only a number can not be a number
    if type(x) ~= "number" then
       return false; 
    end;

    --fails in cultures other than en-US, and sometimes fails in enUS depending on the compiler
--  if tostring(x) == "-1.#IND" then

    --Slower, but works around the three above bugs in LUA
    if tostring(x) == tostring((-1)^0.5) then
        --print("NaN: x = sqrt(-1)");
        return true; 
    end;

    --i really can't help you anymore. 
    --You're just going to have to live with the exception

    return false;
end
Ian Boyd
  • 220,884
  • 228
  • 805
  • 1,125
Paul Kulchenko
  • 22,780
  • 3
  • 28
  • 49
  • It should be noted that `n ~= n` does not always work (as @Mud linked to); nor does it work for me. – Ian Boyd Aug 24 '12 at 20:07
  • @Ian, right; that's why "tostring(n) == tostring(0/0)" may be a more portable way as I noted. If someone doesn't want the "string" representation to be match, then "type(n) == 'number' and tostring(n) == tostring(0/0)" should do. – Paul Kulchenko Aug 24 '12 at 21:15
  • i also have reports of some people getting *"division by zero"* errors, rather than "division by zero" simply returning `+INF` or `-INF`. – Ian Boyd Aug 25 '12 at 01:37
  • @Ian: that's interesting; do you know under what circumstances? I use 0/0 representation in my serializer (https://github.com/pkulchenko/serpent) and haven't seen any reports about division by zero (although nan numbers seem to be rarely used). – Paul Kulchenko Aug 25 '12 at 02:40
  • i haven't been able to figure out why they'll get a division by zero error on a `x = y / z` when `z` is zero. My system raises no error. Nonetheless i had check `if z == 0 then x = 0 else x = y/z end`. – Ian Boyd Aug 25 '12 at 12:50
  • @Ian, updated the answer to add an alternative solution that should avoid division by zero problem. – Paul Kulchenko Aug 25 '12 at 20:29
  • Strangely enough `tostring((-1) ^ 0.5)` is `"-1.#IND"`, but `local s = tostring((-1) ^ 0.5)` has `s = "0"`. – Ian Boyd Aug 26 '12 at 17:44
1

Lua doesn't have isnan(x).

You can add one to your Lua host or create a module with that function. Just a few lines of code.

How can i test a number for -1.#IND in Lua?

Well, you know that it's converting NaN in to the string representation '-1.#IND', so you could write:

function isnan(n) return tostring(n) == '-1.#IND' end

Or, depending on the platform, compiler, compiler settings, etc., this will work:

function isnan(n) return n ~= n end
Community
  • 1
  • 1
Mud
  • 25,694
  • 10
  • 54
  • 81
  • 3
    It's safe to say that for the same reason that `n ~= n` doesn't always work, that `tostring(n) == "-1.#IND"` will not always work. Depending on the compiler, platform, or locale, the return of `tostring(n)` can also be `NaN` (at least in enUS). Some other versions of *"NaN"* that you're likely to see are: *非数値*, *NkN*, *μη αριθμός*, *غ ع*, *ᠲᠤᠭᠠᠠ ᠪᠤᠰᠤ*, *ཨང་ཀི་མིན་པ།*, *ꌗꂷꀋꉬ*, *不是一個數字*, *非数字*, *NeuN* and *EdZ*. – Ian Boyd Aug 24 '12 at 20:12
  • The main objection of the linked question http://stackoverflow.com/questions/570669/checking-if-a-double-or-float-is-nan-in-c is a g++ compiler flag called `--fast-math` and similar optimizations in other compilers, which do not apply to Lua as they do not affect the bytecode. Or at least I don't know how they would. So the only reason for `x~=x` not working would be if the FPU itself had a non-IEEE conforming floating point implementation. That would be an interesting find though. – dualed Jun 19 '13 at 11:40
0

For serializing purposes, this seems to work best for me:

local function isnan(val)
    if val==1/0 then return "1/0"
    elseif val==-1/0 then return "-1/0"
    elseif val~=val then return "0/0"
    end
end

This lets me:

print(v .. " = " .. isnan(val) or val)

The result is then, for example,

{
  foo = 1/0,
  bar = 0/0,
  bla = -1/0,
}
Sinus Mackowaty
  • 424
  • 4
  • 8