POK
scalbn.c
1 /*
2  * POK header
3  *
4  * The following file is a part of the POK project. Any modification should
5  * made according to the POK licence. You CANNOT use this file or a part of
6  * this file is this part of a file for your own project
7  *
8  * For more information on the POK licence, please see our LICENCE FILE
9  *
10  * Please follow the coding guidelines described in doc/CODING_GUIDELINES
11  *
12  * Copyright (c) 2007-2009 POK team
13  *
14  * Created by julien on Fri Jan 30 14:41:34 2009
15  */
16 
17 /* @(#)s_scalbn.c 5.1 93/09/24 */
18 /*
19  * ====================================================
20  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
21  *
22  * Developed at SunPro, a Sun Microsystems, Inc. business.
23  * Permission to use, copy, modify, and distribute this
24  * software is freely granted, provided that this notice
25  * is preserved.
26  * ====================================================
27  */
28 
29 #ifdef POK_NEEDS_LIBMATH
30 
31 /*
32  * scalbn (double x, int n)
33  * scalbn(x,n) returns x* 2**n computed by exponent
34  * manipulation rather than by actually performing an
35  * exponentiation or a multiplication.
36  */
37 
38 #include <libm.h>
39 #include "math_private.h"
40 
41 static const double
42 two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
43 twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
44 huge = 1.0e+300,
45 tiny = 1.0e-300;
46 
47 double
48 scalbn(double x, int n)
49 {
50  int32_t k,hx,lx;
51  EXTRACT_WORDS(hx,lx,x);
52  k = ((uint32_t)hx&0x7ff00000)>>20; /* extract exponent */
53  if (k==0) { /* 0 or subnormal x */
54  if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */
55  x *= two54;
56  GET_HIGH_WORD(hx,x);
57  k = (((uint32_t)hx&0x7ff00000)>>20) - 54;
58  if (n< -50000) return tiny*x; /*underflow*/
59  }
60  if (k==0x7ff) return x+x; /* NaN or Inf */
61  k = k+n;
62  if (k > 0x7fe) return huge*copysign(huge,x); /* overflow */
63  if (k > 0) /* normal result */
64  {SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); return x;}
65  if (k <= -54) {
66  if (n > 50000) /* in case integer overflow in n+k */
67  return huge*copysign(huge,x); /*overflow*/
68  else return tiny*copysign(tiny,x); /*underflow*/
69  }
70  k += 54; /* subnormal result */
71  SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20));
72  return x*twom54;
73 }
74 
75 #endif