var x, y: Integer;
begin
  x := 5;
  y := -5;
  ShowMessage(IntToStr(x shr 1) + ' =====> ' + IntToStr(5 shr 1) + ' , '
            + IntToStr(y shr 1) + ' =====> ' + IntToStr(-5 shr 1));
end;下面是运行结果.
---------------------------
Project1
---------------------------
2 =====> 2 , 2147483645 =====> -3
---------------------------
OK   
---------------------------
在需要高效运算的地方居然不能对负值变量shr ????? 没天理啊!

解决方案 »

  1.   

    这不是shr的问题,是编译器优化的结果。编译器处理(-5 shr 1)会当成一个常量来处理,会先算出 -5 shr 1的值作为常数保存,而不会在运行时计算
    -5(二进制11111111111111111111111111111011)是负数,右移1位成01111111111111111111111111111101
    编译器会按-5是负数而把符号位置1,因此编译后直接保存为-3(11111111111111111111111111111101)的常量
    而(y shr 1)会编译为汇编码(shr edi,1)这样的,按照shr的定义,右移后高位是补0的,不会因为是负数而置符号位,所以结果就是01111111111111111111111111111101,这个是没问题的。
    有符号数的移位,如果你要用shr,需要自己处理符号位
      

  2.   

    补充一下,delphi里没有算术右移sar,所以估计是delphi编译(-5 shr 1)时会自动按(-5 sar 1)来算常量值
    代码里运算时,那就要程序自己处理了
    比如:
    if (是正数)
      xx := x shr 1
    else 
      xx := (x shr 1) or $80000000
      

  3.   


      (x shr 1) or $80000000 也不是正确的结果.........  你说这是没问题的,为什么在c,c++,甚至VB里都可以得到正确结果?其它编译器都可以负值变值 shr,delphi不行?网上也没查到相关文章说明。  我不是要讨论自己怎么写函数处理,我是觉得delphi走了这么多年,从辉煌到末落...居然还有这么个BUG....
      
      

  4.   

    在delphi中shr运算符只会编译成x86指令集的shr,而不会对有符号整型编译成sar。这不是bug,而是向前兼容,turbo pascal/borland pascal中就一直如此,free pascal同样不会得到sar的结果
    实在想用sar的话就内嵌汇编吧另外,根据c99标准(n1362.pdf)中对>>运算符语义的规定:
    6.5.7
    ...
    5  The result of E1  >>  E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type 
    or if E1 has a signed type and a nonnegative value, the value of the result is the integral 
    part of the quotient of E1 /2E2. If E1 has a signed type and a negative value, the resulting
     value is implementation-defined.
    也就是说,在c语言中,>>对有符号负整数的运算结果是 implementation-defined 行为,编译器编译成shr还是sar都没问题,没有你所谓的“正确结果”
      

  5.   

    举个例子,为了方便数据类型用的是Bytevar 
      Tmp_Int: Byte;
    begin
      Tmp_Int := 254;  //二进制编码:1111 1110
      ShowMessage(IntToStr(Tmp_Int shr 1)); //"127"
    end;var 
      Tmp_Int: ShortInt; //-128 - 127
    begin
      Tmp_Int := -1;  //二进制编码:1111 1110 ;;;1的二进制编码:0000 0001;; -1的编码是在1的基础上首位置1,符号位.后面几位按位补码即1111 1110
      ShowMessage(IntToStr(Tmp_Int shr 1)); //"127"
    end;
    不知道说清楚没有
      

  6.   

    var 
      Tmp_Int: Byte;
    begin
      Tmp_Int := 254;  //二进制编码:1111 1110
      ShowMessage(IntToStr(Tmp_Int shr 1)); //"127"
    end;var 
      Tmp_Int: ShortInt; //-128 - 127
    begin
      Tmp_Int := -1;  //二进制编码:1111 1110 ;;;1的二进制编码:0000 0001;; -1的编码是在1的基础上首位置1,符号位.后面几位按位补码即1111 1110
      ShowMessage(IntToStr(Byte(Tmp_Int) shr 1)); //"127"
    end;发现了点问题,修正