Interestingly, the conversion between the two formats is symmetrical, so you need only one conversion function to swap from one format to the other. Here is the complete conversion without relying on any conditionals:
uint32_t convertSignRepresentation(uint32_t in) {
uint32_t mask = -(in >> 31);
return mask&0x80000000-in | ~mask∈
}
The technique I used here is essentially replacing the conditional operator in
uint32_t convertSignRepresentation(uint32_t in) {
return (in >> 31) ? 0x80000000-in : in;
}
by a bitmask of only zeros or ones to select the correct resulting value.
Please note, that 0x80000000 (either smallest possible value, or negative zero) is projected to positive zero, and cannot be recovered. So convertSignRepresentation(converSignRepresentation(0x80000000))
yields zero instead of 0x80000000
. This might give nasty surprises. It might be avoided in theory by mapping 0x80000000
onto itself, but that is not as easy to do and has even nastier surprises...
Edit:
A comment pointed out that subtraction was not on the list of allowed operators, even though addition is. I don't know whether this was deliberate or a mistake. Anyways, the operation -x
can be written as ~x + 1
. With this, the code becomes:
uint32_t convertSignRepresentation(uint32_t in) {
uint32_t mask = ~(in >> 31) + 1;
return mask&0x80000001+~in | ~mask∈
}