/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "lint.h" #include "base_conversion.h" /* conversion from hex chars to hex values */ #define HEXVAL(c) (('0' <= c && c <= '9')? c - '0' : \ 10 + (('a' <= c && c <= 'f')? c - 'a' : c - 'A')) /* * Convert a hexadecimal record in *pd to unpacked form in *pu. * * Up to 30 hexadecimal digits from pd->ds are converted to a binary * value in px->significand, which is then normalized so that the most * significant bit is 1. If there are additional, unused digits in * pd->ds, the least significant bit of px->significand will be set. */ static void __hex_to_unpacked(decimal_record *pd, unpacked *pu) { int i, n; pu->sign = pd->sign; pu->fpclass = pd->fpclass; /* * Adjust the (base two) exponent to reflect the fact that the * radix point in *pd lies to the right of the last (base sixteen) * digit while the radix point in *pu lies to the right of the * most significant bit. */ pu->exponent = pd->exponent + (pd->ndigits << 2) - 1; /* fill in the significand */ for (i = 0; i < 5; i++) pu->significand[i] = 0; n = pd->ndigits; if (n > 30) n = 30; for (i = 0; i < n; i++) { pu->significand[i >> 3] |= HEXVAL(pd->ds[i]) << ((7 - (i & 7)) << 2); } /* sanity check */ if (pu->significand[0] == 0) { pu->fpclass = fp_zero; return; } /* normalize so the most significant bit is set */ while (pu->significand[0] < 0x80000000u) { pu->significand[0] = (pu->significand[0] << 1) | (pu->significand[1] >> 31); pu->significand[1] = (pu->significand[1] << 1) | (pu->significand[2] >> 31); pu->significand[2] = (pu->significand[2] << 1) | (pu->significand[3] >> 31); pu->significand[3] <<= 1; pu->exponent--; } /* if there are any unused digits, set a sticky bit */ if (pd->ndigits > 30 || pd->more) pu->significand[4] = 1; } /* * The following routines convert the hexadecimal value encoded in the * decimal record *pd to a floating point value *px observing the round- * ing mode specified in rd and passing back any exceptions raised via * *ps. * * These routines assume pd->fpclass is either fp_zero or fp_normal. * If pd->fpclass is fp_zero, *px is set to zero with the sign indicated * by pd->sign and no exceptions are raised. Otherwise, pd->ds must * contain a string of hexadecimal digits of length pd->ndigits > 0, and * the first digit must be nonzero. Let m be the integer represented by * this string. Then *px is set to a correctly rounded approximation to * * (-1)^(pd->sign) * m * 2^(pd->exponent) * * with inexact, underflow, and/or overflow raised as appropriate. */ void __hex_to_single(decimal_record *pd, enum fp_direction_type rd, single *px, fp_exception_field_type *ps) { single_equivalence kluge; unpacked u; *ps = 0; if (pd->fpclass == fp_zero) { kluge.f.msw.sign = pd->sign? 1 : 0; kluge.f.msw.exponent = 0; kluge.f.msw.significand = 0; *px = kluge.x; } else { __hex_to_unpacked(pd, &u); __pack_single(&u, px, rd, ps); if (*ps != 0) __base_conversion_set_exception(*ps); } } void __hex_to_double(decimal_record *pd, enum fp_direction_type rd, double *px, fp_exception_field_type *ps) { double_equivalence kluge; unpacked u; *ps = 0; if (pd->fpclass == fp_zero) { kluge.f.msw.sign = pd->sign? 1 : 0; kluge.f.msw.exponent = 0; kluge.f.msw.significand = 0; kluge.f.significand2 = 0; *px = kluge.x; } else { __hex_to_unpacked(pd, &u); __pack_double(&u, px, rd, ps); if (*ps != 0) __base_conversion_set_exception(*ps); } } #if defined(__sparc) void __hex_to_quadruple(decimal_record *pd, enum fp_direction_type rd, quadruple *px, fp_exception_field_type *ps) { quadruple_equivalence kluge; unpacked u; *ps = 0; if (pd->fpclass == fp_zero) { kluge.f.msw.sign = pd->sign? 1 : 0; kluge.f.msw.exponent = 0; kluge.f.msw.significand = 0; kluge.f.significand2 = 0; kluge.f.significand3 = 0; kluge.f.significand4 = 0; *px = kluge.x; } else { __hex_to_unpacked(pd, &u); __pack_quadruple(&u, px, rd, ps); if (*ps != 0) __base_conversion_set_exception(*ps); } } #elif defined(__i386) || defined(__amd64) void __hex_to_extended(decimal_record *pd, enum fp_direction_type rd, extended *px, fp_exception_field_type *ps) { extended_equivalence kluge; unpacked u; *ps = 0; if (pd->fpclass == fp_zero) { kluge.f.msw.sign = pd->sign? 1 : 0; kluge.f.msw.exponent = 0; kluge.f.significand = 0; kluge.f.significand2 = 0; (*px)[0] = kluge.x[0]; (*px)[1] = kluge.x[1]; (*px)[2] = kluge.x[2]; } else { __hex_to_unpacked(pd, &u); __pack_extended(&u, px, rd, ps); if (*ps != 0) __base_conversion_set_exception(*ps); } } #else #error Unknown architecture #endif