【CNN-FPGA开源项目解析】01--floatMult16模块

2023-09-18 13:50:12

(基础)半精度浮点数的表示和乘运算

16位半精度浮点数

在这里插入图片描述

浮点数的乘运算

根本原理式:
X = X S ⋅ 2 X E Y = Y S ⋅ 2 Y E X ⋅ Y = ( X S ∗ Y S ) ⋅ 2 X E + Y E X = X_{S} · 2^{X_{E}} \\ Y = Y_{S} · 2^{Y_{E}} \\ X·Y = (X_{S}*Y_{S}) · 2^{X_{E} + Y_{E}} X=XS2XEY=YS2YEXY=(XSYS)2XE+YE
基本流程:

  • 判符号。

  • 算尾数:结果的尾数是输入两数的尾数之积。(未标准化)

  • 算指数:结果的指数是输入两数的指数之和。(未标准化)

  • 标准化和舍位:

    ① 结果化为二级制(1.xx)的形式,取出尾数。

    ② 舍去低位,保留高位。


floatMult16完整代码

完整代码:

`timescale 100 ns / 10 ps

module floatMult16 (floatA,floatB,product);

input [15:0] floatA, floatB;
output reg [15:0] product;

reg sign;
reg signed [5:0] exponent; //6th bit is the sign
reg [9:0] mantissa;
reg [10:0] fractionA, fractionB;	//fraction = {1,mantissa}
reg [21:0] fraction;


always @ (floatA or floatB) begin
	if (floatA == 0 || floatB == 0) begin
		product = 0;
	end else begin
		sign = floatA[15] ^ floatB[15];
		exponent = floatA[14:10] + floatB[14:10] - 5'd15 + 5'd2;
	
		fractionA = {1'b1,floatA[9:0]};
		fractionB = {1'b1,floatB[9:0]};
		fraction = fractionA * fractionB;
		
		if (fraction[21] == 1'b1) begin
			fraction = fraction << 1;
			exponent = exponent - 1; 
		end else if (fraction[20] == 1'b1) begin
			fraction = fraction << 2;
			exponent = exponent - 2;
		end else if (fraction[19] == 1'b1) begin
			fraction = fraction << 3;
			exponent = exponent - 3;
		end else if (fraction[18] == 1'b1) begin
			fraction = fraction << 4;
			exponent = exponent - 4;
		end else if (fraction[17] == 1'b1) begin
			fraction = fraction << 5;
			exponent = exponent - 5;
		end else if (fraction[16] == 1'b1) begin
			fraction = fraction << 6;
			exponent = exponent - 6;
		end else if (fraction[15] == 1'b1) begin
			fraction = fraction << 7;
			exponent = exponent - 7;
		end else if (fraction[14] == 1'b1) begin
			fraction = fraction << 8;
			exponent = exponent - 8;
		end else if (fraction[13] == 1'b1) begin
			fraction = fraction << 9;
			exponent = exponent - 9;
		end else if (fraction[12] == 1'b0) begin
			fraction = fraction << 10;
			exponent = exponent - 10;
		end 
	
		mantissa = fraction[21:12];
		if(exponent[5]==1'b1) begin //exponent is negative
			product=16'b0000000000000000;
		end
		else begin
			product = {sign,exponent[4:0],mantissa};
		end
	end
end

endmodule

floatMult16代码逐步解析

符号位sign判断

​ 正正得正,负负得正,正负得负。用异或运算即可。

sign = floatA[15] ^ floatB[15];

指数exponent计算

​ floatA与floatB的指数相加,初步得到了乘法结果的指数(尚未标准化)。

  • 后面进行标准化时,指数要随着"尾数小数点"的移动而变化。
exponent = floatA[14:10] + floatB[14:10] - 5'd15 + 5'd2;

尾数fraction计算

​ floatA与floatB的尾数相乘,初步得到了乘法结果的尾数(尚未标准化)。

  • 输入的两个浮点数是上一级操作完成的。fraction为省略整数1的小数部分,因此运算时需要先把这个整数1还回去。
  • 此步得到的运算结果尚未经历标准化。
  • 两个10bit的二进制相乘结果先暂存为20bit,避免在乘法过程中造成精度损失。后续再进行移位和舍位。
//输入的两个浮点数A,B都是标准的。把整数1先借回去,以便参与运算。
fractionA = {1'b1,floatA[9:0]};
fractionB = {1'b1,floatB[9:0]};
//尾数相乘
fraction = fractionA * fractionB;

尾数fraction的标准化和舍位

​ 通过小数点的移动,将运算结果变为二进制(1.xx)的形式。尾数即取小数点后(xx)的部分。同时,在这个过程中"指数"要同步发生变化。

  • 尾数小数点"左移n位",二进制右移:指数+n。
  • 尾数小数点"右移n位",二进制左移:指数-n。

代码的思路是:

  • 从乘法结果尾数的高位开始,寻找到最高位的1。通过左移,将"这一位"变为最高位。

  • 半精度浮点数尾数位只取5位。舍去低位。

标准化:

		if (fraction[21] == 1'b1) begin
			fraction = fraction << 1;
			exponent = exponent - 1; 
		end else if (fraction[20] == 1'b1) begin
			fraction = fraction << 2;
			exponent = exponent - 2;
		end else if (fraction[19] == 1'b1) begin
			fraction = fraction << 3;
			exponent = exponent - 3;
		end else if (fraction[18] == 1'b1) begin
			fraction = fraction << 4;
			exponent = exponent - 4;
		end else if (fraction[17] == 1'b1) begin
			fraction = fraction << 5;
			exponent = exponent - 5;
		end else if (fraction[16] == 1'b1) begin
			fraction = fraction << 6;
			exponent = exponent - 6;
		end else if (fraction[15] == 1'b1) begin
			fraction = fraction << 7;
			exponent = exponent - 7;
		end else if (fraction[14] == 1'b1) begin
			fraction = fraction << 8;
			exponent = exponent - 8;
		end else if (fraction[13] == 1'b1) begin
			fraction = fraction << 9;
			exponent = exponent - 9;
		end else if (fraction[12] == 1'b0) begin
			fraction = fraction << 10;
			exponent = exponent - 10;
		end 

舍位:

		mantissa = fraction[21:12];

整合为最后的16位浮点数结果[sign,exponent,fraction]

使用"拼接"语法,最后结果product为16位。

product = {sign,exponent[4:0],mantissa};

其他

变量宽度表

input [15:0] floatA, floatB;
output reg [15:0] product;

reg sign;
reg signed [5:0] exponent; 
reg [9:0] mantissa;
reg [10:0] fractionA, fractionB;
reg [21:0] fraction;

always敏感列表

本模块为纯组合逻辑,非时序。因此只要有数据输入,便触发模块功能,开始运算。

always @ (floatA or floatB)	begin
   /* -------------------- */ 
end

特殊情况处理

  • 输入两个数都是0时,输出也为0。
if (floatA == 0 || floatB == 0) begin
	product = 0;
end
  • 不允许指数为负数。在半精度浮点数中,指数本来只有5位。但是代码中的变量设置为6位,其中多出的最高一位是符号位。通过这一位,我们来判断指数的正负。

(这一点从上面操作fraction只进行左移也可以看出来。)

if(exponent[5]==1'b1) begin 
	product=16'b0000000000000000;
end

学习文章:二进制浮点数以及二进制浮点数算术运算
开源项目github-URL:CNN-FPGA

更多推荐

Flutter的oktoast插件详解

文章目录简介详细介绍安装和导入导入在MaterialApp外面套一层OKToast组件为什么是包住MaterialApp?显示Toast消息:高级使用Toast位置Toast持续时间自定义Toast样式高级用法使用场景提示消息表单验证操作反馈网络请求状态调试信息小结总结简介oktoast是一个Flutter库,它提供了

vue项目嵌套安卓壳子打包apk

1.确保你的项目可以正常运行2.vue.config.jspublicPath添加一个publicPath:'./',3.需要下载一个HBuilderX编辑器下载地址:HBuilderX-高效极客技巧4.新建一个项目选择5+App创建完成之后删除掉红框内的文件只保留一个manifest.json5.把自己要变成app的

Java 函数式编程思考 —— 授人以渔

引言最近在使用函数式编程时,突然有了一点心得体会,简单说,用好了函数式编程,可以极大的实现方法调用的解耦,业务逻辑高度内聚,同时减少不必要的分支语句(if-else)。一、函数式编程就是Lambda表达式吗?Java语言早在JDK8就提供了函数式编程的基础。你可能会问,函数编程不就是lambda表达式吗?的确,大多数开

Three.js 实现导出模型文件(.glb,.gltf)功能 GLTFExporter

Three.js提供了导出(.glb,.gltf)文件的APIGLTFExporter用于实现场景内容导出模型文件的功能导出模型文件主要使用parse方法,该方法接收三个参数:1.scene:要导出的场景对象。2.onComplete:解析完成后的回调函数,接收一个参数result,表示解析后的glTF数据。3.opt

常用排序算法

一、插入排序1、直接插入排序2、折半插入排序3、希尔排序二、交换排序1、冒泡排序2、快速排序三、选择排序1、简单选择排序2、堆排序(1)调整堆(2)创建堆四、归并排序五、基数排序六、各种排序方法的比较将一组杂乱无章的数据按一定规律顺次排列起来(由小到大或由大到小),即将无序序列排成一个有序序列的运算。排序方法的分类:一

展会预告 | 图扑邀您共聚 IOTE 国际物联网展·深圳站

参展时间:9月20日-22日图扑展位:9号馆9B35-1参展地址:深圳国际会展中心(宝安新馆)IOTE2023第二十届国际物联网展·深圳站,将于9月20日-22日在深圳国际会展中心(宝安)9、10、11号馆震撼来袭。本届展会以“IoT构建数字经济底座”为主题,将IoT技术引入实体经济领域,促进数字化转型和智能化升级,推

【运维】dockerfile 中的COPY 会覆盖文件夹吗

Dockerfile中的COPY命令会根据指定的源路径将文件或文件夹复制到容器中的目标路径。行为取决于两个因素:源路径和目标路径以及目标路径的类型。源路径是文件,目标路径是文件:如果源路径是文件,目标路径也是文件,则COPY命令会将源文件复制到目标路径,并覆盖目标路径中的任何现有文件。例如:COPY./source-f

中小企业生产信息化系统哪个好用?选亿发制造业管理系统提供商

中小型制造企业虽然规模相对较小,但同样是市场经济的重要组成部分。要在这个竞争环境中脱颖而出,智能化生产管理系统成为中小型制造企业不可或缺的工具。让各部门之间的数据无缝衔接,实现工厂的整体协调性和工作效率的大幅提升。让我们从几个关键方面来看中小型制造工厂如何选择适合的生产管理系统。生产计划管理:中小型工厂通常需要灵活的生

001 linux 导学

前言本文建立在您已经安装好linux环境后,本文会向您介绍Shell的一些常用指令什么是linuxLinux是一种自由和开放源代码的类UNIX操作系统,该操作系统的内核由林纳斯托瓦兹在1991年首次发布,之后,在加上用户空间的应用程序之后,就成为了Linux操作系统,并在全球范围内得到了广泛的使用和支持。Linux具有

新闻软文的写作要点有哪些?媒介盒子告诉你

信息时代,受众获取信息的方式越来越碎片化,他们对信息的敏感度越来越高,这就导致虽然广告的成本高了,但是广告的效果越来越不明显。这个时候可以考虑新闻软文,新闻体软文是软文与新闻的结合体,它能够提升企业的曝光率,为企业的宣传起到积极作用,那接下来媒介盒子就从三大方面告诉大家,新闻软文的写作方式。一、&nbsp;保证真实性新

VUE之proxy配置实现跨域

什么是跨域要了解跨域,首先得知道浏览器的同源策略。同源策略:是由Netscape提出的一个安全策略,能够阻挡恶意文档,保护本地数据。它能限制一个源的文档或脚本对另一个源的交互,使得其它源的文档或脚本,无法读取或修改当前源。是否同源:当两个url的域名、协议和端口均相同。举例来说:url:http://127.0.0.1

热文推荐