summaryrefslogtreecommitdiff
path: root/2/homework/2.73.c
diff options
context:
space:
mode:
Diffstat (limited to '2/homework/2.73.c')
-rw-r--r--2/homework/2.73.c113
1 files changed, 113 insertions, 0 deletions
diff --git a/2/homework/2.73.c b/2/homework/2.73.c
new file mode 100644
index 0000000..7ed0ca2
--- /dev/null
+++ b/2/homework/2.73.c
@@ -0,0 +1,113 @@
+#include <stdio.h>
+#include <limits.h>
+#include <assert.h>
+#include <stdint.h>
+
+/*
+ Addition that saturates to TMIN or TMAX
+ 2^(w-2) + 2^(w-2)
+ w=4
+ 0100
+ 0100
+ +
+ 1000 (-8)
+ Normally overflow wraps around to the other extreme.
+ z mod 2w
+ and do unsigned addition
+
+ positive overflow -> TMAX
+ negative overflow -> TMIN
+
+ for w=4
+ 1000
+ 1000
+ +
+ 1000
+
+ 0100
+ 0100
+ +
+ 0111
+
+ z +
+
+ note: you can apparently also do something like
+
+ thing_is_true && (x = my_value)
+
+ in c :/.
+ Now I did it with a weird method using masks based on booleans.
+*/
+int saturating_add(int x, int y) {
+ int sum = x + y;
+ printf("sum: %x\n", sum);
+ int min = INT_MIN;
+ int did_negative_overflow = ((min & x) && (min & y) && !(min & sum)) - 1;
+ int did_positive_overflow = (!(min & x) && !(min & y) && (min & sum)) - 1;
+ sum |= INT_MIN & ~did_negative_overflow;
+ sum &= INT_MIN | did_negative_overflow;
+ sum |= INT_MAX & ~did_positive_overflow;
+ sum &= INT_MAX | did_positive_overflow;
+ return sum;
+}
+
+/*
+ Determine whether arguments can be subtracted without overflow.
+ important to note is that the positive range of integers is shorter than the negative.
+
+ positive [0, 2^{w-1} - 1]
+ negative [-2^{w-1}, 0]
+*/
+int tsub_ok(int x, int y) {
+ if (y == INT_MIN) {
+ return 0;
+ }
+ int positive_overflow = x > 0 && y < 0 && x - y < 0;
+ int negative_overflow = x < 0 && y > 0 && x - y >= 0;
+ return !positive_overflow && !negative_overflow;
+}
+
+/*
+ The result of 2.18 shows us
+ T2B(x*y) <=> U2B(x'*y')
+ but this is only for w bits.
+ In this case we are looking at the 2w bits.
+
+
+ */
+int signed_high_prod(int x, int y) {
+ int64_t result = (int64_t) x * y;
+ return result >> 32;
+}
+unsigned correct_unsigned_high_prod(unsigned x, unsigned y) {
+ uint64_t result = (uint64_t) x * y;
+ return result >> 32;
+}
+unsigned unsigned_high_prod(unsigned x, unsigned y) {
+ unsigned xl = x>>31;
+ unsigned yl = y>>31;
+ return signed_high_prod(x, y) + xl*y + yl*x;
+}
+
+int main() {
+ /* assert(unsigned_high_prod(0xFFFFFFFF, 3) == correct_unsigned_high_prod(0xFFFFFFFF, 3)); */
+ unsigned x = 0x12345678;
+ unsigned y = 0xFFFFFFFF;
+
+ assert(correct_unsigned_high_prod(x, y) == unsigned_high_prod(x, y));
+ return 0;
+
+ printf("%d\n", tsub_ok(1, INT_MIN>>1));
+ printf("%d\n", tsub_ok(1, (INT_MIN>>1) - 1));
+ printf("%d\n", tsub_ok(1, INT_MIN));
+ printf("%d\n", tsub_ok(INT_MIN, INT_MAX));
+ printf("%d\n", -((INT_MIN>>1) - 1));
+ printf("%d\n", INT_MAX);
+ return 0;
+
+ printf("%x\n", INT_MIN);
+ printf("%x\n", saturating_add(INT_MIN, INT_MIN));
+ printf("%x\n", saturating_add(4, 4));
+ printf("%x\n", saturating_add(-3, 4));
+ return 0;
+}