c语言浮点数乘法算法,单精度浮点数乘法的实现
按:计算机组成课程第四周作业
算法证明
图表 1 浮点数的表示
浮点数的表示如上图所示,我们要做的是将按如上方式存储的两个浮点数相乘,将其结果用如上的方式表示。
符号位只是两者的异或,指数位基本上是两指数的相加,而尾数位就需要在正常的乘法之余考虑到移位(和随之而来的指数为的溢出)和进位的情况。
下面就来讨论一下尾数的运算:
在尾数前补上1,进行无符号数乘法。小数点仅作为算法分析时的记号,实际上不参加运算。用64位的long long类型的数来存储运算结果。
图表 2 尾数相乘(用“画图”程序画的)
如上图所示,后46个数字是结果的小数点后的数据,小数点的的问号处可能只有1,可能是1X(10或11,在算法中没有太大区别)。若问号处只有1,说明已经规格化完成;若是1X,需要将整个数右移一位,质数加一,从而使问号处只有1。
规格化后要进行round操作,如下图所示。如果第23位是0,这一位之前的23位就是所需要的尾数。如果第23位是1,截取这位之前的数,加一(类似于四舍五入)。判断结果是否仍规格化。若没有规格化,从规格化开始继续做,直到找到规格化后的23位尾数。
图表 3 有效数处理(用“画图”程序画的)
程序框图
主要流程如下图所示。在代码注释中的Step1到step5即分别对应流程图中的1至5部分。有所不同的是,因为后面只会增加exponent而不会减少,所以我的程序在step1就判断是否overflow,在step3也判断是否overflow就行了,规格化完成后再判断underflow。
图表 4 浮点乘法程序框图
使用方法
输入两个数,程序用自带的scanf将其作为单精度浮点数读入。通过一系列的无符号数的计算,得到用单精度浮点数表示的结果,将其输出(为了更详细地看到整个数,输出的数小数点后有20位)。如果overflow或underflow,输出的是相应的提示。为了验证计算是否正确,在输出的数据后面有个括号,里面放了是直接让机器进行的单精度浮点数的乘法的结果。
特殊处理
特殊输入数据
有些输入的数据是在太大或太小,以至于数据本身就已经overflow或underflow,从而根本无法存贮到单精度浮点数中,不是合法的单精度浮点数。对于这样的数,我们不应该对其提供任何服务,不然只会闹出笑话。
对于零要特殊处理,因为0在浮点数中的表示并不是按照一般的规范来的。
溢出
这里的溢出指的是乘数和被乘数本身是合法的单精度浮点数,但相乘后造成了溢出。
因为后面只会增加exponent而不会减少,所以与上面的流程图不同,我的程序在step1就判断是否overflow,在step3也判断是否overflow就行了,规格化完成后再判断underflow。
数位扩展
整个程序都是按照单精度的浮点数来写的,数位扩展可能有点麻烦。如果要扩展为双精度的,需要更改代码中的大量参数。鉴于浮点数一般也就只有单精度和双精度两种,我觉得不是太必要提高做成可扩展的。
实例分析
图表 5 大数的乘法
图表 6 overflow
图表 7 underflow(本程序判为underflow,而C语言自己的浮点数乘法计算结果为0.000000)
图表 8 对0的乘法
图表 9 很大的与很小的正数相乘
图表 10 观察精确度
图表 11 对负数乘法的测试
图表 12 对于无法用浮点数表示的输入数据
图表 13 对于过小的数据
结果分析
我们对过于大的数据和过于小的数据,以及精度太大的数据都做了试验。从上述结果可以看到,这个程序的结果与C程序自带的浮点数乘法结果基本吻合。说明这个程序还是比较可靠的。
通过对精度的测试,我们发现浮点数虽然能表示较大较小的数据,但有效数字还是有限的。如-100与0.6相乘的结果,整数部分60是对的,小数点五位后就出现了偏差。一连串8与1相乘,结果的头部只有7个8。可以大致地认为浮点数的表示与计算的十进制有效数位是7位。
可以更进一步的工作
l 程序中对于无符号整数的加法、乘法,对于exponent的有符号整数运算都是直接使用的,其实可以调用之前写的相关程序,做成更加本质的浮点数乘法。
Source Code
#include
union unionfloat{
float f;
unsigned long l;
};
union unionfloat x,y,product;
/*
disp(union unionfloat x)
{
long i;
unsigned long m;
printf("%f:",x.f);
m=0x80000000;
for(i=0; i<32; i++){
if((i&7)==0)printf(" ");
if(m&x.l)printf("1");
else printf("0");
m>>=1;
}
printf("\n");
}*/
int mul(void){
//Step 1
int exponent;
exponent=(x.l&0x7F800000)>>23;
exponent-=0x7F;
exponent+=(y.l&0x7F800000)>>23;
exponent-=0x7F;
if(exponent>=128) return 1;
//Step 2
unsigned long long raw_product;
unsigned long long raw_x=x.l&0x007FFFFF|0x00800000;
unsigned long long raw_y=y.l&0x007FFFFF|0x00800000;
int carry;
raw_product = raw_x * raw_y;
/*int i=64;
unsigned long long p=0x8000000000000000;
while(i--){
if(i%4==3)printf(" ");
if(raw_product&p)printf("1");
else printf("0");
p=p>>1;
}
printf("\n");*/
//相乘结果若小数点前有两位
do{
//Step 3
if(raw_product>>47){
raw_product = raw_product>>1;
exponent++;
if(exponent>=128) return 1;//printf("Overflow");
}
//Step 4
if(raw_product & 0x0000000000400000){
raw_product = ((raw_product>>23)+1)<<23;
}
}while(raw_product>>47);//still normalized?
//Step 5
product.l = ((x.l>>31)^(y.l>>31))<<31;
if(exponent<=-127)return -1;//printf("Underflow");
//-127
product.l = product.l | ((unsigned long)(exponent+127))<<23;
product.l = product.l|((unsigned long)((raw_product&0x00003FFFFF800000)>>23));
//disp(product);
printf("%.20f(%.20f)\n",product.f,x.f*y.f);
return 0;
}
int main(void){
while(~scanf("%f%f",&x.f,&y.f)){
//printf("Input %.10f %.10f\n",x.f,y.f);
//disp(x);disp(y);
if(x.l==0||y.l==0)
printf("%f(%f)\n",0,x.f*y.f);
else if((((x.l>>23)&0x000000FF)==0) || (((x.l>>23)&0x000000FF)==0x000000FF))
printf("The first number is unavailable\n");
else if((((y.l>>23)&0x000000FF)==0) || (((y.l>>23)&0x000000FF)==0x000000FF))
printf("The second number is unavailable\n");
else{
switch(mul()){
case 1:printf("Overflow(%f)\n",x.f*y.f);break;
case -1:printf("Underflow(%f)\n",x.f*y.f);break;
default:break;
}
}
}
return 0;
}
c语言浮点数乘法算法,单精度浮点数乘法的实现相关推荐
- C语言布斯乘法算法,布斯Booth算法带符号位的乘法verilog语言实现booth算法
Booth算法的推倒表示看不懂,举例说明:算法的计算过程. 求M*Q的值 M=5,Q=6 按二进制分解M和Q :M3M2M1M0×Q3Q2Q1Q0: 0110×0101 (有符号数用补码表示,最高位表 ...
- 【软考学习3】数据表示——浮点数计算 + 单精度浮点数IEEE754计算
浮点数计算在软考中的考查形式一般为选择题,要求选择正确的或者错误的是什么,所以需要学习浮点数的基本运算流程. 另外在本科<计算机组成原理>中还学过 IEEE754单精度 浮点数运算,所以一 ...
- C语言 int 转单精度浮点,单精度浮点数与十六进制转换 C语言程序 单片机也可用...
单精度浮点数与十六进制转换 C语言程序 单片机也可用 #include float Hex_To_Decimal(unsigned char *Byte,int num)//十六进制到浮点数 { // ...
- c语言里单精度浮点数和双精度浮点数的区别
单精度浮点数(float)和双精度浮点数(double)在C语言中是两种不同类型的数据.单精度浮点数占用4个字节的空间,精度范围在67位左右:双精度浮点数占用8个字节的空间,精度范围在1517位左右. ...
- 单精度浮点数转十进制C语言,C语言:IEEE754十进制数转二进制单精度浮点数
1. 背景知识 IEEE754是由IEEE制定的有关浮点数的工业标准.针对于单精度浮点数,其公式如下,S为符号位,只占1位,为0表示正数,为1表示负数.P为指数(阶码),用移码表示,占8位.M为尾数, ...
- 双精度改单精度c语言程序,C语言菜鸟基础教程之单精度浮点数与双精度浮点数...
上节课 简单介绍了浮点数.计算机程序中的浮点数分为单精度浮点数和双精度浮点数. 单精度和双精度精确的范围不一样. 计算机里的最基本的存储单位用位(bit)来表示.bit只能用来存储0或1. 稍大一点的 ...
- c语言浮点数高精度求平方根,快速高精度的二进制浮点数开平方算法
1引盲开平方运算在用徽机.单片机等构成的实时控制系统和测量仪器中有着广泛的应用.开平方运算的实现方法有多种:如牛顿迭代法.查表法.直线逼近法(线性化方法)和减奇数法等.对于查表法,当被开方数变化范围较 ...
- c语言浮点型菜鸟教程,C语言菜鸟基础教程之单精度浮点数与双精度浮点数
上节课 简单介绍了浮点数.计算机程序中的浮点数分为单精度浮点数和双精度浮点数. 单精度和双精度精确的范围不一样. 计算机里的最基本的存储单位用位(bit)来表示.bit只能用来存储0或1. 稍大一点的 ...
- c语言单精度浮点数规格化,对浮点数的一些理解
浮点数的范围和有效位 对于浮点数,其能表示的数值范围和其有效位如下 类型 比特位 数值范围 有效位 float 32 -3.410^38-+3.410^38 6~7位 double 64 -1.710 ...
最新文章
- GNN 系列:Graph 基础知识介绍
- Bert时代的创新:Bert应用模式比较及其它
- Confluence 6 设置 Oracle 数据库准备
- IT人 不要一辈子靠技术生存(转
- Hadoop学习之hadoop安装、JDK安装、集群启动(完全分布式)
- 文件上传漏洞常用绕过方式
- 2021FME博客大赛 —— 利用FME实现三调地类图斑统计分析
- hive查看一张表的分区字段_在Hive中对表进行分区和存储有什么区别?
- Traffic Flow Prediction Using Graph Convolution Neural NetworksOC 翻译笔记
- 进程和线程的主仆问题
- Android Jetpack架构组件之Room
- 游戏建模入门教程:绝地求生—PUBG的游戏模型制作流程
- CSS设计指南---字体和文本的布局
- android苹果蓝牙版本,苹果蓝牙和安卓蓝牙能连吗
- 列表等份切割,Google Utils Lists partition
- JS 日期转换成时间戳
- 添加布林带择时策略有多便捷!股票量化分析工具QTYX-V2.4.7
- Objective-c中的占位符,打印BOOL类型数据
- C/C++黑魔法-字符串分割
- 全国计算机等级考试python教材.pdf_全国计算机等级考试二级教程Python语言程序设计(2018年版).PDF...