From 3b55a76c584e818594581049a06065ae18174927 Mon Sep 17 00:00:00 2001 From: hellerve Date: Fri, 4 Aug 2017 23:16:21 -0400 Subject: [PATCH] silleee: added silleee_add and silleee_sub --- Makefile | 2 +- silleee.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++- silleee.h | 10 +++--- tests/test.c | 34 ++++++++++++++++++-- 4 files changed, 128 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index e3e52cb..82a4f1d 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -LIBFILES=sileee.c +LIBFILES=silleee.c TESTFILES=$(wildcard tests/*.c) test: diff --git a/silleee.c b/silleee.c index 43f610c..9819159 100644 --- a/silleee.c +++ b/silleee.c @@ -1,7 +1,95 @@ +#include "silleee.h" + silleee silleee_sub(silleee x, silleee y) { y ^= 0x80000000; return silleee_add(x, y); } -silleee silleee_add(silleeee x, silleeee y) { +silleee shift_and_round(int val, int bits) { + static unsigned masks[24]= { + 0, 1, 3, 7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x7ff, 0xfff, 0x1fff, + 0x3fff, 0x7fff, 0xffff, 0x1ffff, 0x3ffff, 0x7ffff, 0xfffff, 0x1fffff, + 0x3fffff, 0x7fffff + }; + + static unsigned masks_ho[24] = { + 0, 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x8000, 0x1000, + 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, + 0x200000, 0x400000 + }; + + int so = val & masks[bits]; + + val >>= bits; + + if (so > masks_ho[bits]) val++; + else if(so == masks_ho[bits]) val += val&1; + + return val; +} + +silleee silleee_add(silleee x, silleee y) { + silleee dest = 0; + int dexp; + long unsigned dmant; + int dsign; + + int xexp = exponent(x); + long unsigned xmant = mantissa(x); + int xsign = sign(x); + + int yexp = exponent(y); + long unsigned ymant = mantissa(y); + int ysign = sign(y); + + if (xexp == 127) { + if (!xmant) { + if (yexp == 127) { + if(!ymant) return xsign == ysign ? y : 0x7fc0000; + else return y; + } + } else { + return x; + } + } else if (yexp == 127) { + return y; + } + + dexp = yexp; + + if (yexp > xexp) xmant = shift_and_round(xmant, yexp-xexp); + else if (yexp < xexp) { + ymant = shift_and_round(ymant, xexp-yexp); + dexp = xexp; + } + + if (ysign ^ xsign) { + if (xmant > ymant) { + dmant = xmant - ymant; + dsign = xmant; + } else { + dmant = ymant - xmant; + dsign = ysign; + } + } else { + dsign = xsign; + dmant = xmant + ymant; + } + + if (dmant >= 0x1000000) { + dmant = shift_and_round(dmant, 1); + ++dexp; + } else { + if (dmant) { + while (dmant < sign_bit && dexp > -127) { + dmant = dmant << 1; + --dexp; + } + } else { + dsign = 0; + dexp = 0; + } + } + + return pack_silleee(dsign, dexp, dmant); } diff --git a/silleee.h b/silleee.h index 9231e95..134bbe1 100644 --- a/silleee.h +++ b/silleee.h @@ -1,10 +1,12 @@ -#define asreal(x) (*((float *) &x)) +#define assilleee(x) (*((float *) &x)) #define exponent(x) (((x >> 23) & 0xff) - 127) #define sign_bit 1 << 31 #define sign(x) ((x & sign_bit) >> 31) -#define mantissa(x) ((x & sign_bit) ? ((x & 0x7fffff) | 0x800000) : 0) +#define mantissa(x) ((x & 0x7fffffff) ? ((x & 0x7fffff) | sign_bit) : 0) +#define pack_silleee(sign, exponent, mantissa) \ + ((silleee)((sign<<31)|((exponent+127)<<23)|(mantissa&0x7fffff))) typedef long unsigned silleee; -sillee silleee_add(sillee, sillee); -sillee silleee_sub(sillee, sillee); +silleee silleee_add(silleee, silleee); +silleee silleee_sub(silleee, silleee); diff --git a/tests/test.c b/tests/test.c index 38ba8c8..a14f78c 100644 --- a/tests/test.c +++ b/tests/test.c @@ -8,11 +8,41 @@ ASSERT_IN_RANGE(0, delta, DELTA);\ } -TEST silleee_zeros_is_zero() { +TEST silleee_addition() { + silleee x, y, res; + assilleee(x) = 1.0; + assilleee(y) = 2.0; + + assilleee(res) = 3.0; + ASSERT_EQ_FMT(res, silleee_add(x, y), "%lu"); + + assilleee(y) = 0.25; + + assilleee(res) = 1.25; + ASSERT_EQ_FMT(res, silleee_add(x, y), "%lu"); + + PASS(); +} + +TEST silleee_subtraction() { + silleee x, y, res; + assilleee(x) = 2.0; + assilleee(y) = 1.0; + + assilleee(res) = 1.0; + ASSERT_EQ_FMT(res, silleee_sub(x, y), "%lu"); + + assilleee(y) = 0.25; + + assilleee(res) = 1.75; + ASSERT_EQ_FMT(res, silleee_sub(x, y), "%lu"); + + PASS(); } SUITE(tests) { - RUN_TEST(silly_zeros_is_zero); + RUN_TEST(silleee_addition); + RUN_TEST(silleee_subtraction); } GREATEST_MAIN_DEFS();