1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #if !defined(sparc) && !defined(__sparc) 30 #error This code is for SPARC only 31 #endif 32 33 /* 34 * _Q_scl(x, n) sets *x = *x * 2^n. 35 * 36 * This routine tacitly assumes the result will be either zero 37 * or normal, so there is no need to raise any exceptions. 38 */ 39 void 40 _Q_scl(long double *x, int n) 41 { 42 union { 43 unsigned int i[4]; 44 long double q; 45 } xx; 46 int hx; 47 48 xx.q = *x; 49 hx = xx.i[0] & ~0x80000000; 50 51 if (hx < 0x10000) { /* x is zero or subnormal */ 52 if ((hx | xx.i[1] | xx.i[2] | xx.i[3]) == 0) 53 return; 54 55 /* normalize x */ 56 while (hx == 0 && xx.i[1] < 0x10000) { 57 hx = xx.i[1]; 58 xx.i[1] = xx.i[2]; 59 xx.i[2] = xx.i[3]; 60 xx.i[3] = 0; 61 n -= 32; 62 } 63 while (hx < 0x10000) { 64 hx = (hx << 1) | (xx.i[1] >> 31); 65 xx.i[1] = (xx.i[1] << 1) | (xx.i[2] >> 31); 66 xx.i[2] = (xx.i[2] << 1) | (xx.i[3] >> 31); 67 xx.i[3] <<= 1; 68 n--; 69 } 70 xx.i[0] = hx | (xx.i[0] & 0x80000000); 71 } 72 73 if ((hx >> 16) + n < 1) { 74 /* for subnormal result, just deliver zero */ 75 xx.i[0] = xx.i[0] & 0x80000000; 76 xx.i[1] = xx.i[2] = xx.i[3] = 0; 77 } else 78 xx.i[0] += (n << 16); 79 *x = xx.q; 80 } 81 82 static const union { 83 int i[4]; 84 long double q; 85 } consts[2] = { 86 { 0x7ffe0000, 0, 0, 0 }, 87 { 0x00010000, 0, 0, 0 } 88 }; 89 90 /* 91 * _Q_scle(x, n) sets *x = *x * 2^n, raising overflow or underflow 92 * as appropriate. 93 * 94 * This routine tacitly assumes the argument is either zero or normal. 95 */ 96 void 97 _Q_scle(long double *x, int n) 98 { 99 union { 100 unsigned int i[4]; 101 long double q; 102 } xx; 103 int hx; 104 105 xx.q = *x; 106 hx = (xx.i[0] >> 16) & 0x7fff; 107 108 if (hx == 0) /* x must be zero */ 109 return; 110 111 hx += n; 112 if (hx >= 0x7fff) { /* overflow */ 113 xx.i[0] = 0x7ffe0000 | (xx.i[0] & 0x80000000); 114 xx.i[1] = xx.i[2] = xx.i[3] = 0; 115 xx.q *= consts[0].q; 116 } else if (hx < 1) { /* possible underflow */ 117 if (hx < -112) { 118 xx.i[0] = 0x00010000 | (xx.i[0] & 0x80000000); 119 xx.i[1] = xx.i[2] = xx.i[3] = 0; 120 } else { 121 xx.i[0] = (0x3ffe0000 + (hx << 16)) | 122 (xx.i[0] & 0x8000ffff); 123 } 124 xx.q *= consts[1].q; 125 } else 126 xx.i[0] += (n << 16); 127 128 *x = xx.q; 129 } 130