Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.96k stars 555 forks source link

Wacky modulus behaviour #775

Closed p5pRT closed 20 years ago

p5pRT commented 25 years ago

Migrated from rt.perl.org#1700 (status was 'resolved')

Searchable as RT1700$

p5pRT commented 25 years ago

From gnat@frii.com

Until you do it in separate steps\, 'time % -60' is never negative. This smells like a spurious NV conversion. Somewhere.

Nat

p5pRT commented 25 years ago

From [Unknown Contact. See original ticket]

Nathan Torkington writes​:

perl -le 'print time % -60' perl -le '$x = time; print $x % -60' perl -le '$x = time; $y = $x % -60; print $y'

Until you do it in separate steps\, 'time % -60' is never negative. This smells like a spurious NV conversion. Somewhere.

Is not it that time may take an argument\, and % may preceed an identifier?

Ilya

p5pRT commented 25 years ago

From [Unknown Contact. See original ticket]

Ilya Zakharevich writes​:

perl -le 'print time % -60' perl -le '$x = time; print $x % -60' perl -le '$x = time; $y = $x % -60; print $y'

Is not it that time may take an argument\, and % may preceed an identifier?

I don't think so. The second case\, which doesn't give an argument to time()\, prints the same thing as the first case.

Nat

p5pRT commented 25 years ago

From [Unknown Contact. See original ticket]

Nathan Torkington \gnat@​frii\.com wrote

perl -le 'print time % -60' perl -le '$x = time; print $x % -60' perl -le '$x = time; $y = $x % -60; print $y'

Until you do it in separate steps\, 'time % -60' is never negative. This smells like a spurious NV conversion. Somewhere.

Nope. It's a false optimisation. The last time it showed up\, the example was something like

perl -le 'print time; print time*1000'

I don't recall the details\, but basically Perl is saying something like "I know time() returns an IV\, so I know the operation (* or %) is on integers\, so I'll force `use integer'". So you're getting the altered semantics that you get from `use integer'.

I also don't recall why this didn't get fixed - whether it was just lack of tuits\, lack of understanding of the relevant code (that's my excuse)\, or a desire to put performance above correct semantics.

Mike Guy

p5pRT commented 25 years ago

From @gsar

On Sat\, 23 Oct 1999 16​:24​:17 BST\, "M.J.T. Guy" wrote​:

Nathan Torkington \gnat@​frii\.com wrote

perl -le 'print time % -60' perl -le '$x = time; print $x % -60' perl -le '$x = time; $y = $x % -60; print $y'

Until you do it in separate steps\, 'time % -60' is never negative. This smells like a spurious NV conversion. Somewhere.

Nope. It's a false optimisation. The last time it showed up\, the example was something like

perl -le 'print time; print time*1000'

I don't recall the details\, but basically Perl is saying something like "I know time() returns an IV\, so I know the operation (* or %) is on integers\, so I'll force `use integer'". So you're getting the altered semantics that you get from `use integer'.

I also don't recall why this didn't get fixed - whether it was just lack of tuits\, lack of understanding of the relevant code (that's my excuse)\, or a desire to put performance above correct semantics.

AFAIK this particular bug in modulus has never come up before\, or I would have fixed it. :-) Note that the "consistent C modulus" behavior based on C\ was something that got added in 5.004. Pity the testsuite isn't good enough to have caught this. :-(

Sarathy gsar@​ActiveState.com

Inline Patch ```diff -----------------------------------8<----------------------------------- Change 4428 by gsar@auger on 1999/10/23 20:28:56 fix accidental C modulo semantics on integer-valued operations (e.g. caused C to return 3 rather than -7) Affected files ... ... //depot/perl/op.c#205 edit ... //depot/perl/t/op/int.t#6 edit Differences ... ==== //depot/perl/op.c#205 (text) ==== Index: perl/op.c --- perl/op.c.~1~ Sat Oct 23 13:29:02 1999 +++ perl/op.c Sat Oct 23 13:29:02 1999 @@ -2112,8 +2112,12 @@ return o; if (!(PL_hints & HINT_INTEGER)) { - if (type == OP_DIVIDE || !(o->op_flags & OPf_KIDS)) + if (type == OP_MODULO + || type == OP_DIVIDE + || !(o->op_flags & OPf_KIDS)) + { return o; + } for (curop = ((UNOP*)o)->op_first; curop; curop = curop->op_sibling) { if (curop->op_type == OP_CONST) { ==== //depot/perl/t/op/int.t#6 (xtext) ==== Index: perl/t/op/int.t --- perl/t/op/int.t.~1~ Sat Oct 23 13:29:02 1999 +++ perl/t/op/int.t Sat Oct 23 13:29:02 1999 @@ -1,9 +1,7 @@ #!./perl -# $RCSfile: int.t,v $$Revision: 4.1 $$Date: 92/08/07 18:28:00 $ - -print "1..4\n"; +print "1..6\n"; # compile time evaluation if (int(1.234) == 1) {print "ok 1\n";} else {print "not ok 1\n";} @@ -15,3 +13,12 @@ $x = 1.234; if (int($x) == 1) {print "ok 3\n";} else {print "not ok 3\n";} if (int(-$x) == -1) {print "ok 4\n";} else {print "not ok 4\n";} + +$x = length("abc") % -10; +print $x == -7 ? "ok 5\n" : "# expected -7, got $x\nnot ok 5\n"; + +{ + use integer; + $x = length("abc") % -10; + print $x == 3 ? "ok 6\n" : "# expected 3, got $x\nnot ok 6\n"; +} End of Patch. ```
p5pRT commented 25 years ago

From @gisle

Gurusamy Sarathy \gsar@&#8203;ActiveState\.com writes​:

+{ + use integer; + $x = length("abc") % -10; + print $x == 3 ? "ok 6\n" : "# expected 3\, got $x\nnot ok 6\n"; +} End of Patch.

Is this safe?

Under 'use integer' you get the %-operator as implemented by C and C allow more than one result to be correct for negative operands. Perhaps something like is safer​:

use integer; $x = length("abc") % -10; $y = 3 % -10; print $x == $y ? "ok 6\n" : "# expected $y\, got $x\nnot ok 6\n";

Regards\, Gisle

p5pRT commented 25 years ago

From @gsar

On 24 Oct 1999 12​:25​:01 +0200\, Gisle Aas wrote​:

Under 'use integer' you get the %-operator as implemented by C and C allow more than one result to be correct for negative operands. Perhaps something like is safer​:

use integer; $x = length("abc") % -10; $y = 3 % -10; print $x == $y ? "ok 6\n" : "# expected $y\, got $x\nnot ok 6\n";

Good point\, but I think we could do somewhat better.

Sarathy gsar@​ActiveState.com

Inline Patch ```diff -----------------------------------8<----------------------------------- Change 4441 by gsar@auger on 1999/10/24 14:33:11 test in change#4428 needs strict interpretation of C modulus Affected files ... ... //depot/perl/t/op/int.t#8 edit Differences ... ==== //depot/perl/t/op/int.t#8 (xtext) ==== Index: perl/t/op/int.t --- perl/t/op/int.t.~1~ Sun Oct 24 07:33:15 1999 +++ perl/t/op/int.t Sun Oct 24 07:33:15 1999 @@ -25,5 +25,6 @@ { use integer; $x = length("abc") % -10; - print $x == 3 ? "ok 6\n" : "# expected 3, got $x\nnot ok 6\n"; + $y = (3/-10)*-10; + print $x+$y == 3 && abs($x) < 10 ? "ok 6\n" : "not ok 6\n"; } End of Patch. ```