Commit | Line | Data |
---|---|---|
7a47add7 | 1 | /* |
bcf1365c DF |
2 | * Copyright (c) 1982 Regents of the University of California. |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
7a47add7 | 5 | */ |
bcf1365c | 6 | |
7a47add7 | 7 | #ifndef lint |
bcf1365c | 8 | static char sccsid[] = "@(#)natof.c 5.1 (Berkeley) %G%"; |
7a47add7 RH |
9 | #endif not lint |
10 | ||
11 | #include <stdio.h> | |
12 | #include <ctype.h> | |
13 | #include <errno.h> | |
14 | ||
15 | #include "as.h" | |
16 | ||
17 | Bignum bigatof(str, radix) | |
18 | reg char *str; /* r11 */ | |
19 | int radix; /* TYPF ... TYPH */ | |
20 | { | |
21 | int msign; | |
22 | int esign; | |
23 | int decpt; | |
24 | reg chptr temp; /* r10 */ | |
25 | reg u_int quotient; /* r9 */ /* must be here */ | |
26 | reg u_int remainder; /* r8 */ /* must be here */ | |
27 | reg chptr acc; | |
28 | reg int dividend; /* for doing division */ | |
29 | reg u_int i; | |
30 | short *sptr; /* for doing division */ | |
31 | int ch; | |
32 | int dexponent; /* decimal exponent */ | |
33 | int bexponent; /* binary exponent */ | |
34 | Bignum Acc; | |
35 | Bignum Temp; | |
36 | static Bignum znumber; | |
37 | Ovf ovf; | |
38 | u_int j; | |
39 | extern int errno; | |
40 | u_int ediv(); | |
41 | ||
42 | #ifdef lint | |
43 | quotient = 0; | |
44 | remainder = 0; | |
45 | #endif lint | |
46 | msign = 0; | |
47 | esign = 0; | |
48 | decpt = 0; | |
49 | dexponent = 0; | |
50 | Acc = znumber; | |
51 | Acc.num_tag = radix; | |
52 | acc = CH_FIELD(Acc); | |
53 | temp = CH_FIELD(Temp); | |
54 | ||
55 | do{ | |
56 | ch = *str++; | |
57 | } while(isspace(ch)); | |
58 | ||
59 | switch(ch){ | |
60 | case '-': | |
61 | msign = -1; | |
62 | /* FALLTHROUGH */ | |
63 | case '+': | |
64 | ch = *str++; | |
65 | break; | |
66 | } | |
67 | dofract: | |
68 | for(; isdigit(ch); ch = *str++){ | |
69 | assert(((acc[HOC] & SIGNBIT) == 0), "Negative HOC"); | |
70 | if (acc[HOC] < MAXINT_10){ | |
71 | ovf = numshift(3, temp, acc); | |
72 | ovf |= numshift(1, acc, acc); | |
73 | ovf |= numaddv(acc, temp, acc); | |
74 | ovf |= numaddd(acc, acc, ch - '0'); | |
75 | assert(ovf == 0, "Overflow building mantissa"); | |
76 | } else { | |
77 | /* | |
78 | * Then, the number is too large anyway | |
79 | */ | |
80 | dexponent++; | |
81 | } | |
82 | if (decpt) | |
83 | dexponent--; | |
84 | } | |
85 | switch(ch){ | |
86 | case '.': | |
87 | if (decpt == 0){ | |
88 | decpt++; | |
89 | ch = *str++; | |
90 | goto dofract; | |
91 | } | |
92 | break; | |
93 | /* | |
94 | * only 'e' and 'E' are recognized by atof() | |
95 | */ | |
96 | case 'e': | |
97 | case 'E': | |
98 | /* | |
99 | * we include the remainder for compatability with as formats | |
100 | * in as, the radix actual paramater agrees with the character | |
101 | * we expect; consequently, no checking is done. | |
102 | */ | |
103 | case 'd': | |
104 | case 'D': | |
105 | case 'g': | |
106 | case 'G': | |
107 | case 'h': | |
108 | case 'H': | |
109 | j = 0; | |
110 | ch = *str++; | |
111 | esign = 0; | |
112 | switch(ch){ | |
113 | case '-': | |
114 | esign = 1; | |
115 | /* FALLTHROUGH */ | |
116 | case '+': | |
117 | ch = *str++; | |
118 | } | |
119 | for(; isdigit(ch); ch = *str++){ | |
120 | if (j < MAXINT_10){ | |
121 | j *= 10; | |
122 | j += ch - '0'; | |
123 | } else { | |
124 | /* | |
125 | * outrageously large exponent | |
126 | */ | |
127 | /*VOID*/ | |
128 | } | |
129 | } | |
130 | if (esign) | |
131 | dexponent -= j; | |
132 | else | |
133 | dexponent += j; | |
134 | /* | |
135 | * There should be a range check on dexponent here | |
136 | */ | |
137 | } | |
138 | /* | |
139 | * The number has now been reduced to a mantissa | |
140 | * and an exponent. | |
141 | * The mantissa is an n bit number (to the precision | |
142 | * of the extended words) in the acc. | |
143 | * The exponent is a signed power of 10 in dexponent. | |
144 | * msign is on if the resulting number will eventually | |
145 | * be negative. | |
146 | * | |
147 | * We now must convert the number to standard format floating | |
148 | * number, which will be done by accumulating | |
149 | * a binary exponent in bexponent, as we gradually | |
150 | * drive dexponent towards zero, one count at a time. | |
151 | */ | |
152 | if (isclear(acc)){ | |
153 | return(Acc); | |
154 | } | |
155 | bexponent = 0; | |
156 | ||
157 | /* | |
158 | * Scale the number down. | |
159 | * We must divide acc by 10 as many times as needed. | |
160 | */ | |
161 | for (; dexponent < 0; dexponent++){ | |
162 | /* | |
163 | * Align the number so that the most significant | |
164 | * bits are aligned in the most significant | |
165 | * bits of the accumulator, adjusting the | |
166 | * binary exponent as we shift. | |
167 | * The goal is to get the high order bit (NOT the | |
168 | * sign bit) set. | |
169 | */ | |
170 | assert(((acc[HOC] & SIGNBIT) == 0), "Negative HOC"); | |
171 | ovf = 0; | |
172 | ||
173 | for (j = 5; j >= 1; --j){ | |
174 | i = 1 << (j - 1); /* 16, 8, 4, 2, 1 */ | |
175 | quotient = ONES(i); | |
176 | quotient <<= (CH_BITS - 1) - i; | |
177 | while((acc[HOC] & quotient) == 0){ | |
178 | ovf |= numshift((int)i, acc, acc); | |
179 | bexponent -= i; | |
180 | } | |
181 | } | |
182 | /* | |
183 | * Add 2 to the accumulator to effect rounding, | |
184 | * and get set up to divide by 5. | |
185 | */ | |
186 | ovf = numaddd(acc, acc, 2); | |
187 | assert(ovf == 0, "Carry out of left rounding up by 2"); | |
188 | /* | |
189 | * Divide the high order chunks by 5; | |
190 | * The last chunk will be divided by 10, | |
191 | * (to see what the remainder is, also to effect rounding) | |
192 | * and then multipiled by 2 to effect division by 5. | |
193 | */ | |
194 | remainder = 0; | |
195 | #if DEBUGNATOF | |
196 | printf("Dividing: "); | |
197 | bignumprint(Acc); | |
198 | printf("\n"); | |
199 | #endif DEBUGNATOF | |
200 | sptr = (short *)acc; | |
201 | for (i = (CH_N * 2 - 1); i >= 1; --i){ | |
202 | /* | |
203 | * Divide (remainder:16).(acc[i]:16) | |
204 | * by 5, putting the quotient back | |
205 | * into acc[i]:16, and save the remainder | |
206 | * for the next iteration. | |
207 | */ | |
208 | dividend = (remainder << 16) | (sptr[i] & ONES(16)); | |
209 | assert(dividend >= 0, "dividend < 0"); | |
210 | quotient = dividend / 5; | |
211 | remainder = dividend - (quotient * 5); | |
212 | sptr[i] = quotient; | |
213 | remainder = remainder; | |
214 | } | |
215 | /* | |
216 | * Divide the lowest order chunk by 10, | |
217 | * saving the remainder to decide how to round. | |
218 | * Then, multiply by 2, making it look as | |
219 | * if we divided by 10. | |
220 | * This multiply fills in a 0 on the least sig bit. | |
221 | */ | |
222 | dividend = (remainder << 16) | (sptr[0] & ONES(16)); | |
223 | assert(dividend >= 0, "dividend < 0"); | |
224 | quotient = dividend / 10; | |
225 | remainder = dividend - (quotient * 10); | |
226 | sptr[0] = quotient + quotient; | |
227 | ||
228 | if (remainder >= 5) | |
229 | ovf = numaddd(acc, acc, 1); | |
230 | /* | |
231 | * Now, divide by 2, effecting division by 10, | |
232 | * merely by adjusting the binary exponent. | |
233 | */ | |
234 | bexponent--; | |
235 | } | |
236 | /* | |
237 | * Scale the number up by multiplying by 10 as | |
238 | * many times as necessary | |
239 | */ | |
240 | for (; dexponent > 0; dexponent--){ | |
241 | /* | |
242 | * Compare high word to (2**31)/5, | |
243 | * and scale accordingly | |
244 | */ | |
245 | while ( ((unsigned)acc[HOC]) > MAXINT_5){ | |
246 | (void)numshift(-1, acc, acc); | |
247 | bexponent++; | |
248 | } | |
249 | /* | |
250 | * multiply the mantissa by 5, | |
251 | * and scale the binary exponent by 2 | |
252 | */ | |
253 | ovf = numshift(2, temp, acc); | |
254 | ovf |= numaddv(acc, acc, temp); | |
255 | assert(ovf == 0, "Scaling * 10 of manitissa"); | |
256 | bexponent++; | |
257 | } | |
258 | /* | |
259 | * We now have: | |
260 | * a CH_N chunk length binary integer, right | |
261 | * justified (in native format). | |
262 | * a binary exponent. | |
263 | * | |
264 | * Now, we treat this large integer as an octa word | |
265 | * number, and unpack it into standard unpacked | |
266 | * format. That unpacking will give us yet | |
267 | * another binary exponent, which we adjust with | |
268 | * the accumulated binary exponent. | |
269 | */ | |
270 | Acc.num_tag = TYPO; | |
271 | #if DEBUGNATOF | |
272 | printf("Octal number: "); | |
273 | bignumprint(Acc); | |
274 | printf("\n"); | |
275 | #endif DEBUGNATOF | |
276 | Acc = bignumunpack(Acc, &ovf); | |
277 | ||
278 | if (ovf) | |
279 | errno = ERANGE; | |
280 | #if DEBUGNATOF | |
281 | printf("Unpacked octal number: "); | |
282 | bignumprint(Acc); | |
283 | printf("bexponent == %d\n", bexponent); | |
284 | #endif DEBUGNATOF | |
285 | Acc.num_exponent += bexponent; | |
286 | assert(Acc.num_sign == 0, "unpacked integer is < 0"); | |
287 | Acc.num_sign = msign; | |
288 | /* | |
289 | * We now pack the number back into a radix format number. | |
290 | * This checks for overflow, underflow, | |
291 | * and rounds by 1/2 ulp. | |
292 | */ | |
293 | ovf = 0; | |
294 | Acc = bignumpack(Acc, radix, &ovf); | |
295 | if (ovf) | |
296 | errno = ERANGE; | |
297 | #if DEBUGNATOF | |
298 | printf("packed number: "); | |
299 | bignumprint(Acc); | |
300 | printf("\n"); | |
301 | #endif DEBUGNATOF | |
302 | return(Acc); | |
303 | } | |
304 | #if 0 | |
305 | /* | |
306 | * Unfortunately, one can't use the ediv instruction to do | |
307 | * division on numbers with > 64 bits. | |
308 | * This is because ediv returns signed quantities; | |
309 | * if the quotient is an unsigned number > 2^31, | |
310 | * ediv sets integer overflow. | |
311 | */ | |
312 | unsigned int ediv(high, low, divisor, qp, i) | |
313 | register unsigned int high; /* r11 */ | |
314 | register unsigned int low; /* r10 */ | |
315 | register unsigned int divisor; /* r9 */ | |
316 | unsigned int *qp; | |
317 | { | |
318 | register unsigned int remainder; /* r8 */ | |
319 | register unsigned int quotient; /* r7 */ | |
320 | ||
321 | asm("ediv r9, r10, r7, r8 # Divide. q->r7, r->r8 (discarded)"); | |
322 | *qp = quotient; | |
323 | return(remainder); | |
324 | } | |
325 | #endif 0 |