6 ms·
The funny thing about rolling over an integer not being easy to catch is hard to ignore. The PDP-11 'add' instruction sets the 'C' bit if there is a carry from
by GeorgeTirebiter 6y ago
The funny thing about rolling over an integer not being easy to catch is hard to ignore. The PDP-11 'add' instruction sets the 'C' bit if there is a carry from the MSB; the Z bit is set if the result == 0; the N bit is set if the result < 0; and the V bit is set if there is arithmetic overflow (both operands were of the same sign, but the result is of opposite sign). By simply making these bit available as, say, special names that could be tested (e.g. C N Z V) after an operation, you could determine what happened (if appropriate) and take action. HP's SPL had such a feature (used on the HP3000 series). C is not a well-designed language, but an improved 'lifeform' along the way. Today, I would like to see a c-like language developed specifically for RISC-V; especially one that had many many fewer edge cases.
- arcticbull 6y agoWhat's so hard about: if (((a > 0) && (b > 0) && (a + b) < 0) || ((a < 0) && (b < 0) && (a + b) > 0)) { / * Overflow */ } Now you may be saying, well, isn't there a branch-if-arithmetic-overflow instruction in practically every single architecture ever? To which I would say simplicity matters. [edit] </sarcasm>
- jcranmer 6y agoThat is undefined behavior.
- arcticbull 6y agoWell son of a bucket, you're right. What about this? T const highOrderBitMask = (1 << ((sizeof(T) * 8) - 1)); T const hobA = (a & highOrderBitMask); T const hobB = (b & highOrderBitMask); T const hobR = ((a + b) & highOrderBitMask); if ((hobA == hobB) && (hobA != hobR)) { /* Overflow */ } Or is it undefined behavior to assume a 2's complement representation also. [edit] Yep, 2's is only required for C++20, not C, and worse, it's permitted for an implementation to trap on overflow. Back to the drawing board.
- jcranmer 6y agoIt is undefined behavior if a signed integer arithmetic overflows. If T is signed, the first and fourth lines are undefined behavior. The representation of signed numbers is implementation-defined, not undefined.
- arcticbull 6y agoOk, I think I've got it this time -- and incidentally, a new interview question. if (((a > 0) && (a > INT_MAX - b)) || ((a < 0) && (a < INT_MIN - b))) { /* Would Overflow */ } Not standard, but not undefined either are the checked intrinsics: __builtin_add_overflow(a, b, &x) == false Thanks, that was a fun exercise :)
- jcranmer 6y agoIMHO, C really should just standardize the standard checked overflow intrinsics. It's a lot saner than having users try to guess the correct overflow matching pattern (it's worse for multiplication), and many architectures make detecting overflow pretty trivial.
- MaxBarraclough 6y agoYou might like this blog post, We Need Hardware Traps for Integer Overflow. https://blog.regehr.org/archives/1154 https://blog.regehr.org/archives/1154
- deleted 6y ago[deleted]
- MaxBarraclough 6y agoI think I might be missing the intent of this exercise, but that expression risks overflow (and undefined behaviour) when b is not equal to zero, right?
- arcticbull 6y ago
- loup-vaillant 6y ago> Today, I would like to see a c-like language developed specifically for RISC-V When I've learned that RISC-V had no carry bit, I couldn't help but think it might have been designed for C to begin with. Sure, they give reasons for this choice, none of them linked to C. Still, it hurts multi-precision arithmetic any language with BigInt would have benefited from (I recall Python, Haskell, and Scheme at the very least). I'm no hardware designer, though.