This is somewhat reminiscent of Tom Seddon's answer, but uses a slightly cleaner way to clamp higher. Please note that as Mr. Seddon responds, mine avoid the question of ouah's answer, that the transition of a significant value to the right is the behavior determined by the implementation, and therefore work on all architects is not guaranteed.
#include <inttypes.h> #include <iostream> int16_t clamp(int16_t value) { // clampBelow is 0xffff for -ve, 0x0000 for +ve int16_t const clampBelow = -static_cast<int16_t>(static_cast<uint16_t>(value) >> 15); // value is now clamped below at zero value &= ~clampBelow; // subtract 4095 so we can do the same trick again value -= 4095; // clampAbove is 0xffff for -ve, 0x0000 for +ve, // ie 0xffff for original value < 4095, 0x0000 for original >= 4096 int16_t const clampAbove = -static_cast<int16_t>(static_cast<uint16_t>(value) >> 15); // adjusted value now clamped above at zero value &= clampAbove; // and restore to original value. value += 4095; return value; } void verify(int16_t value) { int16_t const clamped = clamp(value); int16_t const check = (value < 0 ? 0 : value > 4095 ? 4095 : value); if (clamped != check) { std::cout << "Verification falure for value: " << value << ", clamped: " << clamped << ", check: " << check << std::endl; } } int main() { for (int16_t i = 0x4000; i != 0x3fff; i++) { verify(i); } return 0; }
This is a complete test program (OK, so it does not check 0x3fff - sue me .;)), from which you can extract the clamp() routine for everything you need.
I also broke the “one step per line” clamp for clarity. If your compiler has a half-worthy optimizer, you can leave it as it is and rely on the compiler to create the best possible code. If your compiler optimizer is not so large, then by all means, it can be reduced in the line counter, although at the cost of a little readability.
“Never Sacrifice Clarity for Efficiency” - Bob Buckley, Professor of Computer Engineering, U-Warwick, Coventry, England, 1980
The best advice I've ever received.;)
source share