xref: /illumos-gate/usr/src/lib/libc/port/fp/hex_bin.c (revision 1da57d55)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7257d1b4Sraf  * Common Development and Distribution License (the "License").
6*7257d1b4Sraf  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*7257d1b4Sraf 
227c478bd9Sstevel@tonic-gate /*
23*7257d1b4Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27*7257d1b4Sraf #include "lint.h"
287c478bd9Sstevel@tonic-gate #include "base_conversion.h"
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /* conversion from hex chars to hex values */
317c478bd9Sstevel@tonic-gate #define	HEXVAL(c)	(('0' <= c && c <= '9')? c - '0' : \
327c478bd9Sstevel@tonic-gate 			10 + (('a' <= c && c <= 'f')? c - 'a' : c - 'A'))
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate  * Convert a hexadecimal record in *pd to unpacked form in *pu.
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  * Up to 30 hexadecimal digits from pd->ds are converted to a binary
387c478bd9Sstevel@tonic-gate  * value in px->significand, which is then normalized so that the most
397c478bd9Sstevel@tonic-gate  * significant bit is 1.  If there are additional, unused digits in
407c478bd9Sstevel@tonic-gate  * pd->ds, the least significant bit of px->significand will be set.
417c478bd9Sstevel@tonic-gate  */
427c478bd9Sstevel@tonic-gate static void
__hex_to_unpacked(decimal_record * pd,unpacked * pu)437c478bd9Sstevel@tonic-gate __hex_to_unpacked(decimal_record *pd, unpacked *pu)
447c478bd9Sstevel@tonic-gate {
457c478bd9Sstevel@tonic-gate 	int	i, n;
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate 	pu->sign = pd->sign;
487c478bd9Sstevel@tonic-gate 	pu->fpclass = pd->fpclass;
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate 	/*
517c478bd9Sstevel@tonic-gate 	 * Adjust the (base two) exponent to reflect the fact that the
527c478bd9Sstevel@tonic-gate 	 * radix point in *pd lies to the right of the last (base sixteen)
537c478bd9Sstevel@tonic-gate 	 * digit while the radix point in *pu lies to the right of the
547c478bd9Sstevel@tonic-gate 	 * most significant bit.
557c478bd9Sstevel@tonic-gate 	 */
567c478bd9Sstevel@tonic-gate 	pu->exponent = pd->exponent + (pd->ndigits << 2) - 1;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate 	/* fill in the significand */
597c478bd9Sstevel@tonic-gate 	for (i = 0; i < 5; i++)
607c478bd9Sstevel@tonic-gate 		pu->significand[i] = 0;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	n = pd->ndigits;
637c478bd9Sstevel@tonic-gate 	if (n > 30)
647c478bd9Sstevel@tonic-gate 		n = 30;
657c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
667c478bd9Sstevel@tonic-gate 		pu->significand[i >> 3] |= HEXVAL(pd->ds[i]) <<
677c478bd9Sstevel@tonic-gate 		    ((7 - (i & 7)) << 2);
687c478bd9Sstevel@tonic-gate 	}
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate 	/* sanity check */
717c478bd9Sstevel@tonic-gate 	if (pu->significand[0] == 0) {
727c478bd9Sstevel@tonic-gate 		pu->fpclass = fp_zero;
737c478bd9Sstevel@tonic-gate 		return;
747c478bd9Sstevel@tonic-gate 	}
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	/* normalize so the most significant bit is set */
777c478bd9Sstevel@tonic-gate 	while (pu->significand[0] < 0x80000000u) {
787c478bd9Sstevel@tonic-gate 		pu->significand[0] = (pu->significand[0] << 1) |
797c478bd9Sstevel@tonic-gate 		    (pu->significand[1] >> 31);
807c478bd9Sstevel@tonic-gate 		pu->significand[1] = (pu->significand[1] << 1) |
817c478bd9Sstevel@tonic-gate 		    (pu->significand[2] >> 31);
827c478bd9Sstevel@tonic-gate 		pu->significand[2] = (pu->significand[2] << 1) |
837c478bd9Sstevel@tonic-gate 		    (pu->significand[3] >> 31);
847c478bd9Sstevel@tonic-gate 		pu->significand[3] <<= 1;
857c478bd9Sstevel@tonic-gate 		pu->exponent--;
867c478bd9Sstevel@tonic-gate 	}
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	/* if there are any unused digits, set a sticky bit */
897c478bd9Sstevel@tonic-gate 	if (pd->ndigits > 30 || pd->more)
907c478bd9Sstevel@tonic-gate 		pu->significand[4] = 1;
917c478bd9Sstevel@tonic-gate }
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate  * The following routines convert the hexadecimal value encoded in the
957c478bd9Sstevel@tonic-gate  * decimal record *pd to a floating point value *px observing the round-
967c478bd9Sstevel@tonic-gate  * ing mode specified in rd and passing back any exceptions raised via
977c478bd9Sstevel@tonic-gate  * *ps.
987c478bd9Sstevel@tonic-gate  *
997c478bd9Sstevel@tonic-gate  * These routines assume pd->fpclass is either fp_zero or fp_normal.
1007c478bd9Sstevel@tonic-gate  * If pd->fpclass is fp_zero, *px is set to zero with the sign indicated
1017c478bd9Sstevel@tonic-gate  * by pd->sign and no exceptions are raised.  Otherwise, pd->ds must
1027c478bd9Sstevel@tonic-gate  * contain a string of hexadecimal digits of length pd->ndigits > 0, and
1037c478bd9Sstevel@tonic-gate  * the first digit must be nonzero.  Let m be the integer represented by
1047c478bd9Sstevel@tonic-gate  * this string.  Then *px is set to a correctly rounded approximation to
1057c478bd9Sstevel@tonic-gate  *
1067c478bd9Sstevel@tonic-gate  *  (-1)^(pd->sign) * m * 2^(pd->exponent)
1077c478bd9Sstevel@tonic-gate  *
1087c478bd9Sstevel@tonic-gate  * with inexact, underflow, and/or overflow raised as appropriate.
1097c478bd9Sstevel@tonic-gate  */
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate void
__hex_to_single(decimal_record * pd,enum fp_direction_type rd,single * px,fp_exception_field_type * ps)1127c478bd9Sstevel@tonic-gate __hex_to_single(decimal_record *pd, enum fp_direction_type rd, single *px,
1137c478bd9Sstevel@tonic-gate     fp_exception_field_type *ps)
1147c478bd9Sstevel@tonic-gate {
1157c478bd9Sstevel@tonic-gate 	single_equivalence	kluge;
1167c478bd9Sstevel@tonic-gate 	unpacked		u;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	*ps = 0;
1197c478bd9Sstevel@tonic-gate 	if (pd->fpclass == fp_zero) {
1207c478bd9Sstevel@tonic-gate 		kluge.f.msw.sign = pd->sign? 1 : 0;
1217c478bd9Sstevel@tonic-gate 		kluge.f.msw.exponent = 0;
1227c478bd9Sstevel@tonic-gate 		kluge.f.msw.significand = 0;
1237c478bd9Sstevel@tonic-gate 		*px = kluge.x;
1247c478bd9Sstevel@tonic-gate 	} else {
1257c478bd9Sstevel@tonic-gate 		__hex_to_unpacked(pd, &u);
1267c478bd9Sstevel@tonic-gate 		__pack_single(&u, px, rd, ps);
1277c478bd9Sstevel@tonic-gate 		if (*ps != 0)
1287c478bd9Sstevel@tonic-gate 			__base_conversion_set_exception(*ps);
1297c478bd9Sstevel@tonic-gate 	}
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate void
__hex_to_double(decimal_record * pd,enum fp_direction_type rd,double * px,fp_exception_field_type * ps)1337c478bd9Sstevel@tonic-gate __hex_to_double(decimal_record *pd, enum fp_direction_type rd, double *px,
1347c478bd9Sstevel@tonic-gate     fp_exception_field_type *ps)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	double_equivalence	kluge;
1377c478bd9Sstevel@tonic-gate 	unpacked		u;
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	*ps = 0;
1407c478bd9Sstevel@tonic-gate 	if (pd->fpclass == fp_zero) {
1417c478bd9Sstevel@tonic-gate 		kluge.f.msw.sign = pd->sign? 1 : 0;
1427c478bd9Sstevel@tonic-gate 		kluge.f.msw.exponent = 0;
1437c478bd9Sstevel@tonic-gate 		kluge.f.msw.significand = 0;
1447c478bd9Sstevel@tonic-gate 		kluge.f.significand2 = 0;
1457c478bd9Sstevel@tonic-gate 		*px = kluge.x;
1467c478bd9Sstevel@tonic-gate 	} else {
1477c478bd9Sstevel@tonic-gate 		__hex_to_unpacked(pd, &u);
1487c478bd9Sstevel@tonic-gate 		__pack_double(&u, px, rd, ps);
1497c478bd9Sstevel@tonic-gate 		if (*ps != 0)
1507c478bd9Sstevel@tonic-gate 			__base_conversion_set_exception(*ps);
1517c478bd9Sstevel@tonic-gate 	}
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate #if defined(__sparc)
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate void
__hex_to_quadruple(decimal_record * pd,enum fp_direction_type rd,quadruple * px,fp_exception_field_type * ps)1577c478bd9Sstevel@tonic-gate __hex_to_quadruple(decimal_record *pd, enum fp_direction_type rd, quadruple *px,
1587c478bd9Sstevel@tonic-gate     fp_exception_field_type *ps)
1597c478bd9Sstevel@tonic-gate {
1607c478bd9Sstevel@tonic-gate 	quadruple_equivalence	kluge;
1617c478bd9Sstevel@tonic-gate 	unpacked		u;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	*ps = 0;
1647c478bd9Sstevel@tonic-gate 	if (pd->fpclass == fp_zero) {
1657c478bd9Sstevel@tonic-gate 		kluge.f.msw.sign = pd->sign? 1 : 0;
1667c478bd9Sstevel@tonic-gate 		kluge.f.msw.exponent = 0;
1677c478bd9Sstevel@tonic-gate 		kluge.f.msw.significand = 0;
1687c478bd9Sstevel@tonic-gate 		kluge.f.significand2 = 0;
1697c478bd9Sstevel@tonic-gate 		kluge.f.significand3 = 0;
1707c478bd9Sstevel@tonic-gate 		kluge.f.significand4 = 0;
1717c478bd9Sstevel@tonic-gate 		*px = kluge.x;
1727c478bd9Sstevel@tonic-gate 	} else {
1737c478bd9Sstevel@tonic-gate 		__hex_to_unpacked(pd, &u);
1747c478bd9Sstevel@tonic-gate 		__pack_quadruple(&u, px, rd, ps);
1757c478bd9Sstevel@tonic-gate 		if (*ps != 0)
1767c478bd9Sstevel@tonic-gate 			__base_conversion_set_exception(*ps);
1777c478bd9Sstevel@tonic-gate 	}
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64)
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate void
__hex_to_extended(decimal_record * pd,enum fp_direction_type rd,extended * px,fp_exception_field_type * ps)1837c478bd9Sstevel@tonic-gate __hex_to_extended(decimal_record *pd, enum fp_direction_type rd, extended *px,
1847c478bd9Sstevel@tonic-gate     fp_exception_field_type *ps)
1857c478bd9Sstevel@tonic-gate {
1867c478bd9Sstevel@tonic-gate 	extended_equivalence	kluge;
1877c478bd9Sstevel@tonic-gate 	unpacked		u;
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	*ps = 0;
1907c478bd9Sstevel@tonic-gate 	if (pd->fpclass == fp_zero) {
1917c478bd9Sstevel@tonic-gate 		kluge.f.msw.sign = pd->sign? 1 : 0;
1927c478bd9Sstevel@tonic-gate 		kluge.f.msw.exponent = 0;
1937c478bd9Sstevel@tonic-gate 		kluge.f.significand = 0;
1947c478bd9Sstevel@tonic-gate 		kluge.f.significand2 = 0;
1957c478bd9Sstevel@tonic-gate 		(*px)[0] = kluge.x[0];
1967c478bd9Sstevel@tonic-gate 		(*px)[1] = kluge.x[1];
1977c478bd9Sstevel@tonic-gate 		(*px)[2] = kluge.x[2];
1987c478bd9Sstevel@tonic-gate 	} else {
1997c478bd9Sstevel@tonic-gate 		__hex_to_unpacked(pd, &u);
2007c478bd9Sstevel@tonic-gate 		__pack_extended(&u, px, rd, ps);
2017c478bd9Sstevel@tonic-gate 		if (*ps != 0)
2027c478bd9Sstevel@tonic-gate 			__base_conversion_set_exception(*ps);
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate }
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate #else
2077c478bd9Sstevel@tonic-gate #error Unknown architecture
2087c478bd9Sstevel@tonic-gate #endif
209