Derek Lamb
2015-02-18 06:05:51 UTC
At the very beginning of Basic/Ops/ops.pd there are currently two MOD macros to define the modulus operator. BU_MOD works on byte and ushort piddles, whereas MOD works on all other types. In both of those, but particularly worrisome in MOD, there are C typecasts to (int). I think this is the source of the modulo failures that Luis Mochan has been reporting on the perldl list for large longlong operands: the longlongs get truncated to ints, lose high order bits, and thus the operator returns garbage.
You can see what I mean by doing:
$a= longlong(71,710,7100,71000,710000,7100000,71000000,710000000,7100000000,71000000000,710000000000,7100000000000,71000000000000,710000000000000,710000000000000,7100000000000000,71000000000000000)
print $a; #the internal representation is fine (at least on my machine)
print $a % 71; #should return 0 for each
[0 0 0 0 0 0 0 0 0 0 609885356032 7013681594368 71051643977728 709906554421248 709906554421248 7.09998037224653e+15 7.10001086651433e+16]
The simplest fix seems to be changing those typecasts from (int) to (long). The above $a%71 returns all zeroes, and "make test" passes. But I'm not sure about portability (is long defined on all our systems?), and it's now obvious that the tests in ops.t for modulo are completely inadequate. Or is that just kicking the can down the road?
I can also get rid of the failures for longlong operands by creating a new macro Q_MOD that works on longlongs only, and replaces the (int) typecasts with (long long). Here I worry more about portability: my "pdl -V" has "longsize=8, d_longlong=define, longlongsize=8".
I guess I'm unclear what we support on what machines; I haven't been paying too much attention to that lately.
Kind of stupid that this long message is for potentially a 14-character source code change, but thought I'd check first before pushing something that's going to mess somebody else up.
best,
Derek
You can see what I mean by doing:
$a= longlong(71,710,7100,71000,710000,7100000,71000000,710000000,7100000000,71000000000,710000000000,7100000000000,71000000000000,710000000000000,710000000000000,7100000000000000,71000000000000000)
print $a; #the internal representation is fine (at least on my machine)
print $a % 71; #should return 0 for each
[0 0 0 0 0 0 0 0 0 0 609885356032 7013681594368 71051643977728 709906554421248 709906554421248 7.09998037224653e+15 7.10001086651433e+16]
The simplest fix seems to be changing those typecasts from (int) to (long). The above $a%71 returns all zeroes, and "make test" passes. But I'm not sure about portability (is long defined on all our systems?), and it's now obvious that the tests in ops.t for modulo are completely inadequate. Or is that just kicking the can down the road?
I can also get rid of the failures for longlong operands by creating a new macro Q_MOD that works on longlongs only, and replaces the (int) typecasts with (long long). Here I worry more about portability: my "pdl -V" has "longsize=8, d_longlong=define, longlongsize=8".
I guess I'm unclear what we support on what machines; I haven't been paying too much attention to that lately.
Kind of stupid that this long message is for potentially a 14-character source code change, but thought I'd check first before pushing something that's going to mess somebody else up.
best,
Derek