4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 1988 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 /* Conversion between binary and decimal floating point. */
31 #include "base_conversion.h"
33 /* PRIVATE FUNCTIONS */
36 * Rounds decimal record *pd according to modes in *pm, recording exceptions
37 * for inexact or overflow in *ps. round is the round digit and sticky is 0
38 * or non-zero to indicate exact or inexact. pd->ndigits is expected to be
42 decimal_round(decimal_mode
*pm
, decimal_record
*pd
, fp_exception_field_type
*ps
,
43 char round
, unsigned sticky
)
47 if ((round
== '0') && (sticky
== 0)) { /* Exact. */
50 *ps
|= 1 << fp_inexact
;
60 /* Now in ambiguous case; round up if lsd is odd. */
62 goto done
; /* Presumed 0. */
63 lsd
= pd
->ds
[pd
->ndigits
- 1] - '0';
79 for (i
= (pd
->ndigits
- 1); (pd
->ds
[i
] == '9') && (i
>= 0); i
--)
83 else { /* Rounding carry out has occurred. */
85 if (pm
->df
== floating_form
) { /* For E format, simply
88 } else { /* For F format, increase length of string. */
90 pd
->ds
[pd
->ndigits
] = '0';
96 if (pd
->ndigits
<= 0) { /* Create zero string. */
101 pd
->ds
[pd
->ndigits
] = 0;/* Terminate string. */
106 * Converts an unpacked integer value *pu into a decimal string in *ds, of
107 * length returned in *ndigs. Inexactness is indicated by setting
111 * pu: Input unpacked integer value input.
112 * nsig: Input number of significant digits required.
113 * ds: Output decimal integer string output
114 * must be large enough.
115 * nzeros: Output number of implicit trailing zeros
117 * ndigs: Output number of explicit digits produced
121 binary_to_decimal_integer(unpacked
*pu
, unsigned nsig
, char ds
[],
122 unsigned *nzeros
, unsigned *ndigs
)
125 _big_float
*pd
, b
, d
;
127 _BIG_FLOAT_DIGIT stickyshift
;
130 b
.bsize
= _BIG_FLOAT_SIZE
; /* Initialize sizes of big floats. */
131 d
.bsize
= _BIG_FLOAT_SIZE
;
132 _unpacked_to_big_float(pu
, &b
, &e
);
134 _right_shift_base_two(&b
, (short unsigned) -e
, &stickyshift
);
136 assert(stickyshift
== 0);
139 _big_binary_to_big_decimal(&b
, &d
);
143 _big_float_times_power(&d
, 2, e
, (int) nsig
, &pd
);
144 switch ((unsigned int)pd
) {
145 case ((unsigned int)BIG_FLOAT_TIMES_TOOBIG
):
149 (void) sprintf(bcastring
, " binary exponent %d ", e
);
150 _base_conversion_abort(ERANGE
, bcastring
);
153 case ((unsigned int)BIG_FLOAT_TIMES_NOMEM
):
157 (void) sprintf(bcastring
, " binary exponent %d ", e
);
158 _base_conversion_abort(ENOMEM
, bcastring
);
164 (void) printf(" large binary exponent %d needs heap buffer \n", e
);
166 _display_big_float(pd
, 10);
171 _fourdigitsquick((short unsigned) pd
->bsignificand
[pd
->blength
- 1], s
);
172 for (i
= 0; s
[i
] == '0'; i
++); /* Find first non-zero digit. */
173 for (is
= 0; i
<= 3;)
174 ds
[is
++] = s
[i
++]; /* Copy subsequent digits. */
176 for (i
= (pd
->blength
- 2); i
>= 0; i
--) { /* Convert powers of
179 _fourdigitsquick((short unsigned) pd
->bsignificand
[i
], &(ds
[is
]));
185 *nzeros
= pd
->bexponent
;
190 printf(" binary to decimal integer result %s * 10**%d \n", ds
, *nzeros
);
195 * Converts an unpacked fraction value *pu into a decimal string consisting
196 * of a) an implicit '.' b) *nzeros implicit leading zeros c) *ndigs explicit
197 * digits in ds ds contains at least nsig significant digits. nzeros + *
198 * *ndigs is at least nfrac digits after the point. Inexactness is indicated
199 * by sticking to the lsb.
203 * pu: Input unpacked fraction value output < 1
205 * nsig: Input number of significant digits
207 * nfrac: Input number of digits after point
209 * ds: Output decimal integer string output -
210 * must be large enough.
211 * nzeros: Output number of implicit leading zeros
213 * ndigs: Output number of explicit digits produced
217 binary_to_decimal_fraction(unpacked
*pu
, unsigned nsig
, unsigned nfrac
,
218 char ds
[], int *nzeros
, int *ndigs
)
220 _big_float
*pb
, b
, d
;
221 int e
, i
, j
, is
, excess
;
223 int tensig
, tenpower
;
224 _BIG_FLOAT_DIGIT stickyshift
;
227 if (pu
->fpclass
== fp_zero
) { /* Exact zero. */
228 for (i
= 0; i
<= nfrac
; i
++)
230 for (; i
<= nsig
; i
++)
235 b
.bsize
= _BIG_FLOAT_SIZE
; /* Initialize sizes of big floats. */
236 d
.bsize
= _BIG_FLOAT_SIZE
;
237 _unpacked_to_big_float(pu
, &b
, &e
);
242 tenpower
= nsig
+ (int) (((17 - e
- 16 * b
.blength
) * (unsigned long) 19729) >> 16);
243 if (tenpower
< nfrac
)
248 tensig
= 1 + (((tensig
+ 2) * 217706) >> 16);
252 printf(" binary to decimal fraction exponent 2**%d \n", e
);
253 printf(" binary to decimal fraction nsig %d nfrac %d tenpower %d tensig %d \n", nsig
, nfrac
, tenpower
, tensig
);
255 _big_float_times_power(&b
, 10, tenpower
, tensig
, &pb
);
256 switch ((unsigned int)pb
) {
257 case ((unsigned int)BIG_FLOAT_TIMES_TOOBIG
):
261 (void) sprintf(bcastring
, " decimal exponent %d ", tenpower
);
262 _base_conversion_abort(ERANGE
, bcastring
);
265 case ((unsigned int)BIG_FLOAT_TIMES_NOMEM
):
269 (void) sprintf(bcastring
, " decimal exponent %d ", tenpower
);
270 _base_conversion_abort(ENOMEM
, bcastring
);
276 printf(" large decimal exponent %d needs heap buffer \n", tenpower
);
278 _display_big_float(pb
, 2);
283 if (pb
->bexponent
<= -16) {
284 /* Have computed appropriate decimal part; now toss fraction. */
285 excess
= (-pb
->bexponent
) / 16;
287 printf(" discard %d excess fraction bits \n", 16 * excess
);
289 for (i
= 0; (i
< excess
) && (pb
->bsignificand
[i
] == 0); i
++);
291 pb
->bsignificand
[excess
] |= 1; /* Sticky bit for
292 * discarded fraction. */
293 for (i
= excess
; i
< pb
->blength
; i
++)
294 pb
->bsignificand
[i
- excess
] = pb
->bsignificand
[i
];
296 pb
->blength
-= excess
;
297 pb
->bexponent
+= 16 * excess
;
299 if (pb
->bexponent
< 0) {
300 _right_shift_base_two(pb
, (short unsigned) -pb
->bexponent
, &stickyshift
);
301 if (stickyshift
!= 0)
302 pb
->bsignificand
[0] |= 1; /* Stick to lsb. */
304 _big_binary_to_big_decimal(pb
, &d
);
307 while (d
.bsignificand
[i
] == 0)
309 _fourdigitsquick((short unsigned) d
.bsignificand
[i
], s
);
310 for (j
= 0; s
[j
] == '0'; j
++); /* Find first non-zero digit. */
311 for (is
= 0; j
<= 3;)
312 ds
[is
++] = s
[j
++]; /* Copy subsequent digits. */
314 for (i
--; i
>= 0; i
--) {/* Convert powers of 10**4 to decimal digits. */
315 _fourdigitsquick((short unsigned) d
.bsignificand
[i
], &(ds
[is
]));
322 assert(tenpower
>= is
);
324 *nzeros
= tenpower
- is
;/* There were supposed to be tenpower leading
325 * digits, and is were found. */
331 printf(" binary to decimal fraction result .%s * 10**%d \n", ds
, -(*nzeros
));
337 _unpacked_to_decimal(unpacked
*px
, decimal_mode
*pm
, decimal_record
*pd
,
338 fp_exception_field_type
*ps
)
341 unsigned fmask
, imask
;
342 int i
, intdigs
, fracdigs
, fraczeros
, fracsigs
, ids
, idsbound
, lzbound
;
343 unsigned nsig
, nfrac
, intzeros
, intsigs
;
344 char is
[_INTEGER_SIZE
], fs
[DECIMAL_STRING_LENGTH
];
349 pd
->fpclass
= px
->fpclass
;
350 if ((px
->fpclass
!= fp_normal
) && (px
->fpclass
!= fp_subnormal
))
352 if ((pm
->ndigits
>= DECIMAL_STRING_LENGTH
) ||
353 ((pm
->df
== floating_form
) && (pm
->ndigits
< 1))) { /* Gross overflow or bad
356 *ps
|= 1 << fp_overflow
;
359 /* Divide x up into integer part ix and fraction part fx. */
363 if (ix
.exponent
<= -1) {/* All fraction. */
364 ix
.fpclass
= fp_zero
;
365 } else if (ix
.exponent
>= 159) { /* All integer. */
366 fx
.fpclass
= fp_zero
;
367 } else if ((ix
.exponent
% 32) == 31) { /* Integer/fraction boundary
368 * is conveniently on a word
370 imask
= (ix
.exponent
+ 1) / 32; /* Words 0..imask-1 are
371 * integer; imask..SIZE are
373 for (i
= 0; i
< imask
; i
++)
374 fx
.significand
[i
] = 0;
375 for (; i
< UNPACKED_SIZE
; i
++)
376 ix
.significand
[i
] = 0;
378 } else { /* Integer/fraction boundary falls in the
379 * middle of a word. */
380 imask
= (ix
.exponent
+ 1) / 32; /* Words 0..imask-1 are
381 * integer; imask is integer
385 for (i
= 0; i
< imask
; i
++)
386 fx
.significand
[i
] = 0;
387 fmask
= (1 << (31 - (ix
.exponent
% 32))) - 1;
388 fx
.significand
[imask
] &= fmask
;
389 ix
.significand
[imask
] &= ~fmask
;
390 for (i
= (imask
+ 1); i
< UNPACKED_SIZE
; i
++)
391 ix
.significand
[i
] = 0;
394 if (ix
.fpclass
!= fp_zero
) { /* Compute integer part of result. */
395 if (pm
->df
== floating_form
)
396 nsig
= pm
->ndigits
+ 1; /* Significant digits wanted
397 * for E format, plus one for
400 nsig
= _INTEGER_SIZE
; /* Significant digits wanted
401 * for F format == all. */
403 binary_to_decimal_integer(&ix
, nsig
, is
, &intzeros
, &intsigs
);
408 intdigs
= intsigs
+ intzeros
;
410 if (((pm
->df
== fixed_form
) && (pm
->ndigits
>= 0)) ||
411 ((pm
->df
== floating_form
) && ((pm
->ndigits
+ 1) > intdigs
))) { /* Need to compute
413 if (pm
->df
== floating_form
) { /* Need more significant
415 nsig
= pm
->ndigits
+ 2 - intdigs
; /* Add two for rounding,
417 if (nsig
> DECIMAL_STRING_LENGTH
)
418 nsig
= DECIMAL_STRING_LENGTH
;
420 } else { /* Need fraction digits. */
422 nfrac
= pm
->ndigits
+ 2; /* Add two for rounding,
424 if (nfrac
> DECIMAL_STRING_LENGTH
)
425 nfrac
= DECIMAL_STRING_LENGTH
;
427 binary_to_decimal_fraction(&fx
, nsig
, nfrac
, fs
, &fraczeros
, &fracsigs
);
428 fracdigs
= fraczeros
+ fracsigs
;
430 if (pm
->df
== floating_form
) { /* Combine integer and fraction for E
433 if (idsbound
> pm
->ndigits
)
434 idsbound
= pm
->ndigits
;
435 for (ids
= 0; ids
< idsbound
; ids
++)
436 pd
->ds
[ids
] = is
[ids
];
437 /* Put integer into output string. */
438 idsbound
= intsigs
+ intzeros
;
439 if (idsbound
> pm
->ndigits
)
440 idsbound
= pm
->ndigits
;
441 for (; ids
< idsbound
; ids
++)
443 if (ids
== pm
->ndigits
) { /* Integer part had enough
444 * significant digits. */
446 pd
->exponent
= intdigs
- ids
;
447 if (ids
< intdigs
) { /* Gather rounding info. */
452 for (; (is
[ids
] == '0') && (ids
< intsigs
); ids
++);
455 if (fx
.fpclass
!= fp_zero
)
457 } else {/* Integer part is exact - round from
459 if (fx
.fpclass
!= fp_zero
) {
461 /* Fraction non-zero. */
462 if (fraczeros
> 0) { /* Round digit is zero. */
464 stickystart
= 0; /* Stickies start with
466 } else { /* Round digit is fs[0]. */
468 stickystart
= 1; /* Stickies start with
471 if (sticky
== 0) { /* Search for sticky
473 for (ids
= stickystart
; (fs
[ids
] == '0') && (ids
< fracdigs
); ids
++);
479 } else { /* Need more significant digits from fraction
481 idsbound
= pm
->ndigits
- ids
;
482 if (ids
== 0) { /* No integer part - find first
483 * significant digit. */
484 for (i
= 0; fs
[i
] == '0'; i
++);
485 idsbound
= i
+ idsbound
+ fraczeros
;
486 i
+= fraczeros
; /* Point i at first
487 * significant digit. */
490 if (idsbound
> fracdigs
)
492 pd
->exponent
= -idsbound
;
494 if (fraczeros
< idsbound
) /* Compute number of
500 for (; (i
< lzbound
); i
++)
502 for (; (i
< idsbound
); i
++)
503 pd
->ds
[ids
++] = fs
[i
- fraczeros
];
504 i
-= fraczeros
; /* Don't worry about leading zeros
505 * from now on, we're just rounding */
506 if (i
< fracsigs
) { /* Gather rounding info. */
512 if (sticky
== 0) { /* Find out if remainder
516 for (; (fs
[i
] == '0') && (i
< fracsigs
); i
++);
520 } else {/* Fraction part is exact - add zero digits
522 for (; ids
< pm
->ndigits
; ids
++)
527 decimal_round(pm
, pd
, ps
, round
, sticky
);
528 } else { /* Combine integer and fraction for F format. */
529 if (pm
->ndigits
>= 0) { /* Normal F format. */
530 if ((intdigs
+ pm
->ndigits
) >= DECIMAL_STRING_LENGTH
)
532 for (ids
= 0; ids
< intsigs
; ids
++)
533 pd
->ds
[ids
] = is
[ids
];
534 for (; ids
< intdigs
; ids
++)
536 /* Copy integer digits. */
538 if (idsbound
> pm
->ndigits
)
539 idsbound
= pm
->ndigits
;
540 if (fraczeros
< idsbound
) /* Compute number of
546 for (i
= 0; (i
< lzbound
); i
++)
548 for (; (i
< idsbound
); i
++)
549 pd
->ds
[ids
++] = fs
[i
- fraczeros
]; /* Copy fraction digits. */
550 for (; i
< pm
->ndigits
; i
++)
552 /* Copy trailing zeros if necessary. */
554 pd
->exponent
= intdigs
- ids
;
555 i
-= fraczeros
; /* Don't worry about leading zeros
556 * from now on, we're just rounding */
557 if (i
< fracsigs
) { /* Gather rounding info. */
563 if (sticky
== 0) { /* Find out if remainder
567 for (; (fs
[i
] == '0') && (i
< fracsigs
); i
++);
572 decimal_round(pm
, pd
, ps
, round
, sticky
);
573 } else { /* Bizarre F format - round to left of point. */
574 int roundpos
= -pm
->ndigits
;
576 if (intdigs
>= DECIMAL_STRING_LENGTH
)
578 if (roundpos
>= DECIMAL_STRING_LENGTH
)
580 if (intdigs
<= roundpos
) { /* Not enough integer
582 if (intdigs
== roundpos
) {
589 for (; (is
[i
] == '0') && (i
< intsigs
); i
++);
590 /* Search for sticky bits. */
594 } else {/* Some integer digits do not get rounded
597 for (ids
= 0; ids
< (intsigs
- roundpos
); ids
++)
598 pd
->ds
[ids
] = is
[ids
];
599 for (ids
= 0; ids
< (intdigs
- roundpos
); ids
++)
603 int ncopy
= intsigs
- roundpos
;
605 /* Copy integer digits. */
606 (void) memcpy(&(pd
->ds
[0]), &(is
[0]), ncopy
);
611 int ncopy
= intdigs
- roundpos
- ids
;
613 (void) memset(&(pd
->ds
[ids
]), '0', ncopy
);
617 #endif /* _NO_GOOD */
618 /* Copy integer digits. */
620 if (ids
< intsigs
) { /* Inexact. */
622 for (; (is
[ids
] == '0') && (ids
< intsigs
); ids
++);
623 /* Search for non-zero digits. */
628 if (fx
.fpclass
!= fp_zero
)
630 decimal_round(pm
, pd
, ps
, round
, sticky
);
631 for (i
= pd
->ndigits
; i
< (pd
->ndigits
+ roundpos
); i
++)
632 pd
->ds
[i
] = '0'; /* Blank out rounded
636 pd
->ds
[i
] = 0; /* Terminate string. */
642 double_to_decimal(double *px
, decimal_mode
*pm
, decimal_record
*pd
,
643 fp_exception_field_type
*ps
)
645 double_equivalence kluge
;
648 *ps
= 0; /* Initialize *ps. */
650 pd
->sign
= kluge
.f
.msw
.sign
;
651 pd
->fpclass
= _class_double(px
);
652 switch (pd
->fpclass
) {
662 _unpack_double(&u
, &kluge
.x
);
663 _unpacked_to_decimal(&u
, pm
, pd
, ps
);
668 quadruple_to_decimal(quadruple
*px
, decimal_mode
*pm
, decimal_record
*pd
,
669 fp_exception_field_type
*ps
)
671 quadruple_equivalence kluge
;
675 *ps
= 0; /* Initialize *ps - no exceptions. */
676 for (i
= 0; i
< 4; i
++)
680 kluge
.x
.u
[i
] = px
->u
[i
];
682 pd
->sign
= kluge
.f
.msw
.sign
;
683 pd
->fpclass
= _class_quadruple(px
);
684 switch (pd
->fpclass
) {
694 _unpack_quadruple(&u
, px
);
695 _unpacked_to_decimal(&u
, pm
, pd
, ps
);