* * *

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

Gammatester

  • Jr. Member
  • **
  • Posts: 64
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

  • Jr. Member
  • **
  • Posts: 78
  • 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: 17
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: 64
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: 3461
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

  • Jr. Member
  • **
  • Posts: 78
  • 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: 344
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: 64
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.pas
Free Pascal Compiler version 3.0.4 [2017/10/06] for i386
Copyright (c) 1993-2017 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling shr1.pas
Linking shr1.exe
10 lines compiled, 0.1 sec, 26560 bytes code, 1300 bytes data

D:\Work\Dev>shr1.exe
Smallint: -1 Longint: 2147483647 Int64: 9223372036854775807

D:\Work\Dev>fpc64304 shr1.pas

D:\Work\Dev>D:\FPC304\bin\i386-win32\ppcrossx64.exe shr1.pas
Free Pascal Compiler version 3.0.4 [2017/10/06] for x86_64
Copyright (c) 1993-2017 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling shr1.pas
Linking shr1.exe
10 lines compiled, 0.1 sec, 31072 bytes code, 1348 bytes data

D:\Work\Dev>shr1.exe
Smallint: -1 Longint: 2147483647 Int64: 9223372036854775807
and attached the FPC.CFG file.

rvk

  • Hero Member
  • *****
  • Posts: 3461
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: 2745
    • Personal webpage
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: 64
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: 3461
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: 2745
    • Personal webpage
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: 17
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: 2781
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
?

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus