📜  为什么 start + (end – start)/2 是在 (start + end)/2 上计算数组中间的首选方法?

📅  最后修改于: 2022-05-13 01:57:14.086000             🧑  作者: Mango

为什么 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) 指针加法与减法