Recent

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

Phemtik

  • New member
  • *
  • Posts: 17
Re: Inconsistent behaviour of shr operator
« Reply #15 on: June 13, 2018, 04:55:17 pm »
Hm nice, I did't know.
Is it somewhere in the wiki/documentation? i hadn't found.
« Last Edit: June 13, 2018, 05:04:11 pm by Phemtik »
Intel i7-3610QM
Fedora 28

howardpc

  • Hero Member
  • *****
  • Posts: 2833
Re: Inconsistent behaviour of shr operator
« Reply #16 on: June 13, 2018, 06:45:15 pm »
See here

circular

  • Hero Member
  • *****
  • Posts: 2785
    • Personal webpage
Re: Inconsistent behaviour of shr operator
« Reply #17 on: June 13, 2018, 07:51:02 pm »
Oh that's great. It could be added to the doc then to make people aware of it:
http://wiki.lazarus.freepascal.org/Shr
https://freepascal.org/docs-html/ref/refsu46.html
Conscience is the debugger of the mind

ASerge

  • Hero Member
  • *****
  • Posts: 998
Re: Inconsistent behaviour of shr operator
« Reply #18 on: June 14, 2018, 06:37:47 pm »
I found a inconsistent behaviour for the shr operator: The output of the following program
Code: [Select]
Smallint: -1 Longint: 2147483647 Int64: 9223372036854775807Since shr is a logical shift right
Rules:
1. shr operation is always a logical shift (unsigned).
2. shr operation is 32 bits for the size of the operands <= 32 bits and 64 bits otherwise.

Now details:
vs := cs shr 1;
cs is SmallInt ($FFFF) are sign extended to 32 bit ($FFFFFFFF). Now it shifted without sign ($7FFFFFFF). Now it's needed store to SmallInt. If {$RANGECHECKS ON} will be range error (very big for SmallInt), otherwize only last 16 bits saved ($FFFF). Result is -1.

vl := cl shr 1;
cl is not changed (already 32), signed, so simple unsigned shift ($7FFFFFFF). Because result is fit in vl, so it's simple 2147483647.
Same behaviour for 64 bit integer.

It's all Delphi compatible (including range error).

What about vs := vs shr 1? With optimization, compiler coded this as in-place operation (which ignore rule 2), but do range check as by rule 2 (range error). It's NOT Delphi compatible. Delphi always convert to 32 bit (and result is -1). Without optimization FPC result is -1.

PS: for constants shr operation make by compiler itself, and result can be arithmetic shift or using large size operand (not documented and version depended).

Gammatester

  • Jr. Member
  • **
  • Posts: 69
Re: Inconsistent behaviour of shr operator
« Reply #19 on: June 14, 2018, 07:33:07 pm »
Rules:
1. shr operation is always a logical shift (unsigned).
2. shr operation is 32 bits for the size of the operands <= 32 bits and 64 bits otherwise.
If rule 2 were correct, how do you explain
Quote
WriteLn(ShortInt(-1) shr 1); // 9223372036854775807

ASerge

  • Hero Member
  • *****
  • Posts: 998
Re: Inconsistent behaviour of shr operator
« Reply #20 on: June 14, 2018, 07:39:44 pm »
If rule 2 were correct, how do you explain
Quote
WriteLn(ShortInt(-1) shr 1); // 9223372036854775807
Did you read my PS: ?

Gammatester

  • Jr. Member
  • **
  • Posts: 69
Re: Inconsistent behaviour of shr operator
« Reply #21 on: June 14, 2018, 08:03:38 pm »
If rule 2 were correct, how do you explain
Quote
WriteLn(ShortInt(-1) shr 1); // 9223372036854775807
Did you read my PS: ?
Yes, but then the rules are not very clear. It looks like the same disclaimer applies as with
Quote
An implicit typecast and extension to a larger unsigned type may be performed before the shift operation.
I would like do have definite rules.

Nitorami

  • Sr. Member
  • ****
  • Posts: 346
Re: Inconsistent behaviour of shr operator
« Reply #22 on: June 14, 2018, 09:36:13 pm »
I understand that shr is normally done on nativeinteger, i.e. 32 bit on 32 bit platforms, 64 on 64 bit platforms. EXCEPT if evaluation can already be done by the parser, which consistently uses 65bit (yes) arithmetic, hence

Code: Pascal  [Select]
  1. WriteLn(ShortInt(-1) shr 1); // 9223372036854775807

But whatever the rules are, they should be consistent. What still puzzles me is that some seem to get 32767 as result of vs := cs shr 1;
I cannot confirm that; with FPC 3.0.4, Win 7 and win 10, with and without optimisation, and whatever other settings,  I always get -1, but never 32767. !?!

jamie

  • Hero Member
  • *****
  • Posts: 973
Re: Inconsistent behaviour of shr operator
« Reply #23 on: June 15, 2018, 12:21:38 am »
First , Shortint are byte size so you won't get 32767, you'll get 127 or what ever it is >:(

smallInt are word size.

when shifting a signed integer the smallest value is -1, so shifting -1 will result in -1.

 0 and up are positive numbers which is why you can shift all the way to 0.

 and if you were to shl 7 with a -1 you would get -128, one more you get 0

 You could almost look at it like SHR is actually a SHL and SHL is actually a SHR with - numbers

 with the exception that -1 is the smallest number.

This is how I understand it...

P.S.
 
The compiler always tries to elevate the type to an integer, but if you cast around the whole equation it
will do what you ask for.





Gammatester

  • Jr. Member
  • **
  • Posts: 69
Re: Inconsistent behaviour of shr operator
« Reply #24 on: June 15, 2018, 08:52:50 am »
when shifting a signed integer the smallest value is -1, so shifting -1 will result in -1.

 0 and up are positive numbers which is why you can shift all the way to 0.

 and if you were to shl 7 with a -1 you would get -128, one more you get 0
...
This is how I understand it...
Your understanding is wrong. shr is a logical right shift, that  means the lowest bits go to nirvana and zero  bits are inserted at the highest positions instead. As shown by
                  shr
1111111111111111 ----> 0111111111111111 = 32767

Theoretically the results are clearly defined by the bit-size of the variables and the shift count. The problems in practice come from the promotion of small-bit-sized types to signed longint or int64, to which the logical shift is applied (and constant expressions are handled by the compiler with int64). Your `shifting -1 will result in -1` is seen to be completely wrong by looking at the results for longint and int64.