2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#include "lint.h"
2N/A#include "base_conversion.h"
2N/A
2N/A/* translation table from hex values to hex chars */
2N/Astatic const char *hexchar = "0123456789abcdef";
2N/A
2N/A/*
2N/A * Convert arg to a hexadecimal string.
2N/A *
2N/A * If arg is finite and nonzero, buf is filled with ndigits hexadecimal
2N/A * digits, representing the significand of arg, followed by a null byte
2N/A * (so ndigits must be at least 1 and buf must be large enough to hold
2N/A * ndigits + 1 characters). If ndigits is large enough, the representa-
2N/A * tion is exact; otherwise, the value is rounded according to the pre-
2N/A * vailing rounding mode to fit the requested number of digits. Either
2N/A * way, the result is normalized so that the first digit is '1'. The
2N/A * corresponding base two exponent is passed back in *exp.
2N/A *
2N/A * If arg is zero, buf is filled with ndigits zeros followed by a null,
2N/A * and *exp is set to zero. If arg is infinite or NaN, __infnanstring
2N/A * is called to place an appropriate string in buf, and *exp is set to
2N/A * zero.
2N/A *
2N/A * Regardless of the value of arg, its sign bit is stored in *sign.
2N/A */
2N/A
2N/A#if defined(__sparc)
2N/A
2N/Avoid
2N/A__aconvert(double arg, int ndigits, int *exp, int *sign, char *buf)
2N/A{
2N/A union {
2N/A unsigned int i[2];
2N/A long long l;
2N/A double d;
2N/A } a, c;
2N/A int ha, i, s;
2N/A unsigned int d;
2N/A
2N/A a.d = arg;
2N/A *sign = s = a.i[0] >> 31;
2N/A ha = a.i[0] & ~0x80000000;
2N/A
2N/A /* check for infinity or nan */
2N/A if (ha >= 0x7ff00000) {
2N/A *exp = 0;
2N/A __infnanstring((ha == 0x7ff00000 && a.i[1] == 0)?
2N/A fp_infinity : fp_quiet, ndigits, buf);
2N/A return;
2N/A }
2N/A
2N/A /* check for subnormal or zero */
2N/A if (ha < 0x00100000) {
2N/A if ((ha | a.i[1]) == 0) {
2N/A *exp = 0;
2N/A for (i = 0; i < ndigits; i++)
2N/A buf[i] = '0';
2N/A buf[ndigits] = '\0';
2N/A return;
2N/A }
2N/A
2N/A /*
2N/A * Normalize. It would be much simpler if we could just
2N/A * multiply by a power of two here, but some SPARC imple-
2N/A * mentations would flush the subnormal operand to zero
2N/A * when nonstandard mode is enabled.
2N/A */
2N/A a.i[0] = ha;
2N/A a.d = (double)a.l;
2N/A if (s)
2N/A a.d = -a.d;
2N/A ha = a.i[0] & ~0x80000000;
2N/A *exp = (ha >> 20) - 0x3ff - 1074;
2N/A } else {
2N/A *exp = (ha >> 20) - 0x3ff;
2N/A }
2N/A
2N/A if (ndigits < 14) {
2N/A /*
2N/A * Round the significand at the appropriate bit by adding
2N/A * and subtracting a power of two. This will also raise
2N/A * the inexact exception if anything is rounded off.
2N/A */
2N/A c.i[0] = (0x43700000 | (s << 31)) - (ndigits << 22);
2N/A c.i[1] = 0;
2N/A a.i[0] = (a.i[0] & 0x800fffff) | 0x3ff00000;
2N/A a.d = (a.d + c.d) - c.d;
2N/A ha = a.i[0] & ~0x80000000;
2N/A if (ha >= 0x40000000)
2N/A (*exp)++;
2N/A }
2N/A
2N/A /* convert to hex digits */
2N/A buf[0] = '1';
2N/A d = ha << 12;
2N/A for (i = 1; i < ndigits && i < 6; i++) {
2N/A buf[i] = hexchar[d >> 28];
2N/A d <<= 4;
2N/A }
2N/A d = a.i[1];
2N/A for (; i < ndigits && i < 14; i++) {
2N/A buf[i] = hexchar[d >> 28];
2N/A d <<= 4;
2N/A }
2N/A for (; i < ndigits; i++)
2N/A buf[i] = '0';
2N/A buf[ndigits] = '\0';
2N/A}
2N/A
2N/Avoid
2N/A__qaconvert(long double *arg, int ndigits, int *exp, int *sign, char *buf)
2N/A{
2N/A union {
2N/A unsigned int i[4];
2N/A long double q;
2N/A } a;
2N/A enum fp_direction_type rd;
2N/A int ha, i, s;
2N/A unsigned int b, r, d;
2N/A
2N/A a.q = *arg;
2N/A *sign = a.i[0] >> 31;
2N/A ha = a.i[0] &= ~0x80000000;
2N/A
2N/A /* check for infinity or nan */
2N/A if (ha >= 0x7fff0000) {
2N/A *exp = 0;
2N/A __infnanstring((ha == 0x7fff0000 && (a.i[1] | a.i[2] | a.i[3])
2N/A == 0)? fp_infinity : fp_quiet, ndigits, buf);
2N/A return;
2N/A }
2N/A
2N/A /* check for subnormal or zero */
2N/A if (ha < 0x00010000) {
2N/A if ((ha | a.i[1] | a.i[2] | a.i[3]) == 0) {
2N/A *exp = 0;
2N/A for (i = 0; i < ndigits; i++)
2N/A buf[i] = '0';
2N/A buf[ndigits] = '\0';
2N/A return;
2N/A }
2N/A
2N/A /* normalize */
2N/A i = 0;
2N/A while ((a.i[0] | (a.i[1] & 0xffff0000)) == 0) {
2N/A a.i[0] = a.i[1];
2N/A a.i[1] = a.i[2];
2N/A a.i[2] = a.i[3];
2N/A a.i[3] = 0;
2N/A i += 32;
2N/A }
2N/A while ((a.i[0] & 0x7fff0000) == 0) {
2N/A a.i[0] = (a.i[0] << 1) | (a.i[1] >> 31);
2N/A a.i[1] = (a.i[1] << 1) | (a.i[2] >> 31);
2N/A a.i[2] = (a.i[2] << 1) | (a.i[3] >> 31);
2N/A a.i[3] <<= 1;
2N/A i++;
2N/A }
2N/A *exp = -0x3ffe - i;
2N/A } else {
2N/A *exp = (ha >> 16) - 0x3fff;
2N/A }
2N/A
2N/A if (ndigits < 29) {
2N/A /*
2N/A * Round the significand at the appropriate bit using
2N/A * integer arithmetic. Explicitly raise the inexact
2N/A * exception if anything is rounded off.
2N/A */
2N/A a.i[0] = (a.i[0] & 0xffff) | 0x10000;
2N/A if (ndigits <= 5) {
2N/A /*
2N/A * i and b are the index and bit position in a.i[]
2N/A * of the last bit to be retained. r holds the bits
2N/A * to be rounded off, left-adjusted and sticky.
2N/A */
2N/A i = 0;
2N/A s = (5 - ndigits) << 2;
2N/A b = 1 << s;
2N/A r = ((a.i[0] << 1) << (31 - s)) | (a.i[1] >> s);
2N/A if ((a.i[1] & (b - 1)) | a.i[2] | a.i[3])
2N/A r |= 1;
2N/A a.i[0] &= ~(b - 1);
2N/A a.i[1] = a.i[2] = a.i[3] = 0;
2N/A } else if (ndigits <= 13) {
2N/A i = 1;
2N/A s = (13 - ndigits) << 2;
2N/A b = 1 << s;
2N/A r = ((a.i[1] << 1) << (31 - s)) | (a.i[2] >> s);
2N/A if ((a.i[2] & (b - 1)) | a.i[3])
2N/A r |= 1;
2N/A a.i[1] &= ~(b - 1);
2N/A a.i[2] = a.i[3] = 0;
2N/A } else if (ndigits <= 21) {
2N/A i = 2;
2N/A s = (21 - ndigits) << 2;
2N/A b = 1 << s;
2N/A r = ((a.i[2] << 1) << (31 - s)) | (a.i[3] >> s);
2N/A if (a.i[3] & (b - 1))
2N/A r |= 1;
2N/A a.i[2] &= ~(b - 1);
2N/A a.i[3] = 0;
2N/A } else {
2N/A i = 3;
2N/A s = (29 - ndigits) << 2;
2N/A b = 1 << s;
2N/A r = (a.i[3] << 1) << (31 - s);
2N/A a.i[3] &= ~(b - 1);
2N/A }
2N/A
2N/A /* conversion is inexact if r is not zero */
2N/A if (r) {
2N/A __base_conversion_set_exception(
2N/A (fp_exception_field_type)(1 << fp_inexact));
2N/A
2N/A /* massage the rounding direction based on the sign */
2N/A rd = _QgetRD();
2N/A if (*sign && (rd == fp_positive || rd == fp_negative))
2N/A rd = fp_positive + fp_negative - rd;
2N/A
2N/A /* decide whether to round up */
2N/A if (rd == fp_positive || (rd == fp_nearest &&
2N/A (r > 0x80000000u || (r == 0x80000000u &&
2N/A (a.i[i] & b))))) {
2N/A a.i[i] += b;
2N/A while (a.i[i] == 0)
2N/A a.i[--i]++;
2N/A if (a.i[0] >= 0x20000)
2N/A (*exp)++;
2N/A }
2N/A }
2N/A }
2N/A
2N/A /* convert to hex digits */
2N/A buf[0] = '1';
2N/A d = a.i[0] << 16;
2N/A for (i = 1; i < ndigits && i < 5; i++) {
2N/A buf[i] = hexchar[d >> 28];
2N/A d <<= 4;
2N/A }
2N/A d = a.i[1];
2N/A for (; i < ndigits && i < 13; i++) {
2N/A buf[i] = hexchar[d >> 28];
2N/A d <<= 4;
2N/A }
2N/A d = a.i[2];
2N/A for (; i < ndigits && i < 21; i++) {
2N/A buf[i] = hexchar[d >> 28];
2N/A d <<= 4;
2N/A }
2N/A d = a.i[3];
2N/A for (; i < ndigits && i < 29; i++) {
2N/A buf[i] = hexchar[d >> 28];
2N/A d <<= 4;
2N/A }
2N/A for (; i < ndigits; i++)
2N/A buf[i] = '0';
2N/A buf[ndigits] = '\0';
2N/A}
2N/A
2N/A#elif defined(__i386) || defined(__amd64)
2N/A
2N/A/*
2N/A * The following code assumes the rounding precision mode is set
2N/A * to the default (round to 64 bits).
2N/A */
2N/Avoid
2N/A__qaconvert(long double *arg, int ndigits, int *exp, int *sign, char *buf)
2N/A{
2N/A union {
2N/A unsigned int i[3];
2N/A long double x;
2N/A } a, c;
2N/A int ea, i, s;
2N/A unsigned int d;
2N/A
2N/A a.x = *arg;
2N/A *sign = s = (a.i[2] >> 15) & 1;
2N/A ea = a.i[2] & 0x7fff;
2N/A
2N/A /* check for infinity or nan */
2N/A if (ea == 0x7fff) {
2N/A *exp = 0;
2N/A __infnanstring((((a.i[1] << 1) | a.i[0]) == 0)?
2N/A fp_infinity : fp_quiet, ndigits, buf);
2N/A return;
2N/A }
2N/A
2N/A /* check for subnormal or zero */
2N/A if (ea == 0) {
2N/A if ((a.i[1] | a.i[0]) == 0) {
2N/A *exp = 0;
2N/A for (i = 0; i < ndigits; i++)
2N/A buf[i] = '0';
2N/A buf[ndigits] = '\0';
2N/A return;
2N/A }
2N/A
2N/A /* normalize */
2N/A a.x *= 18446744073709551616.0; /* 2^64 */
2N/A ea = a.i[2] & 0x7fff;
2N/A *exp = ea - 0x403f;
2N/A } else {
2N/A *exp = ea - 0x3fff;
2N/A }
2N/A
2N/A if (ndigits < 17) {
2N/A /*
2N/A * Round the significand at the appropriate bit by adding
2N/A * and subtracting a power of two. This will also raise
2N/A * the inexact exception if anything is rounded off.
2N/A */
2N/A c.i[2] = (0x4042 | (s << 15)) - (ndigits << 2);
2N/A c.i[1] = 0x80000000;
2N/A c.i[0] = 0;
2N/A a.i[2] = 0x3fff | (s << 15);
2N/A a.x = (a.x + c.x) - c.x;
2N/A ea = a.i[2] & 0x7fff;
2N/A if (ea >= 0x4000)
2N/A (*exp)++;
2N/A }
2N/A
2N/A /* convert to hex digits */
2N/A buf[0] = '1';
2N/A d = (a.i[1] << 1) | (a.i[0] >> 31);
2N/A for (i = 1; i < ndigits && i < 9; i++) {
2N/A buf[i] = hexchar[d >> 28];
2N/A d <<= 4;
2N/A }
2N/A d = a.i[0] << 1;
2N/A for (; i < ndigits && i < 17; i++) {
2N/A buf[i] = hexchar[d >> 28];
2N/A d <<= 4;
2N/A }
2N/A for (; i < ndigits; i++)
2N/A buf[i] = '0';
2N/A buf[ndigits] = '\0';
2N/A}
2N/A
2N/Avoid
2N/A__aconvert(double arg, int ndigits, int *exp, int *sign, char *buf)
2N/A{
2N/A union {
2N/A int i[2];
2N/A double d;
2N/A } a;
2N/A long double ldarg;
2N/A int ha;
2N/A
2N/A /* avoid raising invalid operation exception for signaling nan */
2N/A a.i[0] = *(int *)&arg;
2N/A a.i[1] = *(1+(int *)&arg);
2N/A ha = a.i[1] & ~0x80000000;
2N/A if (ha > 0x7ff00000 || (ha == 0x7ff00000 && a.i[0] != 0))
2N/A a.i[1] |= 0x80000; /* make nan quiet */
2N/A ldarg = a.d;
2N/A __qaconvert(&ldarg, ndigits, exp, sign, buf);
2N/A}
2N/A
2N/A#else
2N/A#error Unknown architecture
2N/A#endif