Skip to content
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

right shift with signed input doesn't match documentation #107

Closed
danaj opened this issue Jan 18, 2021 · 1 comment
Closed

right shift with signed input doesn't match documentation #107

danaj opened this issue Jan 18, 2021 · 1 comment

Comments

@danaj
Copy link
Collaborator

danaj commented Jan 18, 2021

The documentation in lib/Sidef/Types/Number/Number.pod says:

a >> b
Bitwise right-shift, equivalent with (assuming a and b are integers):
int(a / 2**b)

which looks like truncated division. It seems to do a floor division instead. E.g. from the Sidef online system (btw, awesome!):

say(-5/2);
say(int(-5/2));
say(floor(-5/2));
say(-5 >> 1);

-2.5
-2
-3
-3

I tried a single 67-bit input and got similar results. It's using floor. Of course with positive arguments they're all identical.

I just added left and right integer shifting to Math::Prime::Util, with two versions of right shifting (one truncating which matches Pari and Mathematica, and one flooring which matches most programming languages). I can see decent arguments for either one, so honestly I don't have any strong opinions on whether one is better than another. But it's important to document and be consistent.

@trizen
Copy link
Owner

trizen commented Jan 18, 2021

There seems to be quite a bit of discrepancy between programming languages regarding integer division with a negative operand.

Python 2:

print((-5)/2)     # -3
print((-5) >> 1)  # -3

Python 3:

print((-5) // 2)    # -3
print((-5) >> 1)    # -3

Perl:

use integer;
CORE::say ((-5)/2);      # -2
CORE::say ((-5) >> 1);   # -3

Raku:

say ((-5) div 2);  # -3
say ((-5) +> 1);   # -3

Julia:

println(div(-5, 2));  # -2
println((-5) >> 1);   # -3

PARI/GP:

print((-5)\2);   \\ -3
print((-5)>>1);  \\ -2

Sidef:

say (-5 // 2)  # -2
say (-5 >> 1)  # -3

From the above examples, Sidef matches Perl and Julia regarding integer-division (doing truncated division), while the right-shift is doing floor-division in all examples, except for PARI/GP.

There are some pros for integer division to mean floor(a/b) instead of int(a/b), mainly because the floor-division is more useful in mathematics than truncated-division and is also used in more mathematical formulas, like: a mod b = a - b*floor(a/b):

func my_mod(a,b) {
    a - b*floor(a/b)        # ok
    #a - b*idiv(a,b)        # error
}

for a in (-10 .. 10), b in (-10 .. 10) {
    assert_eq(a%b, my_mod(a,b), "#{a} % #{b}") if (b != 0)
}

Thanks for reporting the issue. I will fix the documentation and, I think, I will also change the behavior of a // b to do floor-division instead of truncated-division.

@trizen trizen closed this as completed in 8eaa5bf Jan 18, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants