Dưới đây là những gì tôi đã làm:
#include <stdio.h>
#include <limits.h>
int ThreeFourths(int x)
{
int x3 = x + x + x;
return (x3 >= 0) ? (x3 >> 2) : -(int)((UINT_MAX - x3 + 1) >> 2);
}
int testData[] =
{
0,
1,
-1,
2,
-2,
3,
-3,
4,
-4,
5,
-5,
-9,
11,
INT_MAX/2 + 1,
INT_MIN
};
int main(void)
{
int i;
for (i = 0; i < sizeof(testData)/sizeof(testData[0]); i++)
{
printf(" %d * 3/4 = %d\n",
testData[i], testData[i] * 3/4);
printf("ThreeFourths(%d) = %d\n",
testData[i], ThreeFourths(testData[i]));
}
return 0;
}
Output:
0 * 3/4 = 0
ThreeFourths(0) = 0
1 * 3/4 = 0
ThreeFourths(1) = 0
-1 * 3/4 = 0
ThreeFourths(-1) = 0
2 * 3/4 = 1
ThreeFourths(2) = 1
-2 * 3/4 = -1
ThreeFourths(-2) = -1
3 * 3/4 = 2
ThreeFourths(3) = 2
-3 * 3/4 = -2
ThreeFourths(-3) = -2
4 * 3/4 = 3
ThreeFourths(4) = 3
-4 * 3/4 = -3
ThreeFourths(-4) = -3
5 * 3/4 = 3
ThreeFourths(5) = 3
-5 * 3/4 = -3
ThreeFourths(-5) = -3
-9 * 3/4 = -6
ThreeFourths(-9) = -6
11 * 3/4 = 8
ThreeFourths(11) = 8
1073741824 * 3/4 = -268435456
ThreeFourths(1073741824) = -268435456
-2147483648 * 3/4 = -536870912
ThreeFourths(-2147483648) = -536870912
Lý do tại sao tôi đã không sử dụng đúng ca trên số nguyên âm là đơn giản. Kết quả của những thay đổi này là xác định thực hiện (theo tiêu chuẩn C) và không được đảm bảo giống như sự thay đổi đúng với phần mở rộng dấu hiệu mà chúng ta có thể mong đợi vì nó là triển khai phổ biến nhất.
tôi đã viết (UINT_MAX - x3 + 1)
thay vì chỉ đơn giản là -x3
bởi vì nó có thể gây ra một lỗi tràn bộ ký (khi = INT_MIN
đó là một sức mạnh trừ 2), trong đó đã không xác định hành vi (theo tiêu chuẩn C, một lần nữa). Và ngay cả khi hành vi không xác định này được biết là vô hại, sự phủ định đơn giản vẫn có thể thất bại trong việc tạo ra một số dương (vì sự không đối xứng trong biểu diễn bổ sung của các số nguyên đã ký).
x + x + x
vẫn có thể tạo tràn đăng nhập giống như x * 3
có thể. Vì vậy, đây là hành vi không xác định tương tự.
Btw, vì các luồng tràn đã ký kết quả trong UB, nó thậm chí không được yêu cầu một cách hợp pháp từ bạn để đạt được chúng, hãy để một mình có những kỳ vọng cụ thể về kết quả khi UB xảy ra.
Hm ... Tôi đã chạy thử nghiệm với mã này trong máy tính của tôi và tôi phải nói rằng nó có vẻ là làm việc cho các trường hợp thử nghiệm và các ví dụ bạn đã cho đây. Tôi thậm chí có được kết quả chính xác cho 2147483647 – Lefteris
Trình biên dịch nào bạn đang sử dụng? –
Bạn đã chia nhỏ để xem tất cả các giá trị trung gian? – EboMike