Game Development Community

Modulo oddity

by Shaderman · in Torque Game Engine · 12/18/2008 (11:07 pm) · 7 replies

Hi,

maybe somebody can explain me what's going on here with this modulo operation:

%x = -50;
%x = %x % 20;
echo(%x); [b]-10 seems to be correct[/b]

if(%x < 0)
   echo("moo!"); [b]There's no moo printed. Isn't -10 smaller than 0?[/b]

Thanks,

Stefan

#1
12/19/2008 (12:51 am)
Strange : on my TGE 1.52 Mac, if i write (in the console)
echo( -50 % 20)

I get -10 as a result.
If I write
$a = -50
echo( $a % 20)

I get 0 as a result
Strange !?
#2
12/19/2008 (5:29 am)
@Stefan:
Try your example with global vars both in the console and in script and see what you get, I"m wondering if your local var is out of context

@Nicolas:
I cannot replicate this on Windows or Linux with 1.52, so perhaps it's unique to Mac... I'll load 1.52 on my Mac and see what I get...
#3
12/19/2008 (6:17 am)
@Brian
The same happens with global vars in console and from script in TGB and TGE 1.5.2. Didn't try TGEA yet but I guess it'll be the same.
#4
12/19/2008 (9:30 am)
Good catch Stefan,
there's definitely something screwy here.

in the stock TE 1.5.2 demo executable running on winXP:

==>$b = -50 % 20;
==>echo($b);
-10


==>if ($b < 0) echo(lt); else echo(gt);
gt


==>$b = -10;
==>if ($b < 0) echo(lt); else echo(gt);
lt
#5
12/19/2008 (12:37 pm)
I would have thought the -10 result is incorrect and the value should be 10. Doesn't explain why the echo appears to be a negative number but the "if" fails on it though.

Edit: To clarify, see this description of mod for negative numbers.
#6
12/19/2008 (5:08 pm)
I would have no idea how to fix this, but it appears to be related to some confusion internally as to whether the value returned by the mod operator should be treated as a signed int vs. an unsigned int.

This is revealed by:
==>$b = -50 % 20;
==>echo($b);
-10
==>echo($b + 0);
4.29497e+009

I believe the unsigned int with the same bits as the signed int representation of -10 happens to be 4294967286. It appears that when you do a simple reference to $b, it is retrieved as the signed int -10, but when retrieved as part of a mathematical operation like $b + 0, is retrieved as a very large unsigned int converted to the very large float 4.29497e+009.

I found this bit of code in the engine in compiledEval.cpp (TGEA 1.8) which appears to be consistent with this theory:
case OP_MOD:
    if(  intStack[UINT-1] != 0 )
       intStack[UINT-1] = intStack[UINT] % intStack[UINT-1];
    else
       intStack[UINT-1] = 0;
    UINT--;
    break;
The intStack[] array here is a signed long (S64), so the result will be computed as -10 (according to C++) but the use if UINT here implies that the value is going to be treated as an unsigned. That's as much as I understand of it.

Note that the confused value returned by the mod operator applied to a negative can be fixed by assigning to another variable. This could be used as a work-around until someone figures out how to fix it.
$b = -50;
$temp = $b % 20;
$b = $temp
if($b < 0)
   echo("moo!"); // moo is printed. -10 is smaller than 0.
#7
12/20/2008 (1:09 am)
@Gary
Interesting link you posted. I found this

Quote:If both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined".

on Wikipedia. This applies to C++ and thus to Torque Script in some way I think :)

@Jeff
That's a very interesting theory and seems to explain why it's happening. Thanks for that simple workaround.