xref: /openbsd-src/lib/libc/gen/ldexp.c (revision af3276d5e32f3e939032c022c530ad02a9ed9a1e)
1*af3276d5Sguenther /*	$OpenBSD: ldexp.c,v 1.10 2015/10/27 05:54:49 guenther Exp $	*/
2af87a20cSmartynas /* @(#)s_scalbn.c 5.1 93/09/24 */
3af87a20cSmartynas /* @(#)fdlibm.h 5.1 93/09/24 */
4af87a20cSmartynas /*
5af87a20cSmartynas  * ====================================================
6af87a20cSmartynas  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
7af87a20cSmartynas  *
8af87a20cSmartynas  * Developed at SunPro, a Sun Microsystems, Inc. business.
9af87a20cSmartynas  * Permission to use, copy, modify, and distribute this
10af87a20cSmartynas  * software is freely granted, provided that this notice
11af87a20cSmartynas  * is preserved.
12af87a20cSmartynas  * ====================================================
13af87a20cSmartynas  */
14af87a20cSmartynas 
15af87a20cSmartynas #include <sys/types.h>
16be9b7050Sguenther #include <endian.h>
17af87a20cSmartynas #include <float.h>
18af87a20cSmartynas #include <math.h>
19af87a20cSmartynas 
20af87a20cSmartynas /* Bit fiddling routines copied from msun/src/math_private.h,v 1.15 */
21af87a20cSmartynas 
22016765a7Smartynas #if (BYTE_ORDER == BIG_ENDIAN) || (defined(__arm__) && !defined(__VFP_FP__))
23af87a20cSmartynas 
24af87a20cSmartynas typedef union
25af87a20cSmartynas {
26af87a20cSmartynas   double value;
27af87a20cSmartynas   struct
28af87a20cSmartynas   {
29af87a20cSmartynas     u_int32_t msw;
30af87a20cSmartynas     u_int32_t lsw;
31af87a20cSmartynas   } parts;
32af87a20cSmartynas } ieee_double_shape_type;
33af87a20cSmartynas 
34af87a20cSmartynas #endif
35af87a20cSmartynas 
36016765a7Smartynas #if (BYTE_ORDER == LITTLE_ENDIAN) && !(defined(__arm__) && !defined(__VFP_FP__))
37af87a20cSmartynas 
38af87a20cSmartynas typedef union
39af87a20cSmartynas {
40af87a20cSmartynas   double value;
41af87a20cSmartynas   struct
42af87a20cSmartynas   {
43af87a20cSmartynas     u_int32_t lsw;
44af87a20cSmartynas     u_int32_t msw;
45af87a20cSmartynas   } parts;
46af87a20cSmartynas } ieee_double_shape_type;
47af87a20cSmartynas 
48af87a20cSmartynas #endif
49af87a20cSmartynas 
50af87a20cSmartynas /* Get two 32 bit ints from a double.  */
51af87a20cSmartynas 
52af87a20cSmartynas #define EXTRACT_WORDS(ix0,ix1,d)				\
53af87a20cSmartynas do {								\
54af87a20cSmartynas   ieee_double_shape_type ew_u;					\
55af87a20cSmartynas   ew_u.value = (d);						\
56af87a20cSmartynas   (ix0) = ew_u.parts.msw;					\
57af87a20cSmartynas   (ix1) = ew_u.parts.lsw;					\
58af87a20cSmartynas } while (0)
59af87a20cSmartynas 
60af87a20cSmartynas /* Get the more significant 32 bit int from a double.  */
61af87a20cSmartynas 
62af87a20cSmartynas #define GET_HIGH_WORD(i,d)					\
63af87a20cSmartynas do {								\
64af87a20cSmartynas   ieee_double_shape_type gh_u;					\
65af87a20cSmartynas   gh_u.value = (d);						\
66af87a20cSmartynas   (i) = gh_u.parts.msw;						\
67af87a20cSmartynas } while (0)
68af87a20cSmartynas 
69af87a20cSmartynas /* Set the more significant 32 bits of a double from an int.  */
70af87a20cSmartynas 
71af87a20cSmartynas #define SET_HIGH_WORD(d,v)					\
72af87a20cSmartynas do {								\
73af87a20cSmartynas   ieee_double_shape_type sh_u;					\
74af87a20cSmartynas   sh_u.value = (d);						\
75af87a20cSmartynas   sh_u.parts.msw = (v);						\
76af87a20cSmartynas   (d) = sh_u.value;						\
77af87a20cSmartynas } while (0)
78af87a20cSmartynas 
79af87a20cSmartynas 
80af87a20cSmartynas static const double
81af87a20cSmartynas two54   =  1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
82af87a20cSmartynas twom54  =  5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
83af87a20cSmartynas huge   = 1.0e+300,
84af87a20cSmartynas tiny   = 1.0e-300;
85af87a20cSmartynas 
86af87a20cSmartynas static double
_copysign(double x,double y)87af87a20cSmartynas _copysign(double x, double y)
88af87a20cSmartynas {
89af87a20cSmartynas 	u_int32_t hx,hy;
90af87a20cSmartynas 	GET_HIGH_WORD(hx,x);
91af87a20cSmartynas 	GET_HIGH_WORD(hy,y);
92af87a20cSmartynas 	SET_HIGH_WORD(x,(hx&0x7fffffff)|(hy&0x80000000));
93af87a20cSmartynas 	return x;
94af87a20cSmartynas }
95af87a20cSmartynas 
96af87a20cSmartynas double
ldexp(double x,int n)97af87a20cSmartynas ldexp(double x, int n)
98af87a20cSmartynas {
99af87a20cSmartynas 	int32_t k,hx,lx;
100af87a20cSmartynas 	EXTRACT_WORDS(hx,lx,x);
101af87a20cSmartynas         k = (hx&0x7ff00000)>>20;		/* extract exponent */
102af87a20cSmartynas         if (k==0) {				/* 0 or subnormal x */
103af87a20cSmartynas             if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */
104af87a20cSmartynas 	    x *= two54;
105af87a20cSmartynas 	    GET_HIGH_WORD(hx,x);
106af87a20cSmartynas 	    k = ((hx&0x7ff00000)>>20) - 54;
107af87a20cSmartynas             if (n< -50000) return tiny*x; 	/*underflow*/
108af87a20cSmartynas 	    }
109af87a20cSmartynas         if (k==0x7ff) return x+x;		/* NaN or Inf */
110af87a20cSmartynas         k = k+n;
111af87a20cSmartynas         if (k >  0x7fe) return huge*_copysign(huge,x); /* overflow  */
112af87a20cSmartynas         if (k > 0) 				/* normal result */
113af87a20cSmartynas 	    {SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); return x;}
114af87a20cSmartynas         if (k <= -54) {
115af87a20cSmartynas             if (n > 50000) 	/* in case integer overflow in n+k */
116af87a20cSmartynas 		return huge*_copysign(huge,x);	/*overflow*/
117af87a20cSmartynas 	    else return tiny*_copysign(tiny,x); 	/*underflow*/
118af87a20cSmartynas 	}
119af87a20cSmartynas         k += 54;				/* subnormal result */
120af87a20cSmartynas 	SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20));
121af87a20cSmartynas         return x*twom54;
122af87a20cSmartynas }
123*af3276d5Sguenther DEF_STRONG(ldexp);
124af87a20cSmartynas 
12538ffb667Sespie #if	LDBL_MANT_DIG == DBL_MANT_DIG
1262fbf033eSmartynas __strong_alias(ldexpl, ldexp);
12738ffb667Sespie #endif	/* LDBL_MANT_DIG == DBL_MANT_DIG */
128