/*        $NetBSD$  */

/*
 * Copyright (c) 1995  Ken Nakata
 *        All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the author nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *        @(#)fpu_exp.c       10/24/95
 */

#include "fpu_emul.h"

/*
 * fpu_exp.c: defines fpu_etox(), fpu_etoxm1(), fpu_tentox(), and fpu_twotox();
 */
 
void fpu_calc_expr( struct fpemu *fe, struct fpn *fact1, struct fpn *fact2, int ADJFACT );

static struct expstruct {
	u_int word1,word2,word3,word4,word5,word6;
	} exptbl[] = {
	{  0x3FFF0000,0x80000000,0x00000000,0x3F730000,0x80000000, 0 },
	{  0x3FFF0000,0x8164D1F3,0xBC030773,0x3FBE0000,0xF7CA0000, 0 },
	{  0x3FFF0000,0x82CD8698,0xAC2BA1D7,0x3FBD0000,0xF8A90000, 0 },
	{  0x3FFF0000,0x843A28C3,0xACDE4046,0x3FBC0000,0xD7C90000, 0 },
	{  0x3FFF0000,0x85AAC367,0xCC487B15,0xBFBD0000,0xE8DA0000, 0 },
	{  0x3FFF0000,0x871F6196,0x9E8D1010,0x3FBD0000,0xE85C0000, 0 },
	{  0x3FFF0000,0x88980E80,0x92DA8527,0x3FBE0000,0xBBF10000, 0 },
	{  0x3FFF0000,0x8A14D575,0x496EFD9A,0x3FBB0000,0x80CA0000, 0 },
	{  0x3FFF0000,0x8B95C1E3,0xEA8BD6E7,0xBFBA0000,0x83730000, 0 },
	{  0x3FFF0000,0x8D1ADF5B,0x7E5BA9E6,0xBFBE0000,0x96700000, 0 },
	{  0x3FFF0000,0x8EA4398B,0x45CD53C0,0x3FBD0000,0xB7000000, 0 },
	{  0x3FFF0000,0x9031DC43,0x1466B1DC,0x3FBE0000,0xEEB00000, 0 },
	{  0x3FFF0000,0x91C3D373,0xAB11C336,0x3FBB0000,0xFD6D0000, 0 },
	{  0x3FFF0000,0x935A2B2F,0x13E6E92C,0xBFBD0000,0xB3190000, 0 },
	{  0x3FFF0000,0x94F4EFA8,0xFEF70961,0x3FBD0000,0xBA2B0000, 0 },
	{  0x3FFF0000,0x96942D37,0x20185A00,0x3FBE0000,0x91D50000, 0 },
	{  0x3FFF0000,0x9837F051,0x8DB8A96F,0x3FBE0000,0x8D5A0000, 0 },
	{  0x3FFF0000,0x99E04593,0x20B7FA65,0xBFBC0000,0xDE7B0000, 0 },
	{  0x3FFF0000,0x9B8D39B9,0xD54E5539,0xBFBE0000,0xBAAF0000, 0 },
	{  0x3FFF0000,0x9D3ED9A7,0x2CFFB751,0xBFBD0000,0x86DA0000, 0 },
	{  0x3FFF0000,0x9EF53260,0x91A111AE,0xBFBE0000,0xBEDD0000, 0 },
	{  0x3FFF0000,0xA0B0510F,0xB9714FC2,0x3FBC0000,0xC96E0000, 0 },
	{  0x3FFF0000,0xA2704303,0x0C496819,0xBFBE0000,0xC90B0000, 0 },
	{  0x3FFF0000,0xA43515AE,0x09E6809E,0x3FBB0000,0xD1DB0000, 0 },
	{  0x3FFF0000,0xA5FED6A9,0xB15138EA,0x3FBC0000,0xE5EB0000, 0 },
	{  0x3FFF0000,0xA7CD93B4,0xE965356A,0xBFBE0000,0xC2740000, 0 },
	{  0x3FFF0000,0xA9A15AB4,0xEA7C0EF8,0x3FBE0000,0xA83C0000, 0 },
	{  0x3FFF0000,0xAB7A39B5,0xA93ED337,0x3FBE0000,0xCB000000, 0 },
	{  0x3FFF0000,0xAD583EEA,0x42A14AC6,0x3FBE0000,0x93010000, 0 },
	{  0x3FFF0000,0xAF3B78AD,0x690A4375,0xBFBD0000,0x83670000, 0 },
	{  0x3FFF0000,0xB123F581,0xD2AC2590,0xBFBE0000,0xF05F0000, 0 },
	{  0x3FFF0000,0xB311C412,0xA9112489,0x3FBD0000,0xFB3C0000, 0 },
	{  0x3FFF0000,0xB504F333,0xF9DE6484,0x3FBE0000,0xB2FB0000, 0 },
	{  0x3FFF0000,0xB6FD91E3,0x28D17791,0x3FBA0000,0xE2CB0000, 0 },
	{  0x3FFF0000,0xB8FBAF47,0x62FB9EE9,0x3FBC0000,0xDC3C0000, 0 },
	{  0x3FFF0000,0xBAFF5AB2,0x133E45FB,0x3FBE0000,0xE9AA0000, 0 },
	{  0x3FFF0000,0xBD08A39F,0x580C36BF,0xBFBE0000,0xAEFD0000, 0 },
	{  0x3FFF0000,0xBF1799B6,0x7A731083,0xBFBC0000,0xBF510000, 0 },
	{  0x3FFF0000,0xC12C4CCA,0x66709456,0x3FBE0000,0xF88A0000, 0 },
	{  0x3FFF0000,0xC346CCDA,0x24976407,0x3FBD0000,0x83B20000, 0 },
	{  0x3FFF0000,0xC5672A11,0x5506DADD,0x3FBD0000,0xF8AB0000, 0 },
	{  0x3FFF0000,0xC78D74C8,0xABB9B15D,0xBFBD0000,0xFB170000, 0 },
	{  0x3FFF0000,0xC9B9BD86,0x6E2F27A3,0xBFBE0000,0xFE3C0000, 0 },
	{  0x3FFF0000,0xCBEC14FE,0xF2727C5D,0xBFBB0000,0xB6F80000, 0 },
	{  0x3FFF0000,0xCE248C15,0x1F8480E4,0xBFBC0000,0xEE530000, 0 },
	{  0x3FFF0000,0xD06333DA,0xEF2B2595,0xBFBD0000,0xA4AE0000, 0 },
	{  0x3FFF0000,0xD2A81D91,0xF12AE45A,0x3FBC0000,0x91240000, 0 },
	{  0x3FFF0000,0xD4F35AAB,0xCFEDFA1F,0x3FBE0000,0xB2430000, 0 },
	{  0x3FFF0000,0xD744FCCA,0xD69D6AF4,0x3FBD0000,0xE69A0000, 0 },
	{  0x3FFF0000,0xD99D15C2,0x78AFD7B6,0xBFB80000,0xBC610000, 0 },
	{  0x3FFF0000,0xDBFBB797,0xDAF23755,0x3FBD0000,0xF6100000, 0 },
	{  0x3FFF0000,0xDE60F482,0x5E0E9124,0xBFBD0000,0x8BE10000, 0 },
	{  0x3FFF0000,0xE0CCDEEC,0x2A94E111,0x3FBA0000,0xCB120000, 0 },
	{  0x3FFF0000,0xE33F8972,0xBE8A5A51,0x3FBB0000,0x9BFE0000, 0 },
	{  0x3FFF0000,0xE5B906E7,0x7C8348A8,0x3FBC0000,0xF2F40000, 0 },
	{  0x3FFF0000,0xE8396A50,0x3C4BDC68,0x3FBE0000,0xF22F0000, 0 },
	{  0x3FFF0000,0xEAC0C6E7,0xDD24392F,0xBFBD0000,0xBF4A0000, 0 },
	{  0x3FFF0000,0xED4F301E,0xD9942B84,0x3FBE0000,0xC01A0000, 0 },
	{  0x3FFF0000,0xEFE4B99B,0xDCDAF5CB,0x3FBE0000,0x8CAC0000, 0 },
	{  0x3FFF0000,0xF281773C,0x59FFB13A,0xBFBC0000,0xBB3F0000, 0 },
	{  0x3FFF0000,0xF5257D15,0x2486CC2C,0x3FBE0000,0xF73A0000, 0 },
	{  0x3FFF0000,0xF7D0DF73,0x0AD13BB9,0xBFB80000,0xB7950000, 0 },
	{  0x3FFF0000,0xFA83B2DB,0x722A033A,0x3FBE0000,0xF84B0000, 0 },
	{  0x3FFF0000,0xFD3E0C0C,0xF486C175,0xBFBE0000,0xF5810000, 0 }
};                                                

static u_int CONST_64[] = { 0x42800000 };
static u_int CONST_INV64[] = { 0x3C800000 };
static u_int CONST_LOG2[] = { 0x3FFE0000, 0xB17217F7, 0xD1CF79AC };
static u_int CONST_LOG10[] = { 0x40000000, 0x935d8ddd, 0xAAA8AC17 };

static u_int L2TEN64[] = { 0x406a934f, 0x0979a371 };
static u_int L10TWO1[] = { 0x3f734413, 0x509f8000 };
static u_int L10TWO2[] = { 0xbfcd0000, 0xc0219dc1, 0xda994fd2 };

static u_int DIV64LOG2[] = { 0x42b8aa3b };
static u_int LOG2DIV64_1[] = { 0xbc317218 };
static u_int LOG2DIV64_2[] = { 0x3fdc0000, 0x82e30865, 0x4361c4c6 };

static u_int EXPA5[]={ 0x3F56C16D,0x6F7BD0B2 };
static u_int EXPA4[]={ 0x3F811112,0x302C712C };
static u_int EXPA3[]={ 0x3FA55555,0x55554CC1 };
static u_int EXPA2[]={ 0x3FC55555,0x55554A54 };
static u_int EXPA1[]={ 0x3FE00000,0x00000000 };

struct fpn *fpu_calc_twotox(struct fpemu *);
struct fpn *fpu_calc_tentox(struct fpemu *);
struct fpn *fpu_calc_etox(struct fpemu *);

struct fpn *
fpu_calc_etox(fe)
     struct fpemu *fe;
{

	struct fpn *d;
	struct fpn X,fact1,fact2;
	int N,L,M2,M;
	
	
	CPYFPN(&X, &fe->fe_f2);
	fpu_explode(fe, &fe->fe_f1, FTYPE_SNG, DIV64LOG2);
	
	d=fpu_mul(fe);
	fpu_implode(fe, d, FTYPE_LNG, &N);
	
	
	L=N >> 6;
	M= L>>1;
	M2=L-M;
	
	
	
	fpu_explode(fe, &fe->fe_f1, FTYPE_LNG, &N);
	fpu_explode(fe, &fe->fe_f2, FTYPE_SNG, LOG2DIV64_1);
	 
	d=fpu_mul(fe);
	CPYFPN(&fe->fe_f2, d);
	  
	CPYFPN(&fe->fe_f1, &X);	
	d=fpu_add(fe);
	CPYFPN(&X, d);


	fpu_explode(fe, &fe->fe_f1, FTYPE_LNG, &N);
	fpu_explode(fe, &fe->fe_f2, FTYPE_EXT, LOG2DIV64_2);
	 
	d=fpu_mul(fe);
	CPYFPN(&fe->fe_f2, d);	
	fe->fe_f2.fp_sign= ! fe->fe_f2.fp_sign;  
	CPYFPN(&fe->fe_f1, &X);
	
	d=fpu_add(fe);

	
	CPYFPN(&fe->fe_f2, d);
	
	
        fpu_explode(fe, &fact1, FTYPE_EXT, &exptbl[N & 0x3f].word1);
        fpu_explode(fe, &fact2, FTYPE_EXT, &exptbl[N & 0x3f].word4);
        
        fact1.fp_exp+=M;
        fact2.fp_exp+=M;
        
        fpu_calc_expr(fe, &fact1, &fact2, M2);
	
	
  	return &fe->fe_f2;
  /* stub */
  return &fe->fe_f2;
}

struct fpn *
fpu_etoxm1(fe)
     struct fpemu *fe;
{
    struct fpn *d;
    
  
  	d=fpu_etox(fe);
  	CPYFPN(&fe->fe_f1, d);
  	if(fe->fe_f2.fp_class == FPC_NUM || fe->fe_f2.fp_class == FPC_ZERO ) {
  	
  		fpu_const(&fe->fe_f2, 0x32);
  		fe->fe_f2.fp_sign= 1;
  		d=fpu_add(fe);
  		CPYFPN(&fe->fe_f2, d);
  	};  
  
  return &fe->fe_f2;
}

struct fpn *
fpu_calc_tentox(fe)
     struct fpemu *fe;
{

	struct fpn *d;
	struct fpn X,fact1,fact2;
	int N,L,M2,M;
	
	
	CPYFPN(&X, &fe->fe_f2);
	fpu_explode(fe, &fe->fe_f1, FTYPE_DBL, L2TEN64);
	
	d=fpu_mul(fe);
	fpu_implode(fe, d, FTYPE_LNG, &N);
	
	
	L=N >> 6;
	M= L>>1;
	M2=L-M;
	
	
	
	fpu_explode(fe, &fe->fe_f1, FTYPE_LNG, &N);
	fpu_explode(fe, &fe->fe_f2, FTYPE_DBL, L10TWO1);
	 
	d=fpu_mul(fe);
	CPYFPN(&fe->fe_f2, d);
	
	fe->fe_f2.fp_sign= ! fe->fe_f2.fp_sign;  
	CPYFPN(&fe->fe_f1, &X);	
	d=fpu_add(fe);
	CPYFPN(&X, d);


	fpu_explode(fe, &fe->fe_f1, FTYPE_LNG, &N);
	fpu_explode(fe, &fe->fe_f2, FTYPE_EXT, L10TWO2);
	 
	d=fpu_mul(fe);
	CPYFPN(&fe->fe_f2, d);	
	fe->fe_f2.fp_sign= ! fe->fe_f2.fp_sign;  
	CPYFPN(&fe->fe_f1, &X);
	
	d=fpu_add(fe);
	CPYFPN(&fe->fe_f2, d);
	fpu_explode(fe,&fe->fe_f1, FTYPE_EXT, CONST_LOG10);
	d=fpu_mul(fe);
	
	CPYFPN(&fe->fe_f2, d);
	
	
        fpu_explode(fe, &fact1, FTYPE_EXT, &exptbl[N & 0x3f].word1);
        fpu_explode(fe, &fact2, FTYPE_EXT, &exptbl[N & 0x3f].word4);
        
        fact1.fp_exp+=M;
        fact2.fp_exp+=M;
        
        fpu_calc_expr(fe, &fact1, &fact2, M2);
	
	
  	return &fe->fe_f2;

}


struct fpn *
fpu_calc_twotox(fe)
     struct fpemu *fe;
{
	struct fpn *d;
	struct fpn X,fact1,fact2;
	int N,L,M2,M;
	
	
	CPYFPN(&X, &fe->fe_f2);
	fpu_explode(fe, &fe->fe_f1, FTYPE_SNG, CONST_64);
	
	d=fpu_mul(fe);
	fpu_implode(fe, d, FTYPE_LNG, &N);
	/* now N=offset of 2**j/64 */
	
	L=N >> 6;
	M= L>>1;
	M2=L-M;
	
	
	
	fpu_explode(fe, &fe->fe_f1, FTYPE_LNG, &N);
	fpu_explode(fe, &fe->fe_f2, FTYPE_SNG, CONST_INV64);
	 
	d=fpu_mul(fe);
	CPYFPN(&fe->fe_f2, d);
	
	fe->fe_f2.fp_sign= ! fe->fe_f2.fp_sign;  
	CPYFPN(&fe->fe_f1, &X);
	
	d=fpu_add(fe);
	CPYFPN(&fe->fe_f2, d);
	fpu_explode(fe,&fe->fe_f1, FTYPE_EXT, CONST_LOG2);
	d=fpu_mul(fe);
	
	CPYFPN(&fe->fe_f2, d);
	
	
        fpu_explode(fe, &fact1, FTYPE_EXT, &exptbl[N & 0x3f].word1);
        fpu_explode(fe, &fact2, FTYPE_EXT, &exptbl[N & 0x3f].word4);
        
        fact1.fp_exp+=M;
        fact2.fp_exp+=M;
        
        fpu_calc_expr(fe, &fact1, &fact2, M2);
	
	
  	return &fe->fe_f2;
}
void fpu_calc_expr( struct fpemu *fe, struct fpn *fact1, struct fpn *fact2, int ADJFACT )
{
	
        struct fpn R,S,fp2,fp3;
        struct fpn *d;
        
        
        CPYFPN(&R, &fe->fe_f2);
        CPYFPN(&fe->fe_f1, &R);
        d=fpu_mul(fe);
        CPYFPN(&S, d);
        
        
        fpu_explode(fe, &fp2, FTYPE_DBL, EXPA5);
        fpu_explode(fe, &fp3, FTYPE_DBL, EXPA4);
        
        CPYFPN(&fe->fe_f2, &fp2 );
        CPYFPN(&fe->fe_f1, &S );
        d=fpu_mul(fe);
        CPYFPN(&fp2, d);
        
        CPYFPN(&fe->fe_f2, &fp3 );
        CPYFPN(&fe->fe_f1, &S );
        d=fpu_mul(fe);
        CPYFPN(&fp3, d);
        
        CPYFPN(&fe->fe_f2, &fp2 );
        fpu_explode(fe, &fe->fe_f1, FTYPE_DBL, EXPA3 );
        d=fpu_add(fe);
        CPYFPN(&fp2, d);
        
        CPYFPN(&fe->fe_f2, &fp3 );
        fpu_explode(fe, &fe->fe_f1, FTYPE_DBL, EXPA2 );
        d=fpu_add(fe);
        CPYFPN(&fp3, d);
        
        CPYFPN(&fe->fe_f2, &fp2 );
        CPYFPN(&fe->fe_f1, &S );
        d=fpu_mul(fe);
        CPYFPN(&fp2, d);
       
       
        CPYFPN(&fe->fe_f2, &fp3 );
        CPYFPN(&fe->fe_f1, &S );
        d=fpu_mul(fe);
        CPYFPN(&fp3, d);
        
        CPYFPN(&fe->fe_f2, &fp2 );
        fpu_explode(fe, &fe->fe_f1, FTYPE_DBL, EXPA1 );
        d=fpu_add(fe);
        CPYFPN(&fp2, d);
        
        CPYFPN(&fe->fe_f2, &fp3 );
        CPYFPN(&fe->fe_f1, &R );
        d=fpu_mul(fe);
        CPYFPN(&fp3, d);
        
        
        CPYFPN(&fe->fe_f2, &fp2 );
        CPYFPN(&fe->fe_f1, &S );
        d=fpu_mul(fe);
        CPYFPN(&fp2, d);
        
        
        CPYFPN(&fe->fe_f2, &fp3 );
        CPYFPN(&fe->fe_f1, &R );
        d=fpu_add(fe);
        CPYFPN(&fe->fe_f2, d);
        CPYFPN(&fe->fe_f1, &fp2 );
        d=fpu_add(fe);
        
        CPYFPN(&fe->fe_f1, d);
        CPYFPN(&fe->fe_f2, fact1);
        d=fpu_mul(fe);
        
        CPYFPN(&fe->fe_f1, d);
        CPYFPN(&fe->fe_f2, fact2);
        d=fpu_add(fe);
        
        CPYFPN(&fe->fe_f1, d);
        CPYFPN(&fe->fe_f2, fact1);
        d=fpu_add(fe);
        
        CPYFPN(&fe->fe_f2, d);
        
        fe->fe_f2.fp_exp+=ADJFACT;        
        
        
         
	
}
struct fpn *fpu_tentox(struct fpemu *fe)
{
 
   	u_int fpsr;
        struct fpn *fp= &fe->fe_f2;
     
        struct fpn *d;
        
        fpsr=fe->fe_fpsr&~FPSR_EXCP;
        
        if(fp->fp_class== FPC_NUM ) {
        	if(fp->fp_exp <= -70) {
        		/* this is wrong in FPSP should be 1+ln10*x */
        		
        		fpu_explode(fe, &fe->fe_f1, FTYPE_EXT, CONST_LOG10 );
        		d=fpu_mul(fe);
        		CPYFPN(&fe->fe_f1, d); 
        		fpu_const(&fe->fe_f2, 0x32);
        		d=fpu_add(fe);
        		CPYFPN(&fe->fe_f2,d);
        			
        	} else {	 	 
  			fp=fpu_calc_tentox(fe);
                };
        } else if(fp->fp_class == FPC_ZERO) {
        	
        	fpu_const(&fe->fe_f2,0x32);
        	
        
        
        } else if(fp->fp_class == FPC_INF) {
        	if(fp->fp_sign) {
        		fp->fp_class = FPC_ZERO;
        		fp->fp_mant[0]=fp->fp_mant[1]=fp->fp_mant[2]=fp->fp_mant[3]=0;
        		fp->fp_sign=0;
        		};
        
        } else if(fp->fp_class == FPC_SNAN) {
        
         	fpsr|=FPSR_SNAN;
         	fp=fpu_newnan(fe);
         	
        } else {
         	fp=fpu_newnan(fe);
        }
        
        fe->fe_fpsr =  fpsr;
        return fp;

}
struct fpn *fpu_etox(struct fpemu *fe)
{
 
   	u_int fpsr;
        struct fpn *fp= &fe->fe_f2;
      
        struct fpn *d;
        
        fpsr=fe->fe_fpsr&~FPSR_EXCP;
        
        if(fp->fp_class== FPC_NUM ) {
        	if(fp->fp_exp <= -70) {
        		
        		fpu_const(&fe->fe_f1, 0x32);
        		d=fpu_add(fe);
        		CPYFPN(&fe->fe_f2,d);
        			
        	} else {	 	 
  			fp=fpu_calc_etox(fe);
                };
        } else if(fp->fp_class == FPC_ZERO) {
        	
        	fpu_const(&fe->fe_f2,0x32);
        	
        
        
        } else if(fp->fp_class == FPC_INF) {
        	if(fp->fp_sign) {
        		fp->fp_class = FPC_ZERO;
        		fp->fp_mant[0]=fp->fp_mant[1]=fp->fp_mant[2]=fp->fp_mant[3]=0;
        		fp->fp_sign=0;
        		};
        
        } else if(fp->fp_class == FPC_SNAN) {
        
         	fpsr|=FPSR_SNAN;
         	fp=fpu_newnan(fe);
         	
        } else {
         	fp=fpu_newnan(fe);
        }
        
        fe->fe_fpsr =  fpsr;
        return fp;

}
struct fpn *fpu_twotox(struct fpemu *fe)
{
 
   	u_int fpsr;
        struct fpn *fp= &fe->fe_f2;
      
        struct fpn *d;
        
        fpsr=fe->fe_fpsr&~FPSR_EXCP;
        
        if(fp->fp_class == FPC_NUM ) {
        	if(fp->fp_exp <= -70) {
        		/* this is wrong in FPSP should be 1+ln2*x */
        		
        		fpu_explode(fe, &fe->fe_f1, FTYPE_EXT, CONST_LOG2 );
        		d=fpu_mul(fe);
        		CPYFPN(&fe->fe_f1, d); 
        		fpu_const(&fe->fe_f2, 0x32);
        		d=fpu_add(fe);
        		CPYFPN(&fe->fe_f2,d);
        			
        	} else {	 	 
  			fp=fpu_calc_twotox(fe);
                };
                
        } else if(fp->fp_class == FPC_ZERO) {
        	
        	fpu_const(&fe->fe_f2, 0x32);
        	
        
        } else if(fp->fp_class == FPC_INF) {
        	if(fp->fp_sign) {
        		fp->fp_class = FPC_ZERO;
        		fp->fp_mant[0]=fp->fp_mant[1]=fp->fp_mant[2]=fp->fp_mant[3]=0;
        		fp->fp_sign=0;
                };
        } else if(fp->fp_class == FPC_SNAN) {
        
         	fpsr|=FPSR_SNAN;
         	fp=fpu_newnan(fe);
         	
        } else {
         	fp=fpu_newnan(fe);
        };
        
        fe->fe_fpsr =  fpsr;
        return fp;
}
