aboutsummaryrefslogtreecommitdiff
path: root/src/libmach/ieee.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-04-19 19:29:25 +0000
committerrsc <devnull@localhost>2004-04-19 19:29:25 +0000
commita84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46 (patch)
tree59a0e921597e5aa53e83d487c16727a7bf01547a /src/libmach/ieee.c
parent0e3cc9f456ea49919459bf1164d0c8309a6134fa (diff)
downloadplan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.gz
plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.bz2
plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.zip
libmach
Diffstat (limited to 'src/libmach/ieee.c')
-rw-r--r--src/libmach/ieee.c169
1 files changed, 169 insertions, 0 deletions
diff --git a/src/libmach/ieee.c b/src/libmach/ieee.c
new file mode 100644
index 00000000..0d756d21
--- /dev/null
+++ b/src/libmach/ieee.c
@@ -0,0 +1,169 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+/*
+ * These routines assume that if the number is representable
+ * in IEEE floating point, it will be representable in the native
+ * double format. Naive but workable, probably.
+ */
+int
+ieeeftoa64(char *buf, uint n, u32int h, u32int l)
+{
+ double fr;
+ int exp;
+
+ if (n <= 0)
+ return 0;
+
+
+ if(h & (1L<<31)){
+ *buf++ = '-';
+ h &= ~(1L<<31);
+ }else
+ *buf++ = ' ';
+ n--;
+ if(l == 0 && h == 0)
+ return snprint(buf, n, "0.");
+ exp = (h>>20) & ((1L<<11)-1L);
+ if(exp == 0)
+ return snprint(buf, n, "DeN(%.8lux%.8lux)", h, l);
+ if(exp == ((1L<<11)-1L)){
+ if(l==0 && (h&((1L<<20)-1L)) == 0)
+ return snprint(buf, n, "Inf");
+ else
+ return snprint(buf, n, "NaN(%.8lux%.8lux)", h&((1L<<20)-1L), l);
+ }
+ exp -= (1L<<10) - 2L;
+ fr = l & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (l>>16) & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (h & (1L<<20)-1L) | (1L<<20);
+ fr /= 1L<<21;
+ fr = ldexp(fr, exp);
+ return snprint(buf, n, "%.18g", fr);
+}
+
+int
+ieeeftoa32(char *buf, uint n, u32int h)
+{
+ double fr;
+ int exp;
+
+ if (n <= 0)
+ return 0;
+
+ if(h & (1L<<31)){
+ *buf++ = '-';
+ h &= ~(1L<<31);
+ }else
+ *buf++ = ' ';
+ n--;
+ if(h == 0)
+ return snprint(buf, n, "0.");
+ exp = (h>>23) & ((1L<<8)-1L);
+ if(exp == 0)
+ return snprint(buf, n, "DeN(%.8lux)", h);
+ if(exp == ((1L<<8)-1L)){
+ if((h&((1L<<23)-1L)) == 0)
+ return snprint(buf, n, "Inf");
+ else
+ return snprint(buf, n, "NaN(%.8lux)", h&((1L<<23)-1L));
+ }
+ exp -= (1L<<7) - 2L;
+ fr = (h & ((1L<<23)-1L)) | (1L<<23);
+ fr /= 1L<<24;
+ fr = ldexp(fr, exp);
+ return snprint(buf, n, "%.9g", fr);
+}
+
+int
+beieeeftoa32(char *buf, uint n, void *s)
+{
+ return ieeeftoa32(buf, n, beswap4(*(u32int*)s));
+}
+
+int
+beieeeftoa64(char *buf, uint n, void *s)
+{
+ return ieeeftoa64(buf, n, beswap4(*(u32int*)s), beswap4(((u32int*)(s))[1]));
+}
+
+int
+leieeeftoa32(char *buf, uint n, void *s)
+{
+ return ieeeftoa32(buf, n, leswap4(*(u32int*)s));
+}
+
+int
+leieeeftoa64(char *buf, uint n, void *s)
+{
+ return ieeeftoa64(buf, n, leswap4(((u32int*)(s))[1]), leswap4(*(u32int*)s));
+}
+
+/* packed in 12 bytes, with s[2]==s[3]==0; mantissa starts at s[4]*/
+int
+beieeeftoa80(char *buf, uint n, void *s)
+{
+ uchar *reg = (uchar*)s;
+ int i;
+ ulong x;
+ uchar ieee[8+8]; /* room for slop */
+ uchar *p, *q;
+
+ memset(ieee, 0, sizeof(ieee));
+ /* sign */
+ if(reg[0] & 0x80)
+ ieee[0] |= 0x80;
+
+ /* exponent */
+ x = ((reg[0]&0x7F)<<8) | reg[1];
+ if(x == 0) /* number is ±0 */
+ goto done;
+ if(x == 0x7FFF){
+ if(memcmp(reg+4, ieee+1, 8) == 0){ /* infinity */
+ x = 2047;
+ }else{ /* NaN */
+ x = 2047;
+ ieee[7] = 0x1; /* make sure */
+ }
+ ieee[0] |= x>>4;
+ ieee[1] |= (x&0xF)<<4;
+ goto done;
+ }
+ x -= 0x3FFF; /* exponent bias */
+ x += 1023;
+ if(x >= (1<<11) || ((reg[4]&0x80)==0 && x!=0))
+ return snprint(buf, n, "not in range");
+ ieee[0] |= x>>4;
+ ieee[1] |= (x&0xF)<<4;
+
+ /* mantissa */
+ p = reg+4;
+ q = ieee+1;
+ for(i=0; i<56; i+=8, p++, q++){ /* move one byte */
+ x = (p[0]&0x7F) << 1;
+ if(p[1] & 0x80)
+ x |= 1;
+ q[0] |= x>>4;
+ q[1] |= (x&0xF)<<4;
+ }
+ done:
+ return beieeeftoa64(buf, n, (void*)ieee);
+}
+
+
+int
+leieeeftoa80(char *buf, uint n, void *s)
+{
+ int i;
+ char *cp;
+ char b[12];
+
+ cp = (char*) s;
+ for(i=0; i<12; i++)
+ b[11-i] = *cp++;
+ return beieeeftoa80(buf, n, b);
+}