For a higher level language, one idea would be to automatically widen the result of operations, so for example adding two 32 bit integers would have a 33 bit result.
Since the expression will be eventually assigned to some variable or passed as a function parameter, it will have a limited range (and there should be an exception if that overflows), but intermediate results could be larger.
Is this just completely unfeasible, or just not done because "that's not how C does it"?
ChatGPT came up with this solution when I asked it to handle the overflow, and then asked it to be more efficient.
// Calculates the midpoint of two 64-bit integers
// and returns the result as a 64-bit integer.
int64_t midpoint(int64_t a, int64_t b) {
// Use the __int128 type to calculate the sum
// of the two input numbers without overflowing.
__int128 sum = (__int128) a + (__int128) b;
// Shift the sum to the right by 1 bit to divide it by 2
// and get the midpoint. This operation is equivalent to
// sum / 2, but is more efficient because it uses a bit shift
// operation instead of a division operation.
int64_t midpoint = (int64_t) (sum >> 1);
return midpoint;
}
Yes, but that converts to 128 bits before doing the actual sum (maybe the compiler can still optimize that away?)
My idea was a better language where typecasts are never needed at all, because the compiler knows how the result will be used (in this example, returned as int64_t), and can produce whatever code is most efficient and either produces the correct result or a runtime exception.
edit:
Also any non-toy compiler will optimize division by powers of two into a shift operation, so ChatGPT isn't being clever at all here, just repeating a common superstition.
> ChatGPT isn't being clever at all here, just repeating a common superstition
Source:
#include <stdint.h>
int64_t midpoint_ChatGPT(int64_t a, int64_t b) {
__int128 sum = (__int128) a + (__int128) b;
// Shift the sum to the right by 1 bit to divide it by 2
// and get the midpoint. This operation is equivalent to
// sum / 2, but is more efficient because it uses a bit shift
// operation instead of a division operation.
int64_t midpoint = (int64_t) (sum >> 1);
return midpoint;
}
int64_t midpoint_rep_lodsb(int64_t a, int64_t b) {
__int128 sum = (__int128) a + (__int128) b;
// Shifts are for the superstitious.
int64_t midpoint = (int64_t) (sum / 2);
return midpoint;
}
But all of these use a bit shift instead of the (I)DIV instruction. I wasn't saying compilers can't be stupid, but the AI-generated comment explicitly stated that the shift operation was more efficient than division, not that it would result in fewer instructions emitted.
midpoint_rep_lodsb_handwritten:
endbr64
movq $0x8000000000000000, %rax
xorq %rax, %rsi ;convert two's complement to biased
xorq %rax, %rdi
addq %rsi, %rdi
rcrq $1, %rdi
xorq %rdi, %rax ;convert back
ret
(sorry if I got the syntax wrong, AT&T is just horrible)
Since the expression will be eventually assigned to some variable or passed as a function parameter, it will have a limited range (and there should be an exception if that overflows), but intermediate results could be larger.
Is this just completely unfeasible, or just not done because "that's not how C does it"?