⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 myfloat.c

📁 纯C写的48位软件模拟浮点运算,可移植 测试版
💻 C
📖 第 1 页 / 共 4 页
字号:
//#include "reg51.h"

// myfloat.cpp : Defines the entry point for the console application.
//
// 自定义32位浮点类型及运算
// 2005.12.25
// 邓彬伟 于黄石理工
////////////////////////////////////////////////////////////////////////
#include "reg52.h"
#include "myfloat.h"
char FLAGOVER;
char FLAGALEB;

 xdata myfloat ft;
int main()
{
 
	xdata U32 lt;
	xdata long i,j;
//	printf( "%d.....",MyfloatToLong(MyfloatDiv( LongToMyfloat( 3), LongToMyfloat( 1 ))));

	  SP= 0x79;
    ft=MyfloatMul( LongToMyfloat( 3), LongToMyfloat( 3 ));
    ft=MyfloatAdd( LongToMyfloat( 4 ) , LongToMyfloat( 3 ));
	ft=MyfloatSub( LongToMyfloat( 454 ) , LongToMyfloat(33));
	ft=MyfloatDiv( LongToMyfloat( 454 ) , LongToMyfloat(33));

	// 例子,32位有符号整数转myfloat
	LongToMyfloat( 0x7fffffff );// 
	LongToMyfloat( 0xffffffff );
	LongToMyfloat( 0 );
	// 例子,32位有符号整数转myfloat
	ShortToMyfloat( (short)0x7fff );// 
	ShortToMyfloat( (short)0xffff);
	ShortToMyfloat( 0 );
	// 例子,myfloat转32位有符号整数
//	printf(" short= %d \n ", (short)0xf432);
//	printf(" long = %d \n ", 	MyfloatToLong(LongToMyfloat( (long)(short)0xf432 ) ) );
	
//		printf(" add = %d  ,long add = %d \n ",0x7fffffff+0x7fffffff, MyfloatToLong(MyfloatAddp( LongToMyfloat( 0x7fffffff ) , LongToMyfloat( 0x7fffffff ))) );

	MyfloatToLong(ShortToMyfloat( (short)-0x7e ) );// 
	// 测试MyfloatSubp()函数
//	printf(" sub = %d  ,long sub = %d \n ",0x7fffffff-0x7fffffff, MyfloatToLong(MyfloatSubp( LongToMyfloat( 0x7fffffff ) , LongToMyfloat( 0x7fffffff ))) );
//	printf(" sub = %d  ,long sub = %d \n ",0x7fffffff-0x7ffffff, MyfloatToLong(MyfloatSubp( LongToMyfloat( 0x7fffffff ) , LongToMyfloat( 0x7ffffff ))) );
//	printf(" sub = %d  ,long sub = %d \n ",0x7fff-0x7ffffff, MyfloatToLong(MyfloatSubp( LongToMyfloat( 0x7fff ) , LongToMyfloat( 0x7ffffff ))) );
//	printf(" sub = %d  ,long sub = %d \n ",0x0-0x7ffffff, MyfloatToLong(MyfloatSubp( LongToMyfloat( 0x0 ) , LongToMyfloat( 0x7ffffff ))) );
//	printf(" sub = %d  ,long sub = %d \n ",0x0-0x0, MyfloatToLong(MyfloatSubp( LongToMyfloat( 0x0 ) , LongToMyfloat( 0x0 ))) );
//	printf(" sub = %d  ,long sub = %d \n ",0x7fffffff-0x0, MyfloatToLong(MyfloatSubp( LongToMyfloat( 0x7fffffff ) , LongToMyfloat( 0x0 ))) );
//	printf(" sub = %d  ,long sub = %d \n ",0x1-0x2, MyfloatToLong(MyfloatSubp( LongToMyfloat( 0x1) , LongToMyfloat( 0x2 ))) );
	// 测试MyfloatAdd()函数

	lt =((S32)0x8fffffff+0x7ffffff);//
//	printf(" adds = %d  ,long add = %d \n ",0x7fffffff-0x7fffffff, MyfloatToLong(MyfloatAdd( LongToMyfloat( 0x7fffffff ) , LongToMyfloat( -0x7fffffff ))) );
//	printf(" adds = %d  ,long add = %d \n ",lt, MyfloatToLong(MyfloatAdd( LongToMyfloat( 0x8fffffff ) , LongToMyfloat( 0x7ffffff ))) );
//	printf(" adds = %d  ,long add = %d \n ",0x7fff+0x7ffffff, MyfloatToLong(MyfloatAdd( LongToMyfloat( 0x7fff ) , LongToMyfloat( 0x7ffffff ))) );
//	printf(" adds = %d  ,long add = %d \n ",0x80123456+0x8fffffff, MyfloatToLong(MyfloatAdd( LongToMyfloat( 0x80123456 ) , LongToMyfloat( 0x8fffffff ))) );
//	printf(" adds = %d  ,long add = %d \n ",0x0+0x0, MyfloatToLong(MyfloatAdd( LongToMyfloat( 0x0 ) , LongToMyfloat( 0x0 ))) );
//	printf(" adds = %d  ,long add = %d \n ",0x7fffffff+0x7fffffff, MyfloatToLong(MyfloatAdd( LongToMyfloat( 0x7fffffff ) , LongToMyfloat( 0x7fffffff ))) );
//	printf(" adds = %d  ,long add = %d \n ",0x1+0x2, MyfloatToLong(MyfloatAdd( LongToMyfloat( 0x1) , LongToMyfloat( 0x2 ))) );

	// 测试MyfloatSub()函数
//	printf(" subs = %d  ,long sub = %d \n ",0x7fffffff-0x7fffffff, MyfloatToLong(MyfloatSub( LongToMyfloat( 0x7fffffff ) , LongToMyfloat( 0x7fffffff ))) );
//	printf(" subs = %d  ,long sub = %d \n ",0x7ffffff-0xffffffff, MyfloatToLong(MyfloatSub( LongToMyfloat( 0x7ffffff ) , LongToMyfloat( 0xffffffff ))) );
//	printf(" subs = %d  ,long sub = %d \n ",0xffffffff-0x7ffdffff, MyfloatToLong(MyfloatSub( LongToMyfloat( 0xffffffff ) , LongToMyfloat( 0x7ffdffff ))) );
//	printf(" subs = %d  ,long sub = %d \n ",0x83f1feff-0xffffffff, MyfloatToLong(MyfloatSub( LongToMyfloat( 0x83f1feff ) , LongToMyfloat( 0xffffffff ))) );

	// 测试MyfloatMul()函数
//	printf(" muls = %d  ,long mul = %d \n ",0x7fffffff*0x7fffffff, MyfloatToLong(MyfloatMul( LongToMyfloat( 0x7fffffff ) , LongToMyfloat( 0x7fffffff ))) );// myfloat=0x3dfffffff800  64位整数为0x3fffffff00000001 ,myfloat达不到这高所以转化为32位的积为0是正确
//	printf(" muls = %d  ,long mul = %d \n ",0xf3f1feff*0x2, MyfloatToLong(MyfloatMul( LongToMyfloat( 0xf3f1feff ) , LongToMyfloat( 0x2 ))) );
//	printf(" muls = %d  ,long mul = %d \n ",0*0x2, MyfloatToLong(MyfloatMul( LongToMyfloat( 0 ) , LongToMyfloat( 0x2 ))) );
	
//			printf(" muls = %d  ,long mul = %d \n ",(3)*(4), MyfloatToLong(MyfloatMul( LongToMyfloat( 3) , LongToMyfloat( 4 ))) );
	// 测试MyfloatDiv()函数	全部通过!运行时间20分钟i=0--9999,j=1--9999 ,1亿次
	
	for ( i =-100; i<100; i++)
		for (  j =1; j<1000;j++)
		{
		

		//	MyfloatAdd( LongToMyfloat( i ) , LongToMyfloat( j ));
			//printf(" i=%d, j=%d div = %d, long div =%d \n ", 385,3,(unsigned long )(385/3), MyfloatToLong(MyfloatDiv( LongToMyfloat( 385), LongToMyfloat( 3 )))); 
			//	printf(" i=%d,j=%d, adds = %d  ,long add = %d \n ",i,j,i-j, MyfloatToLong(MyfloatSub( LongToMyfloat( i ) , LongToMyfloat( j ))) );
//					printf(" i=%d,j=%d, muls = %d  ,long Mul= %d \n ",i,j,i*j, MyfloatToLong(MyfloatMul( LongToMyfloat( i ) , LongToMyfloat( j ))) );

			if ((unsigned long )(i*j) != MyfloatToLong(MyfloatMul( LongToMyfloat( i ) , LongToMyfloat( j ))) )//(unsigned long )(i-j) != MyfloatToLong(MyfloatSub( LongToMyfloat( i ) , LongToMyfloat( j ))) )  // MyfloatToLong(MyfloatDiv( LongToMyfloat( i), LongToMyfloat( j ))) )
			{
	//			if ( i*j %20 == 0 ) getchar();
				// 除法测试通过
		///		printf(" i=%d, j=%d div = %d, long div =%d \n ", i,j,(unsigned long )(i/j), MyfloatToLong(MyfloatDiv( LongToMyfloat( i), LongToMyfloat( j )))); 
				// 加法测试1 亿次3分钟通过
			//	printf(" i=%d,j=%d, adds = %d  ,long add = %d \n ",i,j,i+j, MyfloatToLong(MyfloatAdd( LongToMyfloat( i ) , LongToMyfloat( j ))) );
				// 减法测试通过
			//	printf(" i=%d,j=%d, subs = %d  ,long Sub= %d \n ",i,j,i-j, MyfloatToLong(MyfloatSub( LongToMyfloat( i ) , LongToMyfloat( j ))) );
			// 乘法测试通过
	//			printf(" i=%d,j=%d, muls = %d  ,long Mul= %d \n ",i,j,i*j, MyfloatToLong(MyfloatMul( LongToMyfloat( i ) , LongToMyfloat( j ))) );
	
			}

		
		}
	// 精度测试
//	printf(" div = %f, long div =%d \n ", ((double)1/(double)355.0 )*1000000000, MyfloatToLong(MyfloatDiv( MyfloatMul(LongToMyfloat(100000000), MyfloatMul(  LongToMyfloat(1000000000),MyfloatDiv( LongToMyfloat( 1 ), LongToMyfloat( 355 ))) ),LongToMyfloat(1000000)) ) ); 

	return 0;
}

//////////////////////////////////////////////////////////////////////////////
// 算法实现
//////////////////////////////////////////////////////////////////////////////

// 32位有符号型整数---->  myfloat类型转化
myfloat LongToMyfloat( S32 ivar )
{
	xdata myfloat ft;
	xdata U32 fet; // 计算指数的变量
    xdata U32 fmt;// 临时存放尾数m的位的变量
	xdata char e; // 存放指数值

	
	fmt = (U32)( ivar & BIT_S32V );// 默认为正整数,直接取真值
	ft.s = 0; // 默认为正整数

	if ( BIT_S32S  ==( ivar & BIT_S32S ) ) // 如果32位符号整数最高位为1
	{
		// 求补码的真值
		fmt = (U32)( ( ~(  ivar  & BIT_S32V ) + 1 ) & BIT_S32V ) ;
		// 送符号到myfloat中
		ft.s = 1;

	}
	if ( 0 ==fmt )// 如果整数为0
	{
		ft.s = 0;
		ft.e = 0;
		ft.mh = 0;
		ft.ml=0;
		return ( ft );
	}
	// 计算指数e
	e = 1;
	fet = fmt;
	while (  fet = ( fet / 2 ) )
	{
		e++;
	}
	ft.e = e;
	// 计算尾数,因为此时fmt中的真值的二进制即是我们的尾数中的数,但还未规格化,即要求尾数>=0.1
	// 这个尾数已有的位数即是指数e的值,剩余位要补0
	// 如果,指数e>40 则尾数只取40位,剩下的则要舍去,则出现舍入误差
	//	if ( e > 40 )
	//	{
	//		e =40;
	//	}
	if ( e > 8 )
	{
		ft.mh = (U8) ( fmt >> ( e - 8 ) );// 得到高8位,
		ft.ml = fmt << ( 32 -( e - 8 ) ); // 低32位,高位对齐
	}
	else
	{
		ft.mh = (U8)(((U8) fmt) << ( 8 - e )); //高位对齐
		ft.ml = 0;
	}
	return (ft);
}

// 16位有符号整型----> myfloat类型转化 
myfloat ShortToMyfloat( S16 ivar )
{
	myfloat ft;
	U32 fet; // 计算指数的变量
    U32 fmt;// 临时存放尾数m的低32位的变量
	S8  e; // 存放指数值

	
	fmt = (U32)( ivar & BIT_S16V );// 默认为正整数,直接取真值
	ft.s = 0; // 默认为正整数

	if ( BIT_S16S==( ivar & BIT_S16S )   ) // 如果32位符号整数最高位为1
	{
		// 求补码的真值
		fmt = (U32)( ( ~(  ivar  & BIT_S16V ) + 1 ) & BIT_S16V ) ;
		// 送符号到myfloat中
		ft.s = 1;

	}
	if (0 ==fmt   )// 如果整数为0
	{
		ft.s = 0;
		ft.e = 0;
		ft.mh = 0;
		ft.ml=0;
		return ( ft );
	}
	// 计算指数e
	e = 1;
	fet = fmt;
	while (  fet = ( fet / 2 ) )
	{
		e++;
	}
	ft.e = e;
	// 计算尾数,因为此时fmt中的真值的二进制即是我们的尾数中的数,但还未规格化,即要求尾数>=0.1
	// 这个尾数已有的位数即是指数e的值,剩余位要补0
	// 如果,指数e>40 则尾数只取40位,剩下的则要舍去,则出现舍入误差
	//	if ( e > 40 )
	//	{
	//		e =40;
	//	}
	if ( e > 8 )
	{
		ft.mh = (U8)( (U8) ( fmt >> ( e - 8 ) ) );// 得到高8位,
		ft.ml = fmt << ( 32 -( e - 8 ) ); // 低32位,高位对齐
	}
	else
	{
		ft.mh = (U8) ( ((U8) fmt) << ( 8 - e ) ); //高位对齐
		ft.ml = 0;
	}
	return (ft);
}

// myfloat类型转化---->32位有符号型整数 
// myfloat类型转化为32位有符号型整数时:
// 当myfloat值大于32位有符号型整数范围时:
// 采用的是截断高位的方法,但符号位仍保留
// 这样负数仍是负数,正数仍是正数
// 如有一个myfloat 数:0x90efedcbab00 
// 这是一个负数 N= - (0x0.efedcbab00)* 2^32= -4025338795;它超出了S32的范围
// 转成S32时,结果是: -1877855147= -((0xefedcbab) &0x7fffffff);//即截去最高位
// 对于正数也是类似处理.
// 若是ANSI中对超出范围的数-4025338795的处理是: -4025338795 =0xefedcbab
// 对0xefedcbab求补码, ~0xefedcbab+1=0x10123455 =269628501 ;这样就成了正数了
// 这有别于ANSI中的有符号数超出范围就成为相应的补码形式
// 也不同于float 类型超出整数范围时转为有符号数整数的形式
S32 MyfloatToLong( myfloat fvar )
{
	xdata myfloat ft;
	xdata S32		it;
	xdata S32		imt;
	xdata U32		imtv;//真值 
	xdata U8		ftmh,i;
	xdata U32		ftml;
	 ft = fvar;
	 ftmh = ft.mh;
	 ftml = ft.ml;
	it = ( (S32)ft.s )<< 31;// 得到符号位

	// 是纯小数时:
	if ( ( ( ft.e & BIT_MASKES ) == BIT_MASKES ) ) // 指数符号位为1,即是负指数,纯小数是小于0.5的
	 
	{
		return ( (S32)0 );
	}
	if ( (0==ft.e  ) )// 即纯小数可能大于0.5
	{// 不四舍五入
/*		if ( 0x80 == ( ft.mh & 0x80 ) ) // 得到最高位,为1说明纯小数大于0.5
		{
			return ( (S32)1 );
		}
		else
*/		{
			return ( (S32)0 );
		}
	}

	if ( ft.e >31 )// >31就要截断高于31位的数
	{
		/* 有错的代码
		if ( 39 == ft.e )
		{
			imt = (S32)( ( ft.ml >> 1 ) & BIT_MASKSNOT );// 得到真值
		}
		if ( 40 == ft.e   )
		{
			imt = (S32) (ft.ml &BIT_MASKSNOT );// 截去第31位(31~0)
		}
		if ( ft.e < 39 )
		{
			iet =ft.e -31; // 得到ft.mh中可截断的高位位数
			// ft.mh << iet 位,实现要取的在于ft高8位的数移到8位的最高位,
			// 再移23位,就移到32位符号整数的高31位了, 再把ft.ml部分的位数,移到32位的最低位边,
			// 最后高位和低位按位或,就可以得到要求的真值了.
			// ft.mh<< iet 是按32位的中间结果的,但我要去掉iet位,所以必须(unsigned char)(ft.mh << iet )
			imt = (S32)( (((U32)( (unsigned char)(ft.mh << iet )) )<< 23) |((U32)( ( ft.ml >> ( 40 - ft.e ) ))) ); 
		}
		*/
		
		for ( i = 1 ; i<= (ft.e -31); i++ )
		{
			SL40(&ftmh,&ftml);
		}
		imtv = (U32)((((U32)ftmh)<< 23) | (ftml >> 9) );// 组成31位的真值,放在低31位,最高位这里为0
	}
	if ( ft.e <= 31 )
	{
		if ( ft.e >= 8)
		{// 高8位和低32位中的数拼成31位的整数真值
			if ( ft.e == 8 )
			{
				imtv= (S32)( ((U32)ft.mh )<< ( ft.e -8 ) );
			}
			else
			{
				imtv = (S32) ( ( ((U32)ft.mh )<< ( ft.e -8 ) ) | (ft.ml >> ( 40- ft.e) ) );
			}
		}
		if ( ft.e < 8 )
		{
	
			imtv = (U32) ( ((U32)ft.mh ) >> ( 8 - ft.e )); // 右对齐
			imtv = imtv & (~0x80000000);
		}
	}

	// 是负数真值以补码表示
    if (1 ==ft.s   )
	{
		
		imt = (S32)( it | ( ( ( ~imtv ) + 1 ) & BIT_MASKSNOT ) ); // it是符号位的符号

	}
	else
	{
		imt = (S32) (it |imtv);
	}
	return ( imt );
}

// myfloat类型任意数相加
// 负数 - 正数 +
// -- -+ +- ++ 四种相加
myfloat MyfloatAdd( myfloat a, myfloat b )
{
	xdata myfloat ft;
	xdata myfloat ft1,ft2;
	ft1=a;
	ft2=b;
	if ((0==ft1.s ) && ( 0==ft2.s)) //两个都是正数
	{
		ft=MyfloatAddp(ft1,ft2);
		return ( ft );
	}
	if ((0==ft1.s ) && (1==ft2.s ) )//ft1为正,ft2为负
	{
		ft2.s = 0;// ft2变为正数,调用两正数相减函数
		ft =MyfloatSubp(ft1,ft2);
		return (ft );
	}
	if ((1==ft1.s) && (0==ft2.s )) // ft1为负,ft2为正
	{
		ft1.s =0;// ft1变为正数,调用两正数相减函数
		ft= MyfloatSubp(ft2,ft1); 
		return (ft);
	}
	if ( (1==ft1.s) && (1==ft2.s) ) //ft1,ft2都为负
	{
		ft1.s =0;
		ft2.s = 0;
		ft= MyfloatAddp(ft1,ft2);
		ft.s =1;
		return ( ft );
	}
	return ( *(myfloat *)0 ); // 不可能到达这!
}

// myfloat类型任意数相减
// 负数 -,正数 +
// -- -+ +- ++ 四种相减
myfloat MyfloatSub( myfloat a, myfloat b )
{
	xdata myfloat ft;
	xdata myfloat ft1,ft2;
	ft1=a;
	ft2=b;
	if ((0==ft1.s ) && ( 0==ft2.s)) //两个都是正数
	{
		ft =MyfloatSubp(ft1,ft2);
		return ( ft );
	}
	if ((0==ft1.s ) && (1==ft2.s ) )//ft1为正,ft2为负
	{
		ft2.s = 0;// ft2变为正数,调用两正数相加函数
		ft=MyfloatAddp(ft1,ft2);
		return (ft );
	}
	if ((1==ft1.s) && (0==ft2.s )) // ft1为负,ft2为正
	{
		ft1.s =0;
		ft= MyfloatAddp(ft1,ft2);
		ft.s =1;
		return ( ft );

	}
	if ( (1==ft1.s) && (1==ft2.s) ) //ft1,ft2都为负
	{	
		ft1.s =0;// ft1变为正数,调用两正数相减函数
		ft2.s = 0;
		ft= MyfloatSubp(ft2,ft1);
		return ( ft);

	}
	return ( *(myfloat *)0 ); // 不可能到达这!
}


// 这个是被上两函数调用的子函数// 正数+正数
myfloat MyfloatAddp( myfloat a, myfloat b )
{
	xdata myfloat ft;
	xdata myfloat ft1, ft2;
	xdata S8		fet;
	xdata U32		fmt2ml,fmt2mh,fmtmladd;
	xdata U8		fmtmhadd,fmtmhaddt;
	xdata U8		fmtmhC,fmtmlC;
	xdata S8		fet1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -