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 (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 /*
  27  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  28  * Use is subject to license terms.
  29  */
  30 
  31 #pragma weak __scalbn = scalbn
  32 
  33 #include "libm.h"
  34 
  35 static const double one = 1.0,
  36         huge = 1.0e300,
  37         tiny = 1.0e-300,
  38         twom54 = 5.5511151231257827021181583404541015625e-17;
  39 
  40 #if defined(__x86)
  41 static const double two52 = 4503599627370496.0;
  42 #else
  43 /*
  44  * Normalize non-zero subnormal x and return biased exponent of x in [-51,0]
  45  */
  46 static int
  47 ilogb_biased(unsigned *px)
  48 {
  49         int s = 52;
  50         unsigned v = px[HIWORD] & ~0x80000000, w = px[LOWORD], t = v;
  51 
  52         if (t)
  53                 s -= 32;
  54         else
  55                 t = w;
  56 
  57         if (t & 0xffff0000)
  58                 s -= 16, t >>= 16;
  59 
  60         if (t & 0xff00)
  61                 s -= 8, t >>= 8;
  62 
  63         if (t & 0xf0)
  64                 s -= 4, t >>= 4;
  65 
  66         t <<= 1;
  67         s -= (0xffffaa50 >> t) & 0x3;
  68 
  69         if (s < 32) {
  70                 v = (v << s) | w >> (32 - s);
  71                 w <<= s;
  72         } else {
  73                 v = w << (s - 32);
  74                 w = 0;
  75         }
  76 
  77         px[HIWORD] = (px[HIWORD] & 0x80000000) | v;
  78         px[LOWORD] = w;
  79         return (1 - s);
  80 }
  81 #endif /* defined(__x86) */
  82 
  83 double
  84 scalbn(double x, int n)
  85 {
  86         int *px, ix, hx, k;
  87 
  88         px = (int *)&x;
  89         ix = px[HIWORD];
  90         hx = ix & ~0x80000000;
  91         k = hx >> 20;
  92 
  93         if (k == 0x7ff)                 /* x is inf or NaN */
  94                 return (x * one);
  95 
  96         if (k == 0) {
  97                 if ((hx | px[LOWORD]) == 0 || n == 0)
  98                         return (x);
  99 
 100 #if defined(__x86)
 101                 x *= two52;
 102                 ix = px[HIWORD];
 103                 k = ((ix & ~0x80000000) >> 20) - 52;
 104 #else
 105                 k = ilogb_biased((unsigned *)px);
 106                 ix = px[HIWORD];
 107 #endif
 108                 /* now k is in the range -51..0 */
 109                 k += n;
 110 
 111                 if (k > n)           /* integer overflow occurred */
 112                         k = -100;
 113         } else {
 114                 /* k is in the range 1..1023 */
 115                 k += n;
 116 
 117                 if (k < n)           /* integer overflow occurred */
 118                         k = 0x7ff;
 119         }
 120 
 121         if (k > 0x7fe)
 122                 return (huge * ((ix < 0) ? -huge : huge));
 123 
 124         if (k < 1) {
 125                 if (k <= -54)
 126                         return (tiny * ((ix < 0) ? -tiny : tiny));
 127 
 128                 k += 54;
 129                 px[HIWORD] = (ix & ~0x7ff00000) | (k << 20);
 130                 return (x * twom54);
 131         }
 132 
 133         px[HIWORD] = (ix & ~0x7ff00000) | (k << 20);
 134         return (x);
 135 }