### Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook

### Author Topic: Inconsistent behaviour of shr operator  (Read 5742 times)

#### Gammatester

• Jr. Member
• Posts: 69
##### Inconsistent behaviour of shr operator
« on: June 13, 2018, 09:28:47 am »
I found a inconsistent behaviour for the shr operator: The output of the following program
Code: Pascal  [Select][+][-]
1. const
2.   cs:  smallint = -1;
3.   cl:  longint  = -1;
4.   c64: int64  = -1;
5. var
6.   vs:  smallint;
7.   vl:  longint;
8.   v64: int64;
9. begin
10.   vs  := cs shr 1;
11.   vl  := cl shr 1;
12.   v64 := c64 shr 1;
13.   writeln('Smallint: ',vs, ' Longint: ',vl, ' Int64: ',v64);
14. end.
15.
is (using FPC304 target Win32 for i386, identical output for FPC304 target Win64 for x64)

Code: [Select]
`Smallint: -1 Longint: 2147483647 Int64: 9223372036854775807`
Since shr is a logical shift right
(https://www.freepascal.org/docs-html/current/ref/refsu46.html#x149-17100012.8.2) and not a arithmetic shift right I would expect the output for smallint to be 32767.

OK, for 32-bit you can argue that the smallint -1 is promoted to longint -1 (https://www.freepascal.org/docs-html/current/ref/refsu4.html, remark after Table 3.2), but this does not explain the shift result -1. And if this argument would be correct, the shifted longint under 64-bit should be -1 too.

Is this a bug which should be filed to the bug-tracker?

#### RayoGlauco

• Full Member
• Posts: 108
• Beers: 1567
##### Re: Inconsistent behaviour of shr operator
« Reply #1 on: June 13, 2018, 10:06:24 am »
I think the result should be 32767

shr
1111111111111111 ----> 0111111111111111 = 32767

I see no reason for the calculation to be different than in the other cases  .
But maybe someone knows best and can explain it .
To err is human, but to really mess things up, you need a computer.

#### Phemtik

• New Member
• Posts: 19
##### Re: Inconsistent behaviour of shr operator
« Reply #2 on: June 13, 2018, 10:29:50 am »
If you use that code

Code: Pascal  [Select][+][-]
1. var
2.   vs:  smallint = -1;
3.   vl:  longint = -1;
4.   v64: int64 = -1;
5. begin
6.   vs  := vs shr 1;
7.   vl  := vl shr 1;
8.   v64 := v64 shr 1;
9.   writeln('Smallint: ',vs, ' Longint: ',vl, ' Int64: ',v64);
10. end.

You get the corrct results of:
Code: [Select]
`Smallint: 32767 Longint: 2147483647 Int64: 9223372036854775807`
i think that have something to do with typed constants.
Intel i7-3610QM
Fedora 28

#### Gammatester

• Jr. Member
• Posts: 69
##### Re: Inconsistent behaviour of shr operator
« Reply #3 on: June 13, 2018, 10:46:32 am »
i think that have something to do with typed constants.
If I ran your code I still get -1, even the sequence
Code: Pascal  [Select][+][-]
1. vs := -1;
2. vs := vs shr 1;
gives -1 for both 32- and 64-bit.

What compiler/target are you using?

#### rvk

• Hero Member
• Posts: 4329
##### Re: Inconsistent behaviour of shr operator
« Reply #4 on: June 13, 2018, 11:11:23 am »
For both trunk 32 bit and Lazarus 1.8.2 64 bit (with FPC 3.0.4) it worked fine here.

Could you create a small project (with project options) and place it here?
Maybe it's something in the options.

What version (and IDE) are your using?

#### RayoGlauco

• Full Member
• Posts: 108
• Beers: 1567
##### Re: Inconsistent behaviour of shr operator
« Reply #5 on: June 13, 2018, 11:37:37 am »
Phemtik version works fine for me (Windows 8, Lazarus 1.8.4 FPC 3.0.4 win32)
To err is human, but to really mess things up, you need a computer.

#### Nitorami

• Sr. Member
• Posts: 378
##### Re: Inconsistent behaviour of shr operator
« Reply #6 on: June 13, 2018, 11:43:21 am »
Very odd, I always get -1 (windows 7, fpc 3.0.4, 32 bit).

From http://wiki.freepascal.org/Shr: "unlike the >> operator in the C language, the shr operator is a logical (not arithmetic) bit shift, even if the left operand is a signed integer. An implicit typecast and extension to a larger unsigned type may be performed before the shift operation."

I guess the shr is in fact done on the native integer size 32 bit:
Code: Pascal  [Select][+][-]
1. vs := -1;
2. writeln (vs shr 1);
results in 2147483647 (\$7FFFFFFF)

The code
Code: Pascal  [Select][+][-]
1. cs := -1;
2. vs := cs shr 1;
hence tries to assign 2147483647 to a smallint which is not possible. When turning on the range checks {\$R+}, which is always a good idea, the code throws a range check error, otherwise vs will be -1. I am rather surprised that some get a different result than that.

#### Gammatester

• Jr. Member
• Posts: 69
##### Re: Inconsistent behaviour of shr operator
« Reply #7 on: June 13, 2018, 11:43:36 am »
This is the complete Pascal source I used for the last test
Code: Pascal  [Select][+][-]
1. var
2.   vs:  smallint = -1;
3.   vl:  longint = -1;
4.   v64: int64 = -1;
5. begin
6.   vs  := vs shr 1;
7.   vl  := vl shr 1;
8.   v64 := v64 shr 1;
9.   writeln('Smallint: ',vs, ' Longint: ',vl, ' Int64: ',v64);
10. end.
11.
As already written, I am using 32- and 64-bit FPC304 under Win7/64-bit. Here compilations and outputs.
Code: [Select]
`D:\Work\Dev>D:\FPC304\bin\i386-win32\fpc.exe shr1.pasFree Pascal Compiler version 3.0.4 [2017/10/06] for i386Copyright (c) 1993-2017 by Florian Klaempfl and othersTarget OS: Win32 for i386Compiling shr1.pasLinking shr1.exe10 lines compiled, 0.1 sec, 26560 bytes code, 1300 bytes dataD:\Work\Dev>shr1.exeSmallint: -1 Longint: 2147483647 Int64: 9223372036854775807D:\Work\Dev>fpc64304 shr1.pasD:\Work\Dev>D:\FPC304\bin\i386-win32\ppcrossx64.exe shr1.pasFree Pascal Compiler version 3.0.4 [2017/10/06] for x86_64Copyright (c) 1993-2017 by Florian Klaempfl and othersTarget OS: Win64 for x64Compiling shr1.pasLinking shr1.exe10 lines compiled, 0.1 sec, 31072 bytes code, 1348 bytes dataD:\Work\Dev>shr1.exeSmallint: -1 Longint: 2147483647 Int64: 9223372036854775807`and attached the FPC.CFG file.

#### rvk

• Hero Member
• Posts: 4329
##### Re: Inconsistent behaviour of shr operator
« Reply #8 on: June 13, 2018, 11:49:33 am »
Okay, what does this give you?

Quote
D:\FPC304\bin\i386-win32\fpc.exe shr1.pas -O1

(-O1 optimization level is default in Lazarus)
« Last Edit: June 13, 2018, 11:51:17 am by rvk »

#### circular

• Hero Member
• Posts: 3511
##### Re: Inconsistent behaviour of shr operator
« Reply #9 on: June 13, 2018, 11:51:33 am »
I guess it is a bit of a hole in the pascal language. There is no way to tell you want an arithmetic shift or a logical shift unless using assembler.
Conscience is the debugger of the mind

#### Gammatester

• Jr. Member
• Posts: 69
##### Re: Inconsistent behaviour of shr operator
« Reply #10 on: June 13, 2018, 12:01:28 pm »
Okay, what does this give you?

Quote
D:\FPC304\bin\i386-win32\fpc.exe shr1.pas -O1

(-O1 optimization level is default in Lazarus)
Yes, with -O1 I get 32767 with var vs:  smallint = -1.  But with my original program using typed constants I still get -1.

And another observation. If I use the http://wiki.freepascal.org/Shr test example I get the output 9223372036854775806, i.e. the smallint -3 is promoted to int64 -3, then why the longint -1 is not promoted to int64 -1 ?
« Last Edit: June 13, 2018, 12:14:03 pm by Gammatester »

#### rvk

• Hero Member
• Posts: 4329
##### Re: Inconsistent behaviour of shr operator
« Reply #11 on: June 13, 2018, 12:15:46 pm »
Is says
Quote
An implicit typecast and extension to a larger unsigned type may be performed before the shift operation.
So, it's not always promoted to a larger unsigned type.

And these seem to give the same result:
Code: Pascal  [Select][+][-]
1. WriteLn(ShortInt(-2) shr 1); // 9223372036854775807
2. WriteLn(ShortInt(-1) shr 1); // 9223372036854775807

#### circular

• Hero Member
• Posts: 3511
##### Re: Inconsistent behaviour of shr operator
« Reply #12 on: June 13, 2018, 04:01:57 pm »
I would suggest to avoid doing shr on a negative number.

EDIT: There is a system function for the arithmetic shift
http://lazarus-ccr.sourceforge.net/docs/rtl/system/sarlongint.html

You could emulate it with something like that:
Code: Delphi  [Select][+][-]
1. function ASR(AValue: LongInt; AShift: Byte): LongInt;
2. begin
3.   if AValue < 0 then
4.     result := -1-((-1-AValue) shr AShift)
5.   else
6.     result := AValue shr AShift;
7. end;
8.
« Last Edit: June 13, 2018, 07:52:59 pm by circular »
Conscience is the debugger of the mind

#### Phemtik

• New Member
• Posts: 19
##### Re: Inconsistent behaviour of shr operator
« Reply #13 on: June 13, 2018, 04:30:27 pm »
normally you can make a arithmetic right shift (SAR) with x div 2.
free pascal do that even. The problem is, the compiler is not optimized for that particular example.
It make the shift in a 64 / 32 -bit register and doesn't make a shift in the register size of the variable.

But to have SAR and SAL, would be really nice.
Intel i7-3610QM
Fedora 28

#### howardpc

• Hero Member
• Posts: 3553
##### Re: Inconsistent behaviour of shr operator
« Reply #14 on: June 13, 2018, 04:46:58 pm »
But to have SAR and SAL, would be really nice.
Are you aware that 2.6.0 introduced the intrinsics:
SARShortInt
SARSmallInt
SARLongInt
SARInt64
?