usr/src/lib/libc/port/gen/_ftoull.c
author Jon Tibble <meths@btinternet.com>
Thu, 09 Dec 2010 22:32:39 +0100
changeset 13255 4afa820d78b9
parent 6812 febeba71273d
permissions -rw-r--r--
298 SPARC build fails in smt_pause.o 478 Build needs fixing for pkgdepend flag day Reviewed by: [email protected] Reviewed by: [email protected] Reviewed by: [email protected] Approved by: [email protected]
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
0
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
     1
/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
     2
 * CDDL HEADER START
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
     3
 *
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
     4
 * The contents of this file are subject to the terms of the
6812
febeba71273d PSARC 2008/309 expunge synonyms.h
raf
parents: 0
diff changeset
     5
 * Common Development and Distribution License (the "License").
febeba71273d PSARC 2008/309 expunge synonyms.h
raf
parents: 0
diff changeset
     6
 * You may not use this file except in compliance with the License.
0
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
     7
 *
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
     8
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
     9
 * or http://www.opensolaris.org/os/licensing.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    10
 * See the License for the specific language governing permissions
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    11
 * and limitations under the License.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    12
 *
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    13
 * When distributing Covered Code, include this CDDL HEADER in each
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    14
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    15
 * If applicable, add the following below this CDDL HEADER, with the
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    16
 * fields enclosed by brackets "[]" replaced with your own identifying
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    17
 * information: Portions Copyright [yyyy] [name of copyright owner]
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    18
 *
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    19
 * CDDL HEADER END
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    20
 */
6812
febeba71273d PSARC 2008/309 expunge synonyms.h
raf
parents: 0
diff changeset
    21
0
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    22
/*
6812
febeba71273d PSARC 2008/309 expunge synonyms.h
raf
parents: 0
diff changeset
    23
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
0
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    24
 * Use is subject to license terms.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    25
 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    26
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    27
#pragma ident	"%Z%%M%	%I%	%E% SMI"
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    28
6812
febeba71273d PSARC 2008/309 expunge synonyms.h
raf
parents: 0
diff changeset
    29
#include "lint.h"
0
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    30
#include <sys/isa_defs.h>
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    31
#include <floatingpoint.h>
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    32
#include <limits.h>
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    33
#include "libc.h"
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    34
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    35
/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    36
 * Ensure that this "portable" code is only used on big-endian ISAs
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    37
 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    38
#if !defined(_BIG_ENDIAN) || defined(_LITTLE_ENDIAN)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    39
#error	"big-endian only!"
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    40
#endif
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    41
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    42
/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    43
 * Convert a double precision floating point # into a 64-bit unsigned int.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    44
 *
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    45
 * For compatibility with Sun's other conversion routines, pretend result
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    46
 * is signed if input is negative.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    47
 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    48
unsigned long long
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    49
__dtoull(double dval)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    50
{
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    51
	int i0;			/* bitslam */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    52
	unsigned i1;		/* bitslam */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    53
	int exp;		/* exponent */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    54
	unsigned int m0;	/* most significant word of mantissa */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    55
	unsigned int m1;	/* least sig. word of mantissa */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    56
	unsigned int _fp_current_exceptions = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    57
	union {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    58
		int i[2];
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    59
		double d;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    60
	} u;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    61
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    62
	/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    63
	 * Extract the exponent and check boundary conditions.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    64
	 * Notice that the exponent is equal to the bit number where
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    65
	 * we want the most significant bit to live.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    66
	 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    67
	u.d = dval;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    68
	i0 = u.i[0];
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    69
	i1 = u.i[1];
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    70
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    71
	exp = ((i0 >> 20) & 0x7ff) - 0x3ff;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    72
	if (exp < 0) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    73
		/* abs(x) < 1.0, so round to 0 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    74
		return ((unsigned long long)0);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    75
	} else if (exp > 63)  {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    76
		/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    77
		 * abs(x) > MAXLLONG; return {MIN,MAX}ULLONG and as
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    78
		 * overflow, Inf, NaN set fp_invalid exception
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    79
		 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    80
		_fp_current_exceptions |= (1 << (int)fp_invalid);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    81
		(void) _Q_set_exception(_fp_current_exceptions);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    82
		if (i0 < 0)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    83
			return ((unsigned long long)LLONG_MIN);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    84
		else
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    85
			return (ULLONG_MAX); /* MAXLONG */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    86
	}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    87
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    88
	/* Extract the mantissa. */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    89
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    90
	m0 = 0x80000000 | ((i0 << 11) & 0x7ffff800) | ((i1 >> 21) & 0x7ff);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    91
	m1 = i1 << 11;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    92
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    93
	/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    94
	 * The most significant bit of the mantissa is now in bit 63 of m0:m1.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    95
	 * Shift right by (63 - exp) bits.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    96
	 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    97
	switch (exp) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    98
	case 63:
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    99
		break;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   100
	case 31:
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   101
		m1 = m0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   102
		m0 = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   103
		break;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   104
	default:
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   105
		if (exp > 31) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   106
			m1 = (m0 << (exp - 31)) | (m1 >> (63 - exp));
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   107
			m0 = (m0 >> (63 - exp));
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   108
		} else {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   109
			m1 = (m0 >> (31 - exp));
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   110
			m0 = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   111
		}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   112
		break;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   113
	}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   114
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   115
	if (i0 < 0) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   116
		if ((int)m0 < 0) {	/* x < MINLLONG; return MINLLONG */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   117
			m0 = 0x80000000;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   118
			m1 = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   119
		} else {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   120
			m0 = ~m0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   121
			m1 = ~m1;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   122
			if (++m1 == 0)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   123
				m0++;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   124
		}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   125
	}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   126
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   127
	(void) _Q_set_exception(_fp_current_exceptions);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   128
	return (((unsigned long long)m0 << 32) | m1);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   129
}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   130
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   131
/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   132
 * Convert a floating point number into a 64-bit unsigned int.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   133
 *
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   134
 * For compatibility with Sun's other conversion routines, pretend result
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   135
 * is signed if input is negative.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   136
 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   137
unsigned long long
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   138
__ftoull(float fval)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   139
{
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   140
	int i0;			/* bitslam */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   141
	int exp;		/* exponent */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   142
	unsigned int m0;	/* most significant word of mantissa */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   143
	unsigned int m1;	/* least sig. word of mantissa */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   144
	unsigned int _fp_current_exceptions = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   145
	union {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   146
		int i;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   147
		float f;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   148
	} u;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   149
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   150
	/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   151
	 * Extract the exponent and check boundary conditions.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   152
	 * Notice that the exponent is equal to the bit number where
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   153
	 * we want the most significant bit to live.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   154
	 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   155
	u.f = fval;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   156
	i0 = u.i;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   157
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   158
	exp = ((i0 >> 23) & 0xff) - 0x7f;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   159
	if (exp < 0) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   160
		/* abs(x) < 1.0, so round to 0 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   161
		return ((unsigned long long)0);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   162
	} else if (exp > 63)  {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   163
		/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   164
		 * abs(x) > MAXLLONG; return {MIN,MAX}ULLONG and as
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   165
		 * overflow, Inf, NaN set fp_invalid exception
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   166
		 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   167
		_fp_current_exceptions |= (1 << (int)fp_invalid);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   168
		(void) _Q_set_exception(_fp_current_exceptions);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   169
		if (i0 < 0)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   170
			return ((unsigned long long)LLONG_MIN);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   171
		else
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   172
			return (ULLONG_MAX); /* MAXLONG */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   173
	}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   174
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   175
	/* Extract the mantissa. */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   176
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   177
	m0 = 0x80000000 | (i0 << 8) & 0x7fffff00;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   178
	m1 = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   179
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   180
	/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   181
	 * The most significant bit of the mantissa is now in bit 63 of m0:m1.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   182
	 * Shift right by (63 - exp) bits.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   183
	 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   184
	switch (exp) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   185
	case 63:
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   186
		break;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   187
	case 31:
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   188
		m1 = m0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   189
		m0 = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   190
		break;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   191
	default:
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   192
		if (exp > 31) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   193
			m1 = m0 << (exp - 31);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   194
			m0 = (m0 >> (63 - exp));
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   195
		} else {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   196
			m1 = (m0 >> (31 - exp));
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   197
			m0 = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   198
		}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   199
		break;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   200
	}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   201
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   202
	if (i0 < 0) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   203
		if ((int)m0 < 0) {	/* x < MINLLONG; return MINLLONG */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   204
			m0 = 0x80000000;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   205
			m1 = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   206
		} else {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   207
			m0 = ~m0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   208
			m1 = ~m1;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   209
			if (++m1 == 0)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   210
				m0++;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   211
		}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   212
	}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   213
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   214
	(void) _Q_set_exception(_fp_current_exceptions);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   215
	return (((unsigned long long)m0 << 32) | m1);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   216
}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   217
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   218
/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   219
 * Convert an extended precision floating point # into a 64-bit unsigned int.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   220
 *
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   221
 * For compatibility with Sun's other conversion routines, pretend result
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   222
 * is signed if input is negative.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   223
 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   224
unsigned long long
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   225
_Q_qtoull(long double ld)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   226
{
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   227
	int i0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   228
	unsigned int i1, i2;	/* a long double is 128-bit in length */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   229
	int exp;		/* exponent */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   230
	unsigned int m0;	/* most significant word of mantissa */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   231
	unsigned int m1;	/* least sig. word of mantissa */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   232
	unsigned int _fp_current_exceptions = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   233
	int	 *plngdbl = (int *)&ld;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   234
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   235
	/* Only 96-bits of precision used */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   236
	i0 = plngdbl[0];
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   237
	i1 = plngdbl[1];
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   238
	i2 = plngdbl[2];
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   239
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   240
	/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   241
	 * Extract the exponent and check boundary conditions.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   242
	 * Notice that the exponent is equal to the bit number where
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   243
	 * we want the most significant bit to live.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   244
	 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   245
	exp = ((i0 >> 16) & 0x7fff) - 0x3fff;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   246
	if (exp < 0) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   247
		return ((long long)0); /* abs(x) < 1.0, so round to 0 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   248
	} else if (exp > 63) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   249
		/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   250
		 * abs(x) > MAXLLONG; return {MIN,MAX}ULLONG and as
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   251
		 * overflow, Inf, NaN set fp_invalid exception
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   252
		 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   253
		_fp_current_exceptions |= (1 << (int)fp_invalid);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   254
		(void) _Q_set_exception(_fp_current_exceptions);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   255
		if (i0 < 0)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   256
			return ((unsigned long long)LLONG_MIN);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   257
		else
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   258
			return (ULLONG_MAX); /* MAXLONG */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   259
	}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   260
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   261
	/* Extract the mantissa. */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   262
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   263
	m0 = 0x80000000 | ((i0<<15) & 0x7fff8000) | ((i1>>17) & 0x7fff);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   264
	m1 = (i1 << 15) | ((i2 >> 17) & 0x7fff);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   265
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   266
	/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   267
	 * The most significant bit of the mantissa is now in bit 63 of m0:m1.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   268
	 * Shift right by (63 - exp) bits.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   269
	 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   270
	switch (exp) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   271
	case 63:
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   272
		break;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   273
	case 31:
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   274
		m1 = m0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   275
		m0 = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   276
		break;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   277
	default:
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   278
		if (exp > 31) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   279
			m1 = (m0 << (exp - 31)) | (m1 >> (63 - exp));
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   280
			m0 = (m0 >> (63 - exp));
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   281
		} else {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   282
			m1 = (m0 >> (31 - exp));
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   283
			m0 = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   284
		}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   285
		break;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   286
	}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   287
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   288
	if (i0 < 0) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   289
		if ((int)m0 < 0) {	/* x < MINLLONG; return MINLLONG */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   290
			m0 = 0x80000000;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   291
			m1 = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   292
		} else {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   293
			m0 = ~m0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   294
			m1 = ~m1;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   295
			if (++m1 == 0)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   296
				m0++;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   297
		}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   298
	}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   299
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   300
	(void) _Q_set_exception(_fp_current_exceptions);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   301
	return (((unsigned long long)m0 << 32) | m1);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   302
}