usr/src/lib/libc/port/gen/_ftoll.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 number into a 64-bit int.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    44
 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    45
long long
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    46
__dtoll(double dval)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    47
{
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    48
	int i0, i1;		/* bitslam */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    49
	int exp;		/* exponent */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    50
	int m0;			/* most significant word of mantissa */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    51
	unsigned int m1;	/* least sig. word of mantissa */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    52
	unsigned int _fp_current_exceptions = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    53
	union {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    54
		int i[2];
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    55
		double d;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    56
	} u;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    57
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    58
	/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    59
	 * Extract the exponent and check boundary conditions.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    60
	 * Notice that the exponent is equal to the bit number where
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    61
	 * we want the most significant bit to live.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    62
	 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    63
	u.d = dval;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    64
	i0 = u.i[0];
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    65
	i1 = u.i[1];
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    66
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    67
	exp = ((i0 >> 20) & 0x7ff) - 0x3ff;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    68
	if (exp < 0) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    69
		return ((long long)0); /* abs(x) < 1.0, so round to 0 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    70
	} else if (exp > 62) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    71
		/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    72
		 * fp_invalid NOT raised if <i0,i1> == LLONG_MIN
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    73
		 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    74
		if (i0 >= 0 || exp != 63 || (i0 & 0xfffff) != 0 || i1 != 0) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    75
			/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    76
			 * abs(x) > MAXLLONG; return {MIN,MAX}LLONG and as
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    77
			 * overflow, Inf, NaN set fp_invalid exception
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    78
			 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    79
			_fp_current_exceptions |= (1 << (int)fp_invalid);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    80
			(void) _Q_set_exception(_fp_current_exceptions);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    81
		}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    82
		if (i0 < 0)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    83
			return (LLONG_MIN);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    84
		else
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    85
			return (LLONG_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 = 0x40000000 | ((i0 << 10) & 0x3ffffc00) | ((i1 >> 22) & 0x3ff);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    91
	m1 = i1 << 10;
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 62 of m0:m1.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    95
	 * Shift right by (62 - 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 62:
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
    99
		break;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   100
	case 30:
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 > 30) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   106
			m1 = (m0 << (exp - 30)) |
6812
febeba71273d PSARC 2008/309 expunge synonyms.h
raf
parents: 0
diff changeset
   107
			    (m1 >> (62 - exp)) & ~(-1 << (exp - 30));
0
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   108
			m0 >>= 62 - exp;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   109
		} else {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   110
			m1 = m0 >> (30 - exp);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   111
			m0 = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   112
		}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   113
		break;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   114
	}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   115
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   116
	if (i0 < 0) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   117
		m0 = ~m0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   118
		m1 = ~m1;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   119
		if (++m1 == 0)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   120
			m0++;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   121
	}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   122
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   123
	(void) _Q_set_exception(_fp_current_exceptions);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   124
	return ((long long)(((unsigned long long)m0 << 32) | m1));
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
/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   128
 * Convert a floating point number into a 64-bit int.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   129
 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   130
long long
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   131
__ftoll(float fval)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   132
{
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   133
	int i0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   134
	int exp;		/* exponent */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   135
	int m0;			/* most significant word of mantissa */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   136
	unsigned int m1;	/* least sig. word of mantissa */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   137
	unsigned int _fp_current_exceptions = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   138
	union {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   139
		int i;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   140
		float f;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   141
	} u;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   142
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   143
	/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   144
	 * Extract the exponent and check boundary conditions.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   145
	 * Notice that the exponent is equal to the bit number where
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   146
	 * we want the most significant bit to live.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   147
	 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   148
	u.f = fval;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   149
	i0 = u.i;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   150
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   151
	exp = ((i0 >> 23) & 0xff) - 0x7f;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   152
	if (exp < 0) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   153
		return ((long long) 0); /* abs(x) < 1.0, so round to 0 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   154
	} else if (exp > 62)  {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   155
		/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   156
		 * fp_invalid NOT raised if <i0> == LLONG_MIN
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   157
		 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   158
		if (i0 >= 0 || exp != 63 || (i0 & 0x7fffff) != 0) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   159
			/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   160
			 * abs(x) > MAXLLONG; return {MIN,MAX}LLONG and as
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   161
			 * overflow, Inf, NaN set fp_invalid exception
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   162
			 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   163
			_fp_current_exceptions |= (1 << (int)fp_invalid);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   164
			(void) _Q_set_exception(_fp_current_exceptions);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   165
		}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   166
		if (i0 < 0)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   167
			return (LLONG_MIN);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   168
		else
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   169
			return (LLONG_MAX); /* MAXLONG */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   170
	}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   171
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   172
	/* Extract the mantissa. */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   173
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   174
	m0 = 0x40000000 | (i0 << 7) & 0x3fffff80;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   175
	m1 = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   176
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   177
	/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   178
	 * The most significant bit of the mantissa is now in bit 62 of m0:m1.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   179
	 * Shift right by (62 - exp) bits.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   180
	 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   181
	switch (exp) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   182
	case 62:
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   183
		break;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   184
	case 30:
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   185
		m1 = m0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   186
		m0 = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   187
		break;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   188
	default:
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   189
		if (exp > 30) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   190
			m1 = m0 << (exp - 30);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   191
			m0 >>= 62 - exp;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   192
		} else {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   193
			m1 = m0 >> (30 - exp);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   194
			m0 = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   195
		}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   196
		break;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   197
	}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   198
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   199
	if (i0 < 0) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   200
		m0 = ~m0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   201
		m1 = ~m1;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   202
		if (++m1 == 0)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   203
			m0++;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   204
	}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   205
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   206
	(void) _Q_set_exception(_fp_current_exceptions);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   207
	return ((long long)(((unsigned long long)m0 << 32) | m1));
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   208
}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   209
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   210
/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   211
 * Convert an extended precision floating point number into a 64-bit int.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   212
 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   213
long long
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   214
_Q_qtoll(long double longdbl)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   215
{
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   216
	int i0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   217
	unsigned int i1, i2;	/* a long double is 128-bit in length */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   218
	int *plngdbl = (int *)&longdbl;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   219
	int exp;		/* exponent */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   220
	int m0;			/* most significant word of mantissa */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   221
	unsigned int m1;	/* least sig. word of mantissa */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   222
	unsigned int _fp_current_exceptions = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   223
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   224
	/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   225
	 * Only 96-bits of precision used
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   226
	 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   227
	i0 = plngdbl[0];
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   228
	i1 = plngdbl[1];
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   229
	i2 = plngdbl[2];
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   230
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   231
	/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   232
	 * Extract the exponent and check boundary conditions.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   233
	 * Notice that the exponent is equal to the bit number where
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   234
	 * we want the most significant bit to live.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   235
	 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   236
	exp = ((i0 >> 16) & 0x7fff) - 0x3fff;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   237
	if (exp < 0) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   238
		return ((long long)0); /* abs(x) < 1.0, so round to 0 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   239
	} else if (exp > 62)	{
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   240
		/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   241
		 * fp_invalid NOT raised if <i0,i1,i2,i3> when chopped to
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   242
		 * 64 bits == LLONG_MIN
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   243
		 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   244
		if (i0 >= 0 || exp != 63 || (i0 & 0xffff) != 0 || i1 != 0 ||
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   245
		    (i2 & 0xfffe0000) != 0) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   246
			/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   247
			 * abs(x) > MAXLLONG; return {MIN,MAX}LLONG and as
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   248
			 * overflow, Inf, NaN set fp_invalid exception
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   249
			 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   250
			_fp_current_exceptions |= (1 << (int)fp_invalid);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   251
			(void) _Q_set_exception(_fp_current_exceptions);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   252
		}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   253
		if (i0 < 0)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   254
			return (LLONG_MIN);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   255
		else
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   256
			return (LLONG_MAX); /* MAXLONG */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   257
	}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   258
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   259
	/* Extract the mantissa. */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   260
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   261
	m0 = 0x40000000 | ((i0 << 14) & 0x3fffc000) | ((i1 >> 18) & 0x3fff);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   262
	m1 = (i1 << 14) | ((i2 >> 18) & 0x3fff);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   263
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   264
	/*
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   265
	 * The most significant bit of the mantissa is now in bit 62 of m0:m1.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   266
	 * Shift right by (62 - exp) bits.
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   267
	 */
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   268
	switch (exp) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   269
	case 62:
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   270
		break;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   271
	case 30:
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   272
		m1 = m0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   273
		m0 = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   274
		break;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   275
	default:
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   276
		if (exp > 30) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   277
			m1 = (m0 << (exp - 30)) |
6812
febeba71273d PSARC 2008/309 expunge synonyms.h
raf
parents: 0
diff changeset
   278
			    (m1 >> (62 - exp)) & ~(-1 << (exp - 30));
0
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   279
			m0 >>= 62 - exp;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   280
		} else {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   281
			m1 = m0 >> (30 - exp);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   282
			m0 = 0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   283
		}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   284
		break;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   285
	}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   286
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   287
	if (i0 < 0) {
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   288
		m0 = ~m0;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   289
		m1 = ~m1;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   290
		if (++m1 == 0)
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   291
			m0++;
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   292
	}
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   293
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   294
	(void) _Q_set_exception(_fp_current_exceptions);
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   295
	return ((long long)(((unsigned long long)m0 << 32) | m1));
68f95e015346 OpenSolaris Launch
stevel@tonic-gate
parents:
diff changeset
   296
}