About the most likely overflow problem in binary time

For example, part of the code of an article I wrote before https://blog.csdn.net/qq_34115899/article/details/79526538

public int rank(int key, int n) {  
       int lo = 0, hi = n - 1;  
       while (lo <= hi) {  
           int mid = lo + ((hi - lo) >> 1); //>>1 is divided by 2 or directly (lo + hi) >>> 1
           // Why not directly (lo+hi)>>1, because lo+hi may overflow, but hi-lo does not overflow, lo+(hi-lo)>>1 is less than hi, and it does not overflow, which is safer  
           int cmp = key - a[mid];// a is an ordered array  
           if (cmp < 0) {  
               hi = mid - 1;  
           } else if (cmp > 0) {  
               lo = mid + 1;  
           } else {  
               return mid;  
           }  
       }  
       return lo;  
   }  

I use the mid processing method above

int mid = lo + ((hi - lo) >> 1); 


But I found that Arrays.binarySearch() method when dealing with mid

int mid = (low + high) >>> 1;

Bitwise operators in Java:

>> means arithmetic right shift, if the number is positive, the high order is filled with 0, if it is negative, the high order is filled with 1;

>>> means logical right shift , also known as unsigned right shift , that is, if the number is positive, the high-order bits are filled with 0, and if the number is negative, the high-order bits are also filled with 0 after the right shift.


For example, int range  -2147483648~2147483647 

It is more than 2.1 billion. If the input exceeds the int range, the compiler will report an error, and obviously you will know that you are wrong. But the key is that each number entered is large and does not exceed the int range, but the addition or multiplication operation is out of range! ! ! This situation is difficult to detect and will cause unnecessary trouble

>>>1 operation is very good, for example

Do the following respectively:

System.out.println(1500000000 + 1500000000);

System.out.println((1500000000 + 1500000000) >> 1);
System.out.println((1500000000 + 1500000000) >>> 1);

 show

-1294967296 (150000000 + 1500000000 (1.5 billion plus 1.5 billion))

10110010110100000101111000000000

 -647483648 (>>1 case)

11011001011010000010111100000000

1500000000 (>>>1 case)

01011001011010000010111100000000    (just add and divide by 2, that is, unsigned right shift one bit)

Another set of examples

Do the following respectively

System.out.println(1500000000 + 1200000000); // 15亿加12亿
System.out.println((1500000000 + 1200000000) >> 1);
System.out.println((1500000000 + 1200000000) >>> 1);

show

-1594967296

10100000111011101011101100000000

-797483648 (after >>1)

11010000011101110101110110000000

1350000000 (after >>>1)

01010000011101110101110110000000   (just add and divide by 2, that is, unsigned right shift one bit)

To sum up, >>>1 is safer and will not affect the result due to overflow from addition .

But >>>1 can only solve the problem of addition overflow , and almost cannot solve the problem of multiplication overflow (unless there is a coincidence like multiplying by 2 and then >>>1, the high-order data is truncated and not saved), the solution is Use a larger data type to handle multiplication overflow.

============================== I am a slow programmer ============= =============


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325947244&siteId=291194637