这个例子展示了如何将一个浮点算法定点,然后生成C代码的算法。示例使用以下最佳实践:
单独的算法从测试文件。
准备你的仪表和代码生成算法。
管理数据类型和控制增长。
单独的数据类型定义从算法的代码创建一个表的数据定义。
最佳实践的完整列表,请参阅手工定点转换的最佳实践。
写一个MATLAB®函数,mysum
,和一个向量的元素。
函数y = mysum (x) y = 0;为n = 1:长度(x) y = y + x (n);结束结束
因为你只需要算法部分转换为定点,这样代码结构更为高效的算法,核心处理,你做的是独立于测试文件。
在测试文件,创建您的输入,调用算法,绘制结果。
写一个MATLAB脚本,mysum_test
,验证你的算法使用双数据类型的行为。
n = 10;rng默认的兰德(n, 1) x = 2 * 1;%的算法y = mysum (x);%验证结果y_expected =总和(双(x));呃= (y)——y_expected两倍
rng违约
的设置使用的随机数生成器rand函数其默认值,以便它产生的随机数如果你重启MATLAB。
运行测试脚本。
mysum_test
呃= 0
获得的结果使用mysum
使用MATLAB与获得总和
函数。
有关更多信息,请参见创建一个测试文件。
在你的算法,函数签名后,添加% # codegen
编译指令表明你打算仪器算法和生成C代码。添加这个指令指示MATLAB代码分析器来帮助您诊断和解决违规,将导致错误在仪表和代码生成。
函数y = mysum (x)% # codegeny = 0;为n = 1:长度(x) y = y + x (n);结束结束
对于该算法,代码分析器指示器在编辑器窗口的右上角绿色告诉你,它没有发现任何问题。
有关更多信息,请参见准备加速算法代码或代码生成。
为原算法生成C代码来验证该算法适用于代码生成和浮点C代码。使用codegen
(MATLAB编码器)函数(需要MATLAB编码器™)来生成一个C库。
添加以下行结束您的测试脚本生成C代码mysum
。
codegenmysumarg游戏{x}配置:自由报告
再次运行测试脚本。
MATLAB编码器生成C代码mysum
功能和提供了一个链接到代码生成报告。
点击链接打开代码生成报告并查看生成的C代码mysum
。
/ *函数定义* /双mysum (const双x[10]){双y;int n;y = 0.0;(n = 0;n < 10;n + +) {y + = x [n];}返回y;}
因为C不允许浮点指标,循环计数器,n
,自动声明为一个整数类型。你不需要转换n
不动点。
输入x
和输出y
声明为双。
测试你的算法与单打检查类型不匹配
修改您的测试文件,这样的数据类型x
是单身。
n = 10;rng默认的x =单(2 *兰德(n, 1) 1);%的算法y = mysum (x);%验证结果y_expected =总和(双(x));呃=双(y) - y_expected codegenmysumarg游戏{x}配置:自由报告
再次运行测试脚本。
mysum_test
呃= -4.4703 e-08 ? ? ?这个作业写一个单一的值为“双”类型。通过赋值代码生成不支持改变类型。金宝app检查前的作业输入类型规格类型不匹配。
代码生成失败,报告数据类型不匹配y = y + x (n);
。
查看错误,打开报告。
在报告中,在直线上y = y + x (n)
这份报告强调了y
左边的作业用红色表明有一个错误。问题是,y
被声明为一但被分配到一个。y + x (n)
是一个双重的总和,一个是一个。如果你把你的光标在变量和表达式在报告中,你可以看到他们的类型的信息。在这里,你可以看到表情,y + x (n)
是一个单身。
修复类型不匹配,更新你的算法使用下标赋值元素的总和。改变y = y + x (n)
来(,)= y + x (n)
。
函数y = mysum (x)% # codegeny = 0;为n = 1:长度(x) y (:) = y + x (n);结束结束
使用下标赋值,您也防止一些增长这是默认的行为,当你添加定点数字。有关更多信息,请参见一些增长。防止一些增长是很重要的,因为你想要保持你的定点类型在你的代码。有关更多信息,请参见控制一些增长。
重新生成C代码和开放代码生成报告。在C代码,结果现在投双重解决类型不匹配。
使用buildInstrumentedMex
函数来评价您的日志的最大和最小值算法命名和中间变量。使用showInstrumentationResults
函数提出定点基于这些记录值的数据类型。后,你使用这些提议定点类型测试算法。
更新测试脚本:
当你声明n
,添加buildInstrumentedMex mySum args {0 (n, 1)}直方图
。
改变x
回到双。取代x =单(2 *兰德(n, 1) 1);
与兰德(n, 1) x = 2 * 1;
而不是调用原始算法中,调用生成的墨西哥人的功能。改变y = mysum (x)
来y = mysum_mex (x)
。
调用墨西哥人函数后,添加showInstrumentationResults mysum_mex -defaultDT numerictype -proposeFL (1、16)
。的-proposeFL -defaultDT numerictype (16)
国旗表明你想提出部分长度为16位字长。
这是一个更新的测试脚本。
% %建立仪器的墨西哥人n = 10;buildInstrumentedMexmysumarg游戏{0 (n, 1)}柱状图% %测试输入rng默认的兰德(n, 1) x = 2 * 1;%的算法y = mysum_mex (x);%验证结果showInstrumentationResultsmysum_mex…-defaultDTnumerictype (16)-proposeFLy_expected =总和(双(x));呃= (y)——y_expected两倍% %生成C代码codegenmysumarg游戏{x}配置:自由报告
再次运行测试脚本。
的showInstrumentationResults
提出了数据类型和函数打开一个报告来显示结果。
在报告中,单击变量选项卡。showInstrumentationResults
提出了一种分数13的长度y
和15x
。
在报告中,您可以:
查看模拟输入最小和最大值x
和输出y
。
查看该数据类型x
和y
。
查看所有变量的信息,中间结果,代码中的表达式。
查看这些信息,将您的鼠标停留在变量或表达式在报告中。
查看直方图数据x
和y
帮助你识别精度范围外的任何值或低于基于当前数据类型。
要查看一个特定变量的直方图,单击其直方图图标,。
而不是手动修改算法为每个数据类型检查的行为,不同的数据类型定义的算法。
修改mysum
这需要一个输入参数,T
,这是一个结构,定义了数据类型的输入和输出数据。当y
首先是定义,使用投
功能语法- - - - - -铸造(x,“喜欢”,y)
——把x
到所需的数据类型。
函数y = mysum (x, T)% # codegeny =投(0,“喜欢”,T.y);为n = 1:长度(x) y (:) = y + x (n);结束结束
写一个函数,mytypes
,定义您想要使用的不同数据类型来测试你的算法。在你的数据类型表,包括双、单,双扩展数据类型以及早些时候提出的定点数据类型。将你的算法转换为定点之前,它是良好的实践:
测试数据类型定义表之间的连接和使用加倍你的算法。
测试算法的单身人士找到数据类型不匹配等问题。
运行该算法使用了双打检查溢出。
函数T = mytypes (dt)开关dt情况下“双”T.x= double([]); T.y = double([]);情况下“单一”T.x= single([]); T.y = single([]);情况下“固定”T.x= fi([],true,16,15); T.y = fi([],true,16,13);情况下“缩放”T.x= fi([],true,16,15,…“数据类型”,“ScaledDouble”);T。y= fi([],true,16,13,…“数据类型”,“ScaledDouble”);结束结束
有关更多信息,请参见单独的数据类型定义的算法。
更新测试脚本,mysum_test
使用类型表。
第一运行检查表和算法之间的联系使用双打。在你宣布n
,添加T = mytypes(“双”);
更新调用buildInstrumentedMex
使用的类型T.x
表中指定的数据类型:buildInstrumentedMex mysum args {0 (n, 1,“喜欢”,T.x), T}直方图
投x
使用的类型T.x
中指定的表:x =投(2 *兰德(n, 1) 1,‘喜欢’,T.x);
调用函数传入墨西哥人T
:y = mysum_mex (x, T);
调用codegen
传入T
:codegen mysum args {x T}配置:自由报告
这是更新后的测试脚本。
% %建立仪器的墨西哥人T = mytypes (“双”);n = 10;buildInstrumentedMexmysum…arg游戏{0 (n, 1,“喜欢”,T.x), T}柱状图% %测试输入rng默认的x =投(2 *兰德(n, 1) 1,“喜欢”,T.x);%的算法y = mysum_mex (x, T);%验证结果showInstrumentationResultsmysum_mex…-defaultDTnumerictype (16)-proposeFLy_expected =总和(双(x));呃= (y)——y_expected两倍% %生成C代码codegenmysumarg游戏{x T}配置:自由报告
运行测试脚本,并点击链接打开代码生成报告。
生成的C代码是一样的原始算法生成的代码。因为这个变量T
用于指定类型和这些类型在代码生成时间常数;T
不使用在运行时,不出现在生成的代码中。
更新测试脚本以使用定点类型提出了早些时候和视图生成的C代码。
更新测试脚本以使用定点类型。取代T = mytypes(“双”);
与T = mytypes(固定的);
然后保存脚本。
运行测试脚本和视图生成的C代码。
这个版本的C代码不是很有效;它包含很多溢出处理。下一步是优化数据类型,避免溢出。
比例之间混合双打浮点和定点数字。定点设计师™将它们存储在双打的缩放、标志和字长信息保留。因为所有的在双精度运算执行,你可以看到发生的任何溢出。
更新测试脚本使用了双打。取代T = mytypes(固定的);
与T = mytypes(“缩放”);
再次运行测试脚本。
测试使用了双打和显示报告。没有检测到溢出。
到目前为止,您已经运行测试脚本使用随机输入这意味着它是不可能的,测试执行算法的完整的操作范围。
找到输入的全部。
范围(T.x)
-1.000000000000000 - 0.999969482421875 DataTypeMode:定点:二进制扩展Signedness:签了字:16 FractionLength: 15
更新的脚本测试的负面边缘情况。运行mysum_mex
与原来的随机输入和输入测试完整的范围和总结果。
% %建立仪器的墨西哥人T = mytypes (“缩放”);n = 10;buildInstrumentedMexmysum…arg游戏{0 (n, 1,“喜欢”,T.x), T}柱状图% %测试输入rng默认的x =投(2 *兰德(n, 1) 1,“喜欢”,T.x);y = mysum_mex (x, T);%与这组输入运行一次y_expected =总和(双(x));呃= (y)——y_expected两倍用这组输入%再次运行。日志将聚合。x = 1 (n, 1“喜欢”,T.x);y = mysum_mex (x, T);y_expected =总和(双(x));呃= (y)——y_expected两倍%验证结果showInstrumentationResultsmysum_mex…-defaultDTnumerictype (16)-proposeFLy_expected =总和(双(x));呃= (y)——y_expected两倍% %生成C代码codegenmysumarg游戏{x T}配置:自由报告
再次运行测试脚本。
测试运行和y
溢出定点数据类型的范围。showInstrumentationResults
提出了一种新的部分的长度11y
。
更新测试脚本使用了双打与新提出的类型y
。在myTypes.m
,“缩放”
情况下,T。y= fi([],true,16,11,'DataType','ScaledDouble')
重新运行测试脚本。
现在没有溢出。
更新的数据类型表使用该定点类型和生成代码。
在myTypes.m
,“固定”
情况下,T。y= fi([],true,16,11)
更新测试脚本,mysum_test
,用T = mytypes(固定的);
运行测试脚本,然后单击视图报告链接视图生成的C代码。
短mysum (const短x[10]){短y;int n;int我;int i1;int i2;int i3;y = 0;(n = 0;n < 10;n + +){我= y < < 4; i1 = x[n]; if ((i & 1048576) != 0) { i2 = i | -1048576; } else { i2 = i & 1048575; } if ((i1 & 1048576) != 0) { i3 = i1 | -1048576; } else { i3 = i1 & 1048575; } i = i2 + i3; if ((i & 1048576) != 0) { i |= -1048576; } else { i &= 1048575; } i = (i + 8) >> 4; if (i > 32767) { i = 32767; } else { if (i < -32768) { i = -32768; } } y = (short)i; } return y; }
默认情况下,fi
算术上使用饱和溢出和最近的四舍五入导致低效的代码。
生成的代码效率更高,利用定点数学(fimath
)设置更适合C代码生成:包装溢出和地板上舍入。
在myTypes.m
,添加一个“fixed2”
案例:
案件的fixed2 F = fimath (“RoundingMethod”,“地板”,…‘OverflowAction’,‘包装’,……“ProductMode”、“FullPrecision’,……“SumMode”、“KeepLSB’,……“SumWordLength”, 32岁的……“CastBeforeSum”,真正的);T.x= fi([],true,16,15,F); T.y = fi([],true,16,11,F);
提示
而不是手工输入fimath
属性,您可以使用MATLAB编辑器插入fimath选择。有关更多信息,请参见在GUI构建fimath对象构造函数。
更新测试脚本使用“fixed2”
运行该脚本,然后查看生成的C代码。
短mysum (const短x[10]){短y;int n;y = 0;(n = 0;n < 10;n + +) {y =(短期)(((y < < 4) + x [n]) > > 4);}返回y;}
生成的代码效率更高,但是y
转移到结合吗x
失去了4位的精度。
解决这个精度损失,更新单词的长度y
32位,保持15位的精确对齐x
。
在myTypes.m
,添加一个“fixed32”
案例:
案件的fixed32 F = fimath (“RoundingMethod”,“地板”,…‘OverflowAction’,‘包装’,……“ProductMode”、“FullPrecision’,……“SumMode”、“KeepLSB’,……“SumWordLength”, 32岁的……“CastBeforeSum”,真正的);T.x= fi([],true,16,15,F); T.y = fi([],true,32,15,F);
更新测试脚本使用“fixed32”
并再次运行脚本来生成代码。
现在,生成的代码是非常有效的。
int mysum (const短x [10]) {int y;int n;y = 0;(n = 0;n < 10;n + +) {y + = x [n];}返回y;}
有关更多信息,请参见优化算法。