Thanks for the suggestion. As the entire point (hah) of fixed point integers is to not use floats, I'm hesitating to use that solution. But I may have to in the future.
A division that truncates rather than floors an int is going to be doing some processing of the inputs before performing the division anyway, that's unavoidable when you need to treat a signed number differently to an unsigned number (which isn't the case for addition, subtraction, or multiplication). Naturally you could check the modulus and subtract one specifically only if it's negative and not divisible by 65536: x / 65536 - (x % 65536 < 0 ? 1 : 0)
Code (C): #define DISCARD_LOWER_BITS(bits, x) (((x) - (((1 << bits) - 1) * ((x) < 0))) / (1 << bits)) #define DISCARD_LOWER_16_BITS(x) DISCARD_LOWER_BITS(16, x) This should work.
My apologies; I should have mentioned that I had cooked something up this morning, which happens to be exactly what DigitalDuck just suggested: Code (C): short util__longhigh_to_short(long value) { bool negative = value < 0; short result = value / 65536; if (negative && value % 65536 != 0) { --result; } return result; } That being said, that's a cool macro, Clownacy. You subtract the divisor from the dividend before division if it's negative to ensure the end result is lower by 1. And it seems to also work when the entire number is divisible by the original divisor by subtracting 1 from the divisor used in the first part.
Not my project so I don't want to tell you what to do, but here's an example of the performance and code clarity you're sacrificing by not assuming two's complement integers. The first two solutions are the two above this post, while I did the last solution assuming two's complement. You're making your code far more complex to gain compatibility with a few obscure mainframe systems, none of which can even output color graphics.
Code (C): short longhigh_to_short(long value) { unsigned long value_unsigned = (unsigned long)value; long value_shifted = (long)(value_unsigned >> 16); return (value_shifted & 0x7FFF) - (value_shifted & 0x8000); } Here's a version that doesn't rely on C99 fixed-width integers.
I'm not seeing the point on code clarity. The code resides in a clearly-named function. Assembly-wise, it is more complex, no question about that. But unless it's a performance-sensitive part of the code, I don't think it matters. It's not about compatibility with obscure mainframe systems. It's about avoiding implementation-defined behaviour.