1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 
6 /*
7  * These routines assume that if the number is representable
8  * in IEEE floating point, it will be representable in the native
9  * double format.  Naive but workable, probably.
10  */
11 int
ieeeftoa64(char * buf,uint n,u32int h,u32int l)12 ieeeftoa64(char *buf, uint n, u32int h, u32int l)
13 {
14 	double fr;
15 	int exp;
16 
17 	if (n <= 0)
18 		return 0;
19 
20 
21 	if(h & (1UL<<31)){
22 		*buf++ = '-';
23 		h &= ~(1UL<<31);
24 	}else
25 		*buf++ = ' ';
26 	n--;
27 	if(l == 0 && h == 0)
28 		return snprint(buf, n, "0.");
29 	exp = (h>>20) & ((1L<<11)-1L);
30 	if(exp == 0)
31 		return snprint(buf, n, "DeN(%.8lux%.8lux)", h, l);
32 	if(exp == ((1L<<11)-1L)){
33 		if(l==0 && (h&((1L<<20)-1L)) == 0)
34 			return snprint(buf, n, "Inf");
35 		else
36 			return snprint(buf, n, "NaN(%.8lux%.8lux)", h&((1L<<20)-1L), l);
37 	}
38 	exp -= (1L<<10) - 2L;
39 	fr = l & ((1L<<16)-1L);
40 	fr /= 1L<<16;
41 	fr += (l>>16) & ((1L<<16)-1L);
42 	fr /= 1L<<16;
43 	fr += (h & (1L<<20)-1L) | (1L<<20);
44 	fr /= 1L<<21;
45 	fr = ldexp(fr, exp);
46 	return snprint(buf, n, "%.18g", fr);
47 }
48 
49 int
ieeeftoa32(char * buf,uint n,u32int h)50 ieeeftoa32(char *buf, uint n, u32int h)
51 {
52 	double fr;
53 	int exp;
54 
55 	if (n <= 0)
56 		return 0;
57 
58 	if(h & (1UL<<31)){
59 		*buf++ = '-';
60 		h &= ~(1UL<<31);
61 	}else
62 		*buf++ = ' ';
63 	n--;
64 	if(h == 0)
65 		return snprint(buf, n, "0.");
66 	exp = (h>>23) & ((1L<<8)-1L);
67 	if(exp == 0)
68 		return snprint(buf, n, "DeN(%.8lux)", h);
69 	if(exp == ((1L<<8)-1L)){
70 		if((h&((1L<<23)-1L)) == 0)
71 			return snprint(buf, n, "Inf");
72 		else
73 			return snprint(buf, n, "NaN(%.8lux)", h&((1L<<23)-1L));
74 	}
75 	exp -= (1L<<7) - 2L;
76 	fr = (h & ((1L<<23)-1L)) | (1L<<23);
77 	fr /= 1L<<24;
78 	fr = ldexp(fr, exp);
79 	return snprint(buf, n, "%.9g", fr);
80 }
81 
82 int
beieeeftoa32(char * buf,uint n,void * s)83 beieeeftoa32(char *buf, uint n, void *s)
84 {
85 	return ieeeftoa32(buf, n, beswap4(*(u32int*)s));
86 }
87 
88 int
beieeeftoa64(char * buf,uint n,void * s)89 beieeeftoa64(char *buf, uint n, void *s)
90 {
91 	return ieeeftoa64(buf, n, beswap4(*(u32int*)s), beswap4(((u32int*)(s))[1]));
92 }
93 
94 int
leieeeftoa32(char * buf,uint n,void * s)95 leieeeftoa32(char *buf, uint n, void *s)
96 {
97 	return ieeeftoa32(buf, n, leswap4(*(u32int*)s));
98 }
99 
100 int
leieeeftoa64(char * buf,uint n,void * s)101 leieeeftoa64(char *buf, uint n, void *s)
102 {
103 	return ieeeftoa64(buf, n, leswap4(((u32int*)(s))[1]), leswap4(*(u32int*)s));
104 }
105 
106 /* packed in 12 bytes, with s[2]==s[3]==0; mantissa starts at s[4]*/
107 int
beieeeftoa80(char * buf,uint n,void * s)108 beieeeftoa80(char *buf, uint n, void *s)
109 {
110 	uchar *reg = (uchar*)s;
111 	int i;
112 	ulong x;
113 	uchar ieee[8+8];	/* room for slop */
114 	uchar *p, *q;
115 
116 	memset(ieee, 0, sizeof(ieee));
117 	/* sign */
118 	if(reg[0] & 0x80)
119 		ieee[0] |= 0x80;
120 
121 	/* exponent */
122 	x = ((reg[0]&0x7F)<<8) | reg[1];
123 	if(x == 0)		/* number is ±0 */
124 		goto done;
125 	if(x == 0x7FFF){
126 		if(memcmp(reg+4, ieee+1, 8) == 0){ /* infinity */
127 			x = 2047;
128 		}else{				/* NaN */
129 			x = 2047;
130 			ieee[7] = 0x1;		/* make sure */
131 		}
132 		ieee[0] |= x>>4;
133 		ieee[1] |= (x&0xF)<<4;
134 		goto done;
135 	}
136 	x -= 0x3FFF;		/* exponent bias */
137 	x += 1023;
138 	if(x >= (1<<11) || ((reg[4]&0x80)==0 && x!=0))
139 		return snprint(buf, n, "not in range");
140 	ieee[0] |= x>>4;
141 	ieee[1] |= (x&0xF)<<4;
142 
143 	/* mantissa */
144 	p = reg+4;
145 	q = ieee+1;
146 	for(i=0; i<56; i+=8, p++, q++){	/* move one byte */
147 		x = (p[0]&0x7F) << 1;
148 		if(p[1] & 0x80)
149 			x |= 1;
150 		q[0] |= x>>4;
151 		q[1] |= (x&0xF)<<4;
152 	}
153     done:
154 	return beieeeftoa64(buf, n, (void*)ieee);
155 }
156 
157 
158 int
leieeeftoa80(char * buf,uint n,void * s)159 leieeeftoa80(char *buf, uint n, void *s)
160 {
161 	int i;
162 	char *cp;
163 	char b[12];
164 
165 	cp = (char*) s;
166 	for(i=0; i<12; i++)
167 		b[11-i] = *cp++;
168 	return beieeeftoa80(buf, n, b);
169 }
170