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 #if !defined(sparc) && !defined(__sparc) 28 #error This code is for SPARC only 29 #endif 30 31 /* 32 * _Q_scl(x, n) sets *x = *x * 2^n. 33 * 34 * This routine tacitly assumes the result will be either zero 35 * or normal, so there is no need to raise any exceptions. 36 */ 37 void 38 _Q_scl(long double *x, int n) 39 { 40 union { 41 unsigned int i[4]; 42 long double q; 43 } xx; 44 int hx; 45 46 xx.q = *x; 47 hx = xx.i[0] & ~0x80000000; 48 49 if (hx < 0x10000) { /* x is zero or subnormal */ 50 if ((hx | xx.i[1] | xx.i[2] | xx.i[3]) == 0) 51 return; 52 53 /* normalize x */ 54 while (hx == 0 && xx.i[1] < 0x10000) { 55 hx = xx.i[1]; 56 xx.i[1] = xx.i[2]; 57 xx.i[2] = xx.i[3]; 58 xx.i[3] = 0; 59 n -= 32; 60 } 61 while (hx < 0x10000) { 62 hx = (hx << 1) | (xx.i[1] >> 31); 63 xx.i[1] = (xx.i[1] << 1) | (xx.i[2] >> 31); 64 xx.i[2] = (xx.i[2] << 1) | (xx.i[3] >> 31); 65 xx.i[3] <<= 1; 66 n--; 67 } 68 xx.i[0] = hx | (xx.i[0] & 0x80000000); 69 } 70 71 if ((hx >> 16) + n < 1) { 72 /* for subnormal result, just deliver zero */ 73 xx.i[0] = xx.i[0] & 0x80000000; 74 xx.i[1] = xx.i[2] = xx.i[3] = 0; 75 } else 76 xx.i[0] += (n << 16); 77 *x = xx.q; 78 } 79 80 static const union { 81 int i[4]; 82 long double q; 83 } consts[2] = { 84 { 0x7ffe0000, 0, 0, 0 }, 85 { 0x00010000, 0, 0, 0 } 86 }; 87 88 /* 89 * _Q_scle(x, n) sets *x = *x * 2^n, raising overflow or underflow 90 * as appropriate. 91 * 92 * This routine tacitly assumes the argument is either zero or normal. 93 */ 94 void 95 _Q_scle(long double *x, int n) 96 { 97 union { 98 unsigned int i[4]; 99 long double q; 100 } xx; 101 int hx; 102 103 xx.q = *x; 104 hx = (xx.i[0] >> 16) & 0x7fff; 105 106 if (hx == 0) /* x must be zero */ 107 return; 108 109 hx += n; 110 if (hx >= 0x7fff) { /* overflow */ 111 xx.i[0] = 0x7ffe0000 | (xx.i[0] & 0x80000000); 112 xx.i[1] = xx.i[2] = xx.i[3] = 0; 113 xx.q *= consts[0].q; 114 } else if (hx < 1) { /* possible underflow */ 115 if (hx < -112) { 116 xx.i[0] = 0x00010000 | (xx.i[0] & 0x80000000); 117 xx.i[1] = xx.i[2] = xx.i[3] = 0; 118 } else { 119 xx.i[0] = (0x3ffe0000 + (hx << 16)) | 120 (xx.i[0] & 0x8000ffff); 121 } 122 xx.q *= consts[1].q; 123 } else 124 xx.i[0] += (n << 16); 125 126 *x = xx.q; 127 } 128