New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Possible bug in remainder computation (m % n) for negative numbers -- #17097
Comments
From aab@purdue.eduThe attachment is the 'perlbug' output. -- Thanks, -- Paul Townsend |
From aab@purdue.eduCreated by aab@purdue.eduWithout 'use integer;', I think 'perl' miscomputes the remainder op (m % n) for
use integer; print "\n'perl' with 'use integer;'\n"; print "\n'perl' using straight computation\n";
'perl' without 'use integer;' 'perl' with 'use integer;' 'perl' using straight computation I started using 'perl4' in the good-ol-days and have enjoyed using it ever Thanks for all your hard work. Paul Townsend (aab@purdue.edu) Perl Info
|
From @xenu(posting again, this time via RT web interface, because it seems that the mailing list integration has swallowed my reply) On Wed, 17 Jul 2019, at 01:38, Paul Townsend (via RT) wrote:
The operator behaves as documented, see https://perldoc.pl/perlop#Multiplicative-Operators.
In case of -11 % 2, the largest multiple of 2 that is less than or -11 - (-12) = 1 According to perldoc, with 'use integer' enabled, the behaviour of
PS. As you can see on Wikipedia[1] there's no consensus on how modulo [1] - https://en.wikipedia.org/wiki/Modulo_operation#Remainder_calculation_for_the_modulo_operation |
The RT System itself - Status changed from 'new' to 'open' |
From @sisyphusJust wanted to add that python3, python2, and perl6 all treat -ve operands The GMP library ignores the sign of the divisor, but not the sign of the They're the same result because -2 modulo 3 is congruent to 1 modulo 3. If one wants to portably allow -ve operands in mod operations, it might be Cheers, On Wed, Jul 17, 2019 at 10:37 AM Tomasz Konojacki via RT <
|
From aab@purdue.eduThis is from an old fogey who learned his math way back when. Back in the day, a remainder for the division 'a / b' was computed as r = a - (trunc (a /b) * b) Unless r = 0, the sign of 'r' is always the same as the sign of 'a'. The sign of 'b' doesn't matter since it's "canceled" because 'b' is effectively in both the numerator and denominator of '(trunc (a /b) * b)'. Now IEEE comes along and throws in a rounding consideration for the 'a / b'. This is NOT the '%' remainder! If folks wish to do it IEEE's way, a separate function should be provided for it. I have noted functions on the net named IEEEremainder and std::remainder that do the job. In perl, the equation seems to be r = a - (round(a/b) * b) I think that computing a remainder any way other than using the first equation above can produce an incorrect result. Okay, enough ranting. -- Thanks, -- Paul Townsend ________________________________ Just wanted to add that python3, python2, and perl6 all treat -ve operands The GMP library ignores the sign of the divisor, but not the sign of the They're the same result because -2 modulo 3 is congruent to 1 modulo 3. If one wants to portably allow -ve operands in mod operations, it might be Cheers, On Wed, Jul 17, 2019 at 10:37 AM Tomasz Konojacki via RT <
|
From @sisyphusOn Wed, 17 Jul 2019 10:59:56 -0700, aab@purdue.edu wrote:
[snip]
Yep - I've no issue with any of that. Regarding the % operator as a "modulo arithmetic" operator it's just as valid to say that -11 % 2 is 1, as it is to say -11 % 2 is -1. I personally think that the positive value is the one that should be returned in all modulo operations but, as we've seen, that's not always the case. However, the value returned by ($x % $y) should always be congruent to the value returned by your remainder formula % $y. Note that the following script detects no inconsistency for your formula versus the % operator - and that's for both -ve and +ve dividends, and irrespective of whether the integer pragma is in use. ################################ # With +ve dividends # With -ve dividends # Check whether $d % $mod is congruent to rem($d, $mod) # Calculate remainder sub min { sub max { ######################################## Cheers, |
From aab@purdue.eduI think that there is an identity here that is occasionally being violated for at least some negative numbers when using 'round' in the remainder calculation. It is always true for "trunc". a = -11, b = 2 is a counter example for "round". s = a < 0 ? -1 : 1 a % b == s * (abs (a) % b) I think that we tend to forget that machine floating point numbers are, at worst, approximations only. Whether the division result is rounded up or down can at times be in the lap of the gods. A good example of the effects of approximation is found in the 'int' description in the perlfunc(1) man page. It uses -6.725/0.025 as the example. If you are just eyeballing it, the result should be -269. However, the actual floating point result on a 64-bit box is -268.9999999999999432. 'round' works nicely here. -- Thanks and have a great day, -- Paul Townsend ________________________________ On Wed, 17 Jul 2019 10:59:56 -0700, aab@purdue.edu wrote:
[snip]
Yep - I've no issue with any of that. Regarding the % operator as a "modulo arithmetic" operator it's just as valid to say that -11 % 2 is 1, as it is to say -11 % 2 is -1. I personally think that the positive value is the one that should be returned in all modulo operations but, as we've seen, that's not always the case. However, the value returned by ($x % $y) should always be congruent to the value returned by your remainder formula % $y. Note that the following script detects no inconsistency for your formula versus the % operator - and that's for both -ve and +ve dividends, and irrespective of whether the integer pragma is in use. ################################ # With +ve dividends # With -ve dividends # Check whether $d % $mod is congruent to rem($d, $mod) # Calculate remainder sub min { sub max { ######################################## Cheers, |
From @tonycozOn Wed, 17 Jul 2019 10:59:56 -0700, aab@purdue.edu wrote:
The code that calculates the remainder in perl for integers is: UV ans; if (!right) ans = left % right; Note that the actual remainder operation is done with positive numbers and then adjusted based on the original signs of the operands. There's no rounding involved. Given this behaves as documented (or not documented with use integer), I'll close this in a day or two. Tony |
From aab@purdue.eduI assume we are talking arithmetic using the machines integer instructions. Whatever instruction set is used, the perl encoding of remainder is wrong. Once ans has been computed, its absolute value CANNOT change except maybe for some end cases. Also, the sign of the right hand operand will (not should) have no effect on the sign of ans which, except for zero, must have the sign of the left operand. ________________________________ On Wed, 17 Jul 2019 10:59:56 -0700, aab@purdue.edu wrote:
The code that calculates the remainder in perl for integers is: UV ans; if (!right) ans = left % right; Note that the actual remainder operation is done with positive numbers and then adjusted based on the original signs of the operands. There's no rounding involved. Given this behaves as documented (or not documented with use integer), I'll close this in a day or two. Tony |
From @tonycozOn Fri, 02 Aug 2019 14:31:44 -0700, aab@purdue.edu wrote:
My point was that no rounding is done. As Tomas pointed out the sign of the modulus/remainder operation varies from language to language, and perl's behaviour is documented, and similar to many other languages. Changing it at this point would break existing code for no good reason. Closing. Tony
|
@tonycoz - Status changed from 'open' to 'rejected' |
Migrated from rt.perl.org#134290 (status was 'rejected')
Searchable as RT134290$
The text was updated successfully, but these errors were encountered: