6811333 Remove prom_printf() message in emlxs driver
[opensolaris.git] / usr / src / lib / libc / port / fp / double_decim.c
blob0e5758448407cb834c3c223a7a374507111ab916
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Conversion from binary to decimal floating point
31 #include "lint.h"
32 #include <stdlib.h>
33 #include "base_conversion.h"
36 * Any sensible programmer would inline the following routine where
37 * it is used below. Unfortunately, the Sun SPARC compilers are not
38 * consistent in generating efficient code for this, so inlining it
39 * as written can cause the *_to_decimal functions to take twice as
40 * long in some cases.
42 * We might be tempted, then, to rewrite the source to match the most
43 * efficient code the compilers generate and inline that. Alas, the
44 * most efficient code on SPARC uses 32x32->64 bit multiply, which
45 * can't be expressed directly in source code. We could use long long,
46 * which would imply 64x64->64 bit multiply; this would work perfectly
47 * well on SPARC in v8plus mode. But as of Solaris 10, libc for SPARC
48 * is still built in v8 mode, and of course, x86 is another story.
50 * We could also choose to use an inline template to get the most
51 * efficient code without incurring the full cost of a function call.
52 * Since I expect that would not buy much performance gain, and I
53 * prefer to avoid using inline templates for things that can be
54 * written in a perfectly straightforward way in C, I've settled
55 * for this implementation. I hope that someday the compilers will
56 * get less flaky and/or someone will come up with a better way to
57 * do this.
59 static unsigned int
60 __quorem10000(unsigned int x, unsigned short *pr)
62 *pr = x % 10000;
63 return (x / 10000);
67 * Convert the integer part of a nonzero base-2^16 _big_float *pb
68 * to base 10^4 in **ppd. The converted value is accurate to nsig
69 * significant digits. On exit, *sticky is nonzero if *pb had a
70 * nonzero fractional part. If pb->exponent > 0 and **ppd is not
71 * large enough to hold the final converted value (i.e., the con-
72 * verted significand scaled by 2^pb->exponent), then on exit,
73 * *ppd will point to a newly allocated _big_float, which must be
74 * freed by the caller. (The number of significant digits we need
75 * should fit in pd, but __big_float_times_power may allocate new
76 * storage anyway because we could be multiplying by as much as
77 * 2^16271, which would require more than 4000 digits.)
79 * This routine does not check that **ppd is large enough to hold
80 * the result of converting the significand of *pb.
82 static void
83 __big_binary_to_big_decimal(_big_float *pb, int nsig, _big_float **ppd,
84 int *sticky)
86 _big_float *pd;
87 int i, j, len, s;
88 unsigned int carry;
90 pd = *ppd;
92 /* convert pb a digit at a time, most significant first */
93 if (pb->bexponent + ((pb->blength - 1) << 4) >= 0) {
94 carry = pb->bsignificand[pb->blength - 1];
95 pd->bsignificand[1] = __quorem10000(carry,
96 &pd->bsignificand[0]);
97 len = (pd->bsignificand[1])? 2 : 1;
98 for (i = pb->blength - 2; i >= 0 &&
99 pb->bexponent + (i << 4) >= 0; i--) {
100 /* multiply pd by 2^16 and add next digit */
101 carry = pb->bsignificand[i];
102 for (j = 0; j < len; j++) {
103 carry += (unsigned int)pd->bsignificand[j]
104 << 16;
105 carry = __quorem10000(carry,
106 &pd->bsignificand[j]);
108 while (carry != 0) {
109 carry = __quorem10000(carry,
110 &pd->bsignificand[j]);
111 j++;
113 len = j;
115 } else {
116 i = pb->blength - 1;
117 len = 0;
120 /* convert any partial digit */
121 if (i >= 0 && pb->bexponent + (i << 4) > -16) {
122 s = pb->bexponent + (i << 4) + 16;
123 /* multiply pd by 2^s and add partial digit */
124 carry = pb->bsignificand[i] >> (16 - s);
125 for (j = 0; j < len; j++) {
126 carry += (unsigned int)pd->bsignificand[j] << s;
127 carry = __quorem10000(carry, &pd->bsignificand[j]);
129 while (carry != 0) {
130 carry = __quorem10000(carry, &pd->bsignificand[j]);
131 j++;
133 len = j;
134 s = pb->bsignificand[i] & ((1 << (16 - s)) - 1);
135 i--;
136 } else {
137 s = 0;
140 pd->blength = len;
141 pd->bexponent = 0;
143 /* continue accumulating sticky flag */
144 while (i >= 0)
145 s |= pb->bsignificand[i--];
146 *sticky = s;
148 if (pb->bexponent > 0) {
149 /* scale pd by 2^pb->bexponent */
150 __big_float_times_power(pd, 2, pb->bexponent, nsig, ppd);
155 * Convert a base-10^4 _big_float *pf to a decimal string in *pd,
156 * rounding according to the modes in *pm and recording any exceptions
157 * in *ps. If sticky is nonzero, then additional nonzero digits are
158 * assumed to follow those in *pf. pd->sign must have already been
159 * filled in, and pd->fpclass is not modified. The resulting string
160 * is stored in pd->ds, terminated by a null byte. The length of this
161 * string is stored in pd->ndigits, and the corresponding exponent
162 * is stored in pd->exponent. If the converted value is not exact,
163 * the inexact flag is set in *ps.
165 * When pm->df == fixed_form, we may discover that the result would
166 * have more than DECIMAL_STRING_LENGTH - 1 digits. In this case,
167 * we put DECIMAL_STRING_LENGTH - 1 digits into *pd, adjusting both
168 * the exponent and the decimal place at which the value is rounded
169 * as need be, and we set the overflow flag in *ps. (Raising overflow
170 * is a bug, but we have to do it to maintain backward compatibility.)
172 * *pf may be modified.
174 static void
175 __big_decimal_to_string(_big_float *pf, int sticky, decimal_mode *pm,
176 decimal_record *pd, fp_exception_field_type *ps)
178 unsigned short d;
179 int e, er, efirst, elast, i, is, j;
180 char s[4], round;
182 /* set e = floor(log10(*pf)) */
183 i = pf->blength - 1;
184 if (i < 0) {
185 e = pf->bexponent = -DECIMAL_STRING_LENGTH - 2;
186 } else {
187 e = pf->bexponent + (i << 2);
188 d = pf->bsignificand[i];
189 if (d >= 1000)
190 e += 3;
191 else if (d >= 100)
192 e += 2;
193 else if (d >= 10)
194 e++;
198 * Determine the power of ten after which to round and the
199 * powers corresponding to the first and last digits desired
200 * in the result.
202 if (pm->df == fixed_form) {
203 /* F format */
204 er = -pm->ndigits;
205 if (er < 0) {
206 efirst = (e >= 0)? e : -1;
207 elast = er;
208 } else {
209 efirst = (e >= er)? e : ((er > 0)? er - 1 : 0);
210 elast = 0;
213 /* check for possible overflow of pd->ds */
214 if (efirst - elast >= DECIMAL_STRING_LENGTH - 1) {
215 efirst = e;
216 elast = e - DECIMAL_STRING_LENGTH + 2;
217 if (er < elast)
218 er = elast;
219 *ps |= 1 << fp_overflow;
221 } else {
222 /* E format */
223 efirst = e;
224 elast = er = e - pm->ndigits + 1;
227 /* retrieve digits down to the (er - 1) place */
228 is = 0;
229 for (e = efirst; e >= pf->bexponent + (pf->blength << 2) &&
230 e >= er - 1; e--)
231 pd->ds[is++] = '0';
233 i = pf->blength - 1;
234 j = 3 - ((e - pf->bexponent) & 3);
235 if (j > 0 && e >= er - 1) {
236 __four_digits_quick(pf->bsignificand[i], s);
237 while (j <= 3 && e >= er - 1) {
238 pd->ds[is++] = s[j++];
239 e--;
241 while (j <= 3)
242 sticky |= (s[j++] - '0');
243 i--;
246 while ((i | (e - er - 2)) >= 0) { /* i >= 0 && e >= er + 2 */
247 __four_digits_quick(pf->bsignificand[i], pd->ds + is);
248 is += 4;
249 e -= 4;
250 i--;
253 if (i >= 0) {
254 if (e >= er - 1) {
255 __four_digits_quick(pf->bsignificand[i], s);
256 for (j = 0; e >= er - 1; j++) {
257 pd->ds[is++] = s[j];
258 e--;
260 while (j <= 3)
261 sticky |= (s[j++] - '0');
262 i--;
264 } else {
265 while (e-- >= er - 1)
266 pd->ds[is++] = '0';
269 /* collect rounding information */
270 round = pd->ds[--is];
271 while (i >= 0)
272 sticky |= pf->bsignificand[i--];
274 /* add more trailing zeroes if need be */
275 for (e = er - 1; e >= elast; e--)
276 pd->ds[is++] = '0';
278 pd->exponent = elast;
279 pd->ndigits = is;
280 pd->ds[is] = '\0';
282 /* round */
283 if (round == '0' && sticky == 0)
284 return;
286 *ps |= 1 << fp_inexact;
288 switch (pm->rd) {
289 case fp_nearest:
290 if (round < '5' || (round == '5' && sticky == 0 &&
291 (is <= 0 || (pd->ds[is - 1] & 1) == 0)))
292 return;
293 break;
295 case fp_positive:
296 if (pd->sign)
297 return;
298 break;
300 case fp_negative:
301 if (!pd->sign)
302 return;
303 break;
305 default:
306 return;
309 /* round up */
310 for (i = efirst - er; i >= 0 && pd->ds[i] == '9'; i--)
311 pd->ds[i] = '0';
312 if (i >= 0) {
313 (pd->ds[i])++;
314 } else {
315 /* rounding carry out has occurred */
316 pd->ds[0] = '1';
317 if (pm->df == floating_form) {
318 pd->exponent++;
319 } else if (is == DECIMAL_STRING_LENGTH - 1) {
320 pd->exponent++;
321 *ps |= 1 << fp_overflow;
322 } else {
323 if (is > 0)
324 pd->ds[is] = '0';
325 is++;
326 pd->ndigits = is;
327 pd->ds[is] = '\0';
333 * Convert a binary floating point value represented by *pf to a
334 * decimal record *pd according to the modes in *pm. Any exceptions
335 * incurred are passed back via *ps.
337 static void
338 __bigfloat_to_decimal(_big_float *bf, decimal_mode *pm, decimal_record *pd,
339 fp_exception_field_type *ps)
341 _big_float *pbf, *pbd, d;
342 int sticky, powten, sigbits, sigdigits, i;
345 * If pm->ndigits is too large or too small, set the overflow
346 * flag in *ps and do nothing. (Raising overflow is a bug,
347 * but we have to do it to maintain backward compatibility.)
349 if (pm->ndigits >= DECIMAL_STRING_LENGTH || pm->ndigits <=
350 ((pm->df == floating_form)? 0 : -DECIMAL_STRING_LENGTH)) {
351 *ps = 1 << fp_overflow;
352 return;
355 pbf = bf;
356 powten = 0;
358 /* pre-scale to get the digits we want into the integer part */
359 if (pm->df == fixed_form) {
360 /* F format */
361 if (pm->ndigits >= 0 && bf->bexponent < 0) {
363 * Scale by 10^min(-bf->bexponent, pm->ndigits + 1).
365 powten = pm->ndigits + 1;
366 if (powten > -bf->bexponent)
367 powten = -bf->bexponent;
369 * Take sigbits large enough to get all integral
370 * digits correct.
372 sigbits = bf->bexponent + (bf->blength << 4) +
373 (((powten * 217706) + 65535) >> 16);
374 if (sigbits < 1)
375 sigbits = 1;
376 __big_float_times_power(bf, 10, powten, sigbits, &pbf);
378 sigdigits = DECIMAL_STRING_LENGTH + 1;
379 } else {
380 /* E format */
381 if (bf->bexponent < 0) {
382 /* i is a lower bound on log2(x) */
383 i = bf->bexponent + ((bf->blength - 1) << 4);
384 if (i <= 0 || ((i * 19728) >> 16) < pm->ndigits + 1) {
386 * Scale by 10^min(-bf->bexponent,
387 * pm->ndigits + 1 + u) where u is
388 * an upper bound on -log10(x).
390 powten = pm->ndigits + 1;
391 if (i < 0)
392 powten += ((-i * 19729) + 65535) >> 16;
393 else if (i > 0)
394 powten -= (i * 19728) >> 16;
395 if (powten > -bf->bexponent)
396 powten = -bf->bexponent;
398 * Take sigbits large enough to get
399 * all integral digits correct.
401 sigbits = i + 16 +
402 (((powten * 217706) + 65535) >> 16);
403 __big_float_times_power(bf, 10, powten,
404 sigbits, &pbf);
407 sigdigits = pm->ndigits + 2;
410 /* convert to base 10^4 */
411 d.bsize = _BIG_FLOAT_SIZE;
412 pbd = &d;
413 __big_binary_to_big_decimal(pbf, sigdigits, &pbd, &sticky);
415 /* adjust pbd->bexponent based on the scale factor above */
416 pbd->bexponent -= powten;
418 /* convert to ASCII */
419 __big_decimal_to_string(pbd, sticky, pm, pd, ps);
421 if (pbf != bf)
422 (void) free((void *)pbf);
423 if (pbd != &d)
424 (void) free((void *)pbd);
427 /* remove trailing zeroes from the significand of p */
428 static void
429 __shorten(_big_float *p)
431 int length = p->blength;
432 int zeros, i;
434 /* count trailing zeros */
435 for (zeros = 0; zeros < length && p->bsignificand[zeros] == 0; zeros++)
437 if (zeros) {
438 length -= zeros;
439 p->bexponent += zeros << 4;
440 for (i = 0; i < length; i++)
441 p->bsignificand[i] = p->bsignificand[i + zeros];
442 p->blength = length;
447 * Unpack a normal or subnormal double into a _big_float.
449 static void
450 __double_to_bigfloat(double *px, _big_float *pf)
452 double_equivalence *x;
454 x = (double_equivalence *)px;
455 pf->bsize = _BIG_FLOAT_SIZE;
456 pf->bexponent = x->f.msw.exponent - DOUBLE_BIAS - 52;
457 pf->blength = 4;
458 pf->bsignificand[0] = x->f.significand2 & 0xffff;
459 pf->bsignificand[1] = x->f.significand2 >> 16;
460 pf->bsignificand[2] = x->f.msw.significand & 0xffff;
461 pf->bsignificand[3] = x->f.msw.significand >> 16;
462 if (x->f.msw.exponent == 0) {
463 pf->bexponent++;
464 while (pf->bsignificand[pf->blength - 1] == 0)
465 pf->blength--;
466 } else {
467 pf->bsignificand[3] += 0x10;
469 __shorten(pf);
473 * Unpack a normal or subnormal extended into a _big_float.
475 static void
476 __extended_to_bigfloat(extended *px, _big_float *pf)
478 extended_equivalence *x;
480 x = (extended_equivalence *)px;
481 pf->bsize = _BIG_FLOAT_SIZE;
482 pf->bexponent = x->f.msw.exponent - EXTENDED_BIAS - 63;
483 pf->blength = 4;
484 pf->bsignificand[0] = x->f.significand2 & 0xffff;
485 pf->bsignificand[1] = x->f.significand2 >> 16;
486 pf->bsignificand[2] = x->f.significand & 0xffff;
487 pf->bsignificand[3] = x->f.significand >> 16;
488 if (x->f.msw.exponent == 0) {
489 pf->bexponent++;
490 while (pf->bsignificand[pf->blength - 1] == 0)
491 pf->blength--;
493 __shorten(pf);
497 * Unpack a normal or subnormal quad into a _big_float.
499 static void
500 __quadruple_to_bigfloat(quadruple *px, _big_float *pf)
502 quadruple_equivalence *x;
504 x = (quadruple_equivalence *)px;
505 pf->bsize = _BIG_FLOAT_SIZE;
506 pf->bexponent = x->f.msw.exponent - QUAD_BIAS - 112;
507 pf->bsignificand[0] = x->f.significand4 & 0xffff;
508 pf->bsignificand[1] = x->f.significand4 >> 16;
509 pf->bsignificand[2] = x->f.significand3 & 0xffff;
510 pf->bsignificand[3] = x->f.significand3 >> 16;
511 pf->bsignificand[4] = x->f.significand2 & 0xffff;
512 pf->bsignificand[5] = x->f.significand2 >> 16;
513 pf->bsignificand[6] = x->f.msw.significand;
514 if (x->f.msw.exponent == 0) {
515 pf->blength = 7;
516 pf->bexponent++;
517 while (pf->bsignificand[pf->blength - 1] == 0)
518 pf->blength--;
519 } else {
520 pf->blength = 8;
521 pf->bsignificand[7] = 1;
523 __shorten(pf);
526 /* PUBLIC ROUTINES */
528 void
529 single_to_decimal(single *px, decimal_mode *pm, decimal_record *pd,
530 fp_exception_field_type *ps)
532 single_equivalence *kluge;
533 _big_float bf;
534 fp_exception_field_type ef;
535 double x;
537 kluge = (single_equivalence *)px;
538 pd->sign = kluge->f.msw.sign;
540 /* decide what to do based on the class of x */
541 if (kluge->f.msw.exponent == 0) { /* 0 or subnormal */
542 if (kluge->f.msw.significand == 0) {
543 pd->fpclass = fp_zero;
544 *ps = 0;
545 return;
546 } else {
547 #if defined(__sparc) || defined(__amd64)
548 int i;
550 pd->fpclass = fp_subnormal;
552 * On SPARC when nonstandard mode is enabled,
553 * or on x64 when FTZ mode is enabled, simply
554 * converting *px to double can flush a sub-
555 * normal value to zero, so we have to go
556 * through all this nonsense instead.
558 i = *(int *)px;
559 x = (double)(i & ~0x80000000);
560 if (i < 0)
561 x = -x;
562 x *= 1.401298464324817070923730e-45; /* 2^-149 */
563 ef = 0;
564 if (__fast_double_to_decimal(&x, pm, pd, &ef)) {
565 __double_to_bigfloat(&x, &bf);
566 __bigfloat_to_decimal(&bf, pm, pd, &ef);
568 if (ef != 0)
569 __base_conversion_set_exception(ef);
570 *ps = ef;
571 return;
572 #else
573 pd->fpclass = fp_subnormal;
574 #endif
576 } else if (kluge->f.msw.exponent == 0xff) { /* inf or nan */
577 if (kluge->f.msw.significand == 0)
578 pd->fpclass = fp_infinity;
579 else if (kluge->f.msw.significand >= 0x400000)
580 pd->fpclass = fp_quiet;
581 else
582 pd->fpclass = fp_signaling;
583 *ps = 0;
584 return;
585 } else {
586 pd->fpclass = fp_normal;
589 ef = 0;
590 x = *px;
591 if (__fast_double_to_decimal(&x, pm, pd, &ef)) {
592 __double_to_bigfloat(&x, &bf);
593 __bigfloat_to_decimal(&bf, pm, pd, &ef);
595 if (ef != 0)
596 __base_conversion_set_exception(ef);
597 *ps = ef;
600 void
601 double_to_decimal(double *px, decimal_mode *pm, decimal_record *pd,
602 fp_exception_field_type *ps)
604 double_equivalence *kluge;
605 _big_float bf;
606 fp_exception_field_type ef;
608 kluge = (double_equivalence *)px;
609 pd->sign = kluge->f.msw.sign;
611 /* decide what to do based on the class of x */
612 if (kluge->f.msw.exponent == 0) { /* 0 or subnormal */
613 if (kluge->f.msw.significand == 0 &&
614 kluge->f.significand2 == 0) {
615 pd->fpclass = fp_zero;
616 *ps = 0;
617 return;
618 } else {
619 pd->fpclass = fp_subnormal;
621 } else if (kluge->f.msw.exponent == 0x7ff) { /* inf or nan */
622 if (kluge->f.msw.significand == 0 &&
623 kluge->f.significand2 == 0)
624 pd->fpclass = fp_infinity;
625 else if (kluge->f.msw.significand >= 0x80000)
626 pd->fpclass = fp_quiet;
627 else
628 pd->fpclass = fp_signaling;
629 *ps = 0;
630 return;
631 } else {
632 pd->fpclass = fp_normal;
635 ef = 0;
636 if (__fast_double_to_decimal(px, pm, pd, &ef)) {
637 __double_to_bigfloat(px, &bf);
638 __bigfloat_to_decimal(&bf, pm, pd, &ef);
640 if (ef != 0)
641 __base_conversion_set_exception(ef);
642 *ps = ef;
645 void
646 extended_to_decimal(extended *px, decimal_mode *pm, decimal_record *pd,
647 fp_exception_field_type *ps)
649 extended_equivalence *kluge;
650 _big_float bf;
651 fp_exception_field_type ef;
653 kluge = (extended_equivalence *)px;
654 pd->sign = kluge->f.msw.sign;
656 /* decide what to do based on the class of x */
657 if (kluge->f.msw.exponent == 0) { /* 0 or subnormal */
658 if ((kluge->f.significand | kluge->f.significand2) == 0) {
659 pd->fpclass = fp_zero;
660 *ps = 0;
661 return;
662 } else {
664 * x could be a pseudo-denormal, but the distinction
665 * doesn't matter
667 pd->fpclass = fp_subnormal;
669 } else if ((kluge->f.significand & 0x80000000) == 0) {
671 * In Intel's extended format, if the exponent is
672 * nonzero but the explicit integer bit is zero, this
673 * is an "unsupported format" bit pattern; treat it
674 * like a signaling NaN.
676 pd->fpclass = fp_signaling;
677 *ps = 0;
678 return;
679 } else if (kluge->f.msw.exponent == 0x7fff) { /* inf or nan */
680 if (((kluge->f.significand & 0x7fffffff) |
681 kluge->f.significand2) == 0)
682 pd->fpclass = fp_infinity;
683 else if ((kluge->f.significand & 0x7fffffff) >= 0x40000000)
684 pd->fpclass = fp_quiet;
685 else
686 pd->fpclass = fp_signaling;
687 *ps = 0;
688 return;
689 } else {
690 pd->fpclass = fp_normal;
693 ef = 0;
694 __extended_to_bigfloat(px, &bf);
695 __bigfloat_to_decimal(&bf, pm, pd, &ef);
696 if (ef != 0)
697 __base_conversion_set_exception(ef);
698 *ps = ef;
701 void
702 quadruple_to_decimal(quadruple *px, decimal_mode *pm, decimal_record *pd,
703 fp_exception_field_type *ps)
705 quadruple_equivalence *kluge;
706 _big_float bf;
707 fp_exception_field_type ef;
709 kluge = (quadruple_equivalence *)px;
710 pd->sign = kluge->f.msw.sign;
712 /* decide what to do based on the class of x */
713 if (kluge->f.msw.exponent == 0) { /* 0 or subnormal */
714 if (kluge->f.msw.significand == 0 &&
715 (kluge->f.significand2 | kluge->f.significand3 |
716 kluge->f.significand4) == 0) {
717 pd->fpclass = fp_zero;
718 *ps = 0;
719 return;
720 } else {
721 pd->fpclass = fp_subnormal;
723 } else if (kluge->f.msw.exponent == 0x7fff) { /* inf or nan */
724 if (kluge->f.msw.significand == 0 &&
725 (kluge->f.significand2 | kluge->f.significand3 |
726 kluge->f.significand4) == 0)
727 pd->fpclass = fp_infinity;
728 else if (kluge->f.msw.significand >= 0x8000)
729 pd->fpclass = fp_quiet;
730 else
731 pd->fpclass = fp_signaling;
732 *ps = 0;
733 return;
734 } else {
735 pd->fpclass = fp_normal;
738 ef = 0;
739 __quadruple_to_bigfloat(px, &bf);
740 __bigfloat_to_decimal(&bf, pm, pd, &ef);
741 if (ef != 0)
742 __base_conversion_set_exception(ef);
743 *ps = ef;