Created
September 22, 2014 07:42
-
-
Save joshkunz/a0e2f1c95fa5b2e4ca10 to your computer and use it in GitHub Desktop.
Arbitrary bit-width saturing addition and subtraction operations. Created for regher's Advanced Embedded Systems class.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "sat_ops.h" | |
#include <stdio.h> | |
/* Note: This code assumes that sizeof(myuint) == sizeof(myint). This assumption | |
* is made because the comment at the top of 'sat_ops.h' says that each pair | |
* will be in effect at the same time. I am sacrificing robustness to acheive | |
* a smaller footprint. */ | |
#define UMIN ((myuint) 0) | |
#define UMAX ((myuint) (~UMIN)) | |
#define UHIGH ((myuint) (~(UMAX >> 1))) | |
#define MIN ((mysint) UHIGH) | |
#define MAX ((mysint) (UMAX >> 1)) | |
myuint sat_unsigned_sub(myuint a, myuint b) { | |
return b > a ? 0U : a - b; | |
} | |
myuint sat_unsigned_add(myuint a, myuint b) { | |
myuint sum = a + b; | |
return sum < a || sum < b ? UMAX : sum; | |
} | |
/* splitting this into a seperate function reduces my byte count by 16 bytes | |
* in GCC. */ | |
static void signs(myuint *a, myuint *b, myuint *s, | |
myuint *out_a, myuint *out_b, myuint *out_s) { | |
*out_a = (*a & UHIGH); | |
*out_b = (*b & UHIGH); | |
*out_s = (*s & UHIGH); | |
} | |
mysint sat_signed_add(mysint a, mysint b) { | |
myuint usum = (myuint) a + (myuint) b; | |
myuint a_sign, b_sign, s_sign; | |
signs((myuint *) &a, (myuint *) &b, &usum, &a_sign, &b_sign, &s_sign); | |
if (!a_sign && !b_sign && s_sign) { return MAX; } | |
else if (a_sign && b_sign && !s_sign) { return MIN; } | |
return (mysint) usum; | |
} | |
mysint sat_signed_sub(mysint a, mysint b) { | |
myuint usub = (myuint) a - (myuint) b; | |
myuint a_sign, b_sign, s_sign; | |
signs((myuint *) &a, (myuint *) &b, &usub, &a_sign, &b_sign, &s_sign); | |
if (!a_sign && b_sign && s_sign) { return MAX; } | |
else if (a_sign && !b_sign && !s_sign) { return MIN; } | |
return (mysint) usub; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment