为什么 start + (end – start)/2 是在 (start + end)/2 上计算数组中间的首选方法?
我很确定一旦你知道数组的开始索引和结束索引,每个人都能找到数组的中间索引,但是使用start + (end – start)/2 over (start + end)/2有一定的好处,描述如下:
找到中间索引的第一种方法是
mid = (start + end)/2
但是这种方法存在问题,如果 start 或 end 或两者的值都是INT_MAX ,则会导致整数溢出。
计算中间指数的更好方法是:
mid = start + (end - start)/2
让我们在 C 程序中尝试这两种方法:
C
// program for calculating mid of array
#include
#include
int main()
{
int start = INT_MAX, end = INT_MAX;
printf("start = %dn", start);
printf("end = %dn", end);
// method 1
int mid1 = (start + end) / 2;
printf("mid using (start + end)/2 = %dn", mid1);
// method 2
int mid2 = start + (end - start) / 2;
printf("mid using start + (end - start)/2 = %dn", mid2);
return 0;
}
C
int s = 2, e = 3;
int* start = &s;
int* end = &e;
int* mid = (start + end) / 2;
C
int s = 2, e = 3;
int* start = &s;
int* end = &e;
int* mid = start + (end - start) / 2;
输出:
start = 2147483647
end = 2147483647
mid using (start + end)/2 = -1
mid using start + (end - start)/2 = 2147483647
注意: (end – start) 如果 end < 0 或 start < 0 可能会溢出
如果您看到输出,通过使用第二种方法,您会得到正确的输出,第一种方法无法计算 mid,如果您使用此索引(在这种情况下为 -1) ,则可能会由于数组索引无效而导致分段错误。
即使您使用指针,start + (end – start)/2 也有效:
例子 :
方法一
C
int s = 2, e = 3;
int* start = &s;
int* end = &e;
int* mid = (start + end) / 2;
输出 :
error: invalid operands of types ‘int*’ and ‘int*’ to binary ‘operator+’
int *mid = (start + end)/2;
方法二
C
int s = 2, e = 3;
int* start = &s;
int* end = &e;
int* mid = start + (end - start) / 2;
输出 :
It will compile and give expected results
说明: C 不支持指针加法,而支持指针减法,原因是减法的结果是操作数之间的差异(在数组元素上)。减法表达式产生 ptrdiff_t 类型的有符号整数结果(在标准包含文件 STDDEF.H 中定义) (简而言之,减法给出了内存距离) ,但是两个指针的相加没有意义,这就是为什么不支持
参考 :
1) 加法运算符:+ 和 –
2) 为什么-prefer-start-end-start-2-over-start-end-2-when-calculating-
3) 指针加法与减法