3 ms·
Thanks! Yes I am also impressed by how relatively easy this is to implement at the machine level. One thing I meant to do for that article but didn't get to i
by haberman 14y ago
Thanks! Yes I am also impressed by how relatively easy this is to implement at the machine level. One thing I meant to do for that article but didn't get to is implement each of those algorithms in assembly directly and see if the C/C++ solution would compile into the optimal machine code (or something equally efficient).
In assembly you have the luxury of no undefined or implementation-defined behavior. This makes things a lot easier, since you can count on things like two's complement. In assembly these checks are probably as easy as (untested):
will_u64_overflow_u32:
; If any of the high 32 bits are set.
shr rdi, 32
setne al
ret
will_u64_overflow_i32:
; If any of the high 33 bits are set.
shr rdi, 33
setne al
ret
will_i64_overflow_i32
; If the high 32 bits are other than all 0 or all 1.
shr rdi, 32
add edi, 1
cmp edi, 1
seta al
ret
I'm not sure if these are exactly right, but I think the right answers are about this simple. Any of these could also be written simply in C/C++ also, the main difference is just that in assembly you can make machine-specific assumptions (like two's complement) since you're already doing something machine-specific.
- pbsd 14y agoThe shift in the second one should be 31, if I understand what you're doing correctly. The third one is incorrect. Consider, for example, the integer 0xFFFFFFFF00000001, which is -4294967295 in 2's complement. It passes your test, but is not representable as a 32-bit signed integer. An alternative might be: movsxd rax, edi ; signextend(rdi mod 2^32) == rdi cmp rax, rdi setz al ret
- haberman 14y agoBrilliant, I love it. Thanks for the corrections.