Inconsistent signed/unsigned results in right shift

Hi all,

It seems that (-1)>>(1<<32) and (-1)>>(1<<64) produces inconsistent results (at least with SWI 8.0.3). This is probably due to the transition between small and large integer representations (we are fixing the same bug in Ciao right now). See log attached.

Cheers,
Jose

Welcome to SWI-Prolog (threaded, 64 bits, version 8.0.3)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit http://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

?- X is 1 >> (1<<32).
X = 0.

?- X is 1 >> (1<<64).
X = 0.

?- X is 1 >> (1<<128).
X = 0.

?- X is (-1) >> (1<<128).
X = 0.

?- X is (-1) >> (1<<64).
X = 0.

?- X is (-1) >> (1<<32).
X = -1.

?- X is (-1) >> (1<<16).
X = -1.

?- 
1 Like

Right shifting with (1<<32) is right shifting with 4294967296. You need a
number larger than 0.5 GB to see a different result than 0 respectively -1.
In my system I even do not allow it:

This is allowed:

?- X is 1>>(1<<30). 
X = 0 
?- X is (-1)>>(1<<30).
X = -1

This is already not anymore allowed:

Jekejeke Prolog 4, Runtime Library 1.4.2 (12 November 2019)

?- X is 1>>(1<<31). 
Error: Illegal int integer (not between - 2^31 and 2^31-1). 	
         is/2 
?- X is (-1)>>(1<<31). 
Error: Illegal int integer (not between - 2^31 and 2^31-1). 	
         is/2

Mathematically we could allow a larger shift and just return 0 or -1
depending on the sign if the argument is anyway smaller than 0.5 GB.
But the range check makes it easier to implement.

BTW: The SWI-Prolog error starts at 63. Why it exactly returns 0 I don’t know:

Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.15)

?- between(61,64,X), Y is (-1)>>(1<<X), write(X-Y), nl, fail.
61- -1
62- -1
63-0
64-0
false.

By my system are you referring to the machine you are using or Jekejeke Prolog

See edited post.

I noticed that the examples were run with
SWI-Prolog (threaded, 64 bits, version 8.0.3) so I decided to try the latest version
SWI-Prolog (threaded, 64 bits, version 8.1.19-43-ge65571d98)

The results are the same except for

?- X is (-1) >> (1<<32).
X = 0.
Test cases. Click triangle to expand.
:- begin_tests(bit_shift).

test(100) :-
    X is 1 >> (1<<16),
    assertion( X == 0 ).

test(200) :-
    X is 1 >> (1<<32),
    assertion( X == 0 ).

test(300) :-
    X is 1 >> (1<<64),
    assertion( X == 0 ).

test(400) :-
    X is 1 >> (1<<128),
    assertion( X == 0 ).

test(600) :-
    X is (-1) >> (1<<16),
    assertion( X == -1 ).

test(700) :-
    X is (-1) >> (1<<32),
    assertion( X == 0 ).

test(800) :-
    X is (-1) >> (1<<64),
    assertion( X == 0 ).

test(900) :-
    X is (-1) >> (1<<128),
    assertion( X == 0 ).

:- end_tests(bit_shift).

test 700, 800 and 900 the expected outcome should be also -1,
just like test 600. Otherwise there wouldn’t be a bug.

BTW: Not only SWI-Prolog has a bug, also GNU-Prolog
has a bug. For GNU-Prolog its bug happens much earlier,
for much smaller shifts:

GNU Prolog 1.4.5 (64 bits)

?- between(4,7,X), Y is 1>>(1<<X), write(X-Y), nl, fail. 
4-0
5-0
6-1
7-1