About the question itself, the former answers have explained it clearly. But when I tried to figure out its operation mechanism, I found something interesting.
The new question is what will happen when the code mid = left + right - left is running, will it do add first and then sub? If so, whether it'll be overflow in the process?, will the result be infected?
The answer is whether add first sub second depends on compiler, it'll be overflow in the process if it do so, and the result won't be infected.
Test Code 1:
int square() {
int mid, left = 2147483647, right = 2147483647;
mid = left + right - left;
return mid;
}
After x86-64 Clang 18.1.0 compiled:
square: # @square
push rbp
mov rbp, rsp
mov dword ptr [rbp - 8], 2147483647
mov dword ptr [rbp - 12], 2147483647
mov eax, dword ptr [rbp - 8]
add eax, dword ptr [rbp - 12] # add first (eax = -2)
sub eax, dword ptr [rbp - 8] # sub second (eax = 2147483647)
mov dword ptr [rbp - 4], eax
mov eax, dword ptr [rbp - 4]
pop rbp
ret
After x86-64 gcc 14.1 compiled
square:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], 2147483647
mov DWORD PTR [rbp-8], 2147483647
mov eax, DWORD PTR [rbp-8]
mov DWORD PTR [rbp-12], eax
mov eax, DWORD PTR [rbp-12] # it does't even do the simple math totally (optimized)
pop rbp
ret
After loongarch64 gcc 14.1.0 compiled
square:
addi.d $r3,$r3,-32
st.d $r22,$r3,24
addi.d $r22,$r3,32
lu12i.w $r12,2147479552>>12 # 0x7ffff000
ori $r12,$r12,4095
st.w $r12,$r22,-20
lu12i.w $r12,2147479552>>12 # 0x7ffff000
ori $r12,$r12,4095
st.w $r12,$r22,-24
ld.w $r12,$r22,-24 # first
st.w $r12,$r22,-28 # second (same like gcc too, optimized)
ldptr.w $r12,$r22,-28
or $r4,$r12,$r0
ld.d $r22,$r3,24
addi.d $r3,$r3,32
jr $r1
So, the conclusion is although the process maybe overflowed, the result isn't infected totally(Note don't confuse it with left + right, which will indeed terminate your running)
Back to the left+(right-left)/2, according to the assembly code produced by clang, it'll do (right-left) first, then the division /, and finally the add +.
Test Code 2:
int square() {
int mid, left = 2147483647, right = 2147483647;
mid = left + (right - left) / 2 ;
return mid;
}
square: # @square
push rbp
mov rbp, rsp
mov dword ptr [rbp - 8], 2147483647
mov dword ptr [rbp - 12], 2147483647
mov eax, dword ptr [rbp - 8]
mov dword ptr [rbp - 16], eax # 4-byte Spill
mov eax, dword ptr [rbp - 12]
sub eax, dword ptr [rbp - 8] # "sub first"
mov ecx, 2
cdq
idiv ecx # "division second"
mov ecx, eax
mov eax, dword ptr [rbp - 16] # 4-byte Reload
add eax, ecx # "add last"
mov dword ptr [rbp - 4], eax
mov eax, dword ptr [rbp - 4]
pop rbp
ret
Disclaimer: the assembly code is from Compilers, the answer is just for fun.