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