主要内容

手动转换浮点MATLAB算法不动点

这个例子展示了如何将一个浮点算法定点,然后生成C代码的算法。示例使用以下最佳实践:

  • 单独的算法从测试文件。

  • 准备你的仪表和代码生成算法。

  • 管理数据类型和控制增长。

  • 单独的数据类型定义从算法的代码创建一个表的数据定义。

最佳实践的完整列表,请参阅手工定点转换的最佳实践

单独的算法从测试文件

写一个MATLAB®函数,mysum,和一个向量的元素。

函数y = mysum (x) y = 0;n = 1:长度(x) y = y + x (n);结束结束

因为你只需要算法部分转换为定点,这样代码结构更为高效的算法,核心处理,你做的是独立于测试文件。

编写一个测试脚本

在测试文件,创建您的输入,调用算法,绘制结果。

  1. 写一个MATLAB脚本,mysum_test,验证你的算法使用双数据类型的行为。

    n = 10;rng默认的兰德(n, 1) x = 2 * 1;%的算法y = mysum (x);%验证结果y_expected =总和(双(x));呃= (y)——y_expected两倍

    rng违约的设置使用的随机数生成器rand函数其默认值,以便它产生的随机数如果你重启MATLAB。

  2. 运行测试脚本。

    mysum_test
    呃= 0

    获得的结果使用mysum使用MATLAB与获得总和函数。

有关更多信息,请参见创建一个测试文件

准备工具和代码生成算法

在你的算法,函数签名后,添加% # codegen编译指令表明你打算仪器算法和生成C代码。添加这个指令指示MATLAB代码分析器来帮助您诊断和解决违规,将导致错误在仪表和代码生成。

函数y = mysum (x)% # codegeny = 0;n = 1:长度(x) y = y + x (n);结束结束

对于该算法,代码分析器指示器在编辑器窗口的右上角绿色告诉你,它没有发现任何问题。

有关更多信息,请参见准备加速算法代码或代码生成

为您的原始算法生成C代码

为原算法生成C代码来验证该算法适用于代码生成和浮点C代码。使用codegen(MATLAB编码器)函数(需要MATLAB编码器™)来生成一个C库。

  1. 添加以下行结束您的测试脚本生成C代码mysum

    codegenmysumarg游戏{x}配置:自由报告

  2. 再次运行测试脚本。

    MATLAB编码器生成C代码mysum功能和提供了一个链接到代码生成报告。

  3. 点击链接打开代码生成报告并查看生成的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声明为双。

管理数据类型和控制增长

测试你的算法与单打检查类型不匹配

  1. 修改您的测试文件,这样的数据类型x是单身。

    n = 10;rng默认的x =单(2 *兰德(n, 1) 1);%的算法y = mysum (x);%验证结果y_expected =总和(双(x));呃=双(y) - y_expected codegenmysumarg游戏{x}配置:自由报告

  2. 再次运行测试脚本。

    mysum_test
    呃= -4.4703 e-08 ? ? ?这个作业写一个单一的值为“双”类型。通过赋值代码生成不支持改变类型。金宝app检查前的作业输入类型规格类型不匹配。

    代码生成失败,报告数据类型不匹配y = y + x (n);

  3. 查看错误,打开报告。

    在报告中,在直线上y = y + x (n)这份报告强调了y左边的作业用红色表明有一个错误。问题是,y被声明为一但被分配到一个。y + x (n)是一个双重的总和,一个是一个。如果你把你的光标在变量和表达式在报告中,你可以看到他们的类型的信息。在这里,你可以看到表情,y + x (n)是一个单身。

  4. 修复类型不匹配,更新你的算法使用下标赋值元素的总和。改变y = y + x (n)(,)= y + x (n)

    函数y = mysum (x)% # codegeny = 0;n = 1:长度(x) y (:) = y + x (n);结束结束

    使用下标赋值,您也防止一些增长这是默认的行为,当你添加定点数字。有关更多信息,请参见一些增长。防止一些增长是很重要的,因为你想要保持你的定点类型在你的代码。有关更多信息,请参见控制一些增长

  5. 重新生成C代码和开放代码生成报告。在C代码,结果现在投双重解决类型不匹配。

建立仪器的墨西哥人

使用buildInstrumentedMex函数来评价您的日志的最大和最小值算法命名和中间变量。使用showInstrumentationResults函数提出定点基于这些记录值的数据类型。后,你使用这些提议定点类型测试算法。

  1. 更新测试脚本:

    1. 当你声明n,添加buildInstrumentedMex mySum args {0 (n, 1)}直方图

    2. 改变x回到双。取代x =单(2 *兰德(n, 1) 1);兰德(n, 1) x = 2 * 1;

    3. 而不是调用原始算法中,调用生成的墨西哥人的功能。改变y = mysum (x)y = mysum_mex (x)

    4. 调用墨西哥人函数后,添加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}配置:自由报告

  2. 再次运行测试脚本。

    showInstrumentationResults提出了数据类型和函数打开一个报告来显示结果。

  3. 在报告中,单击变量选项卡。showInstrumentationResults提出了一种分数13的长度y和15x

在报告中,您可以:

  • 查看模拟输入最小和最大值x和输出y

  • 查看该数据类型xy

  • 查看所有变量的信息,中间结果,代码中的表达式。

    查看这些信息,将您的鼠标停留在变量或表达式在报告中。

  • 查看直方图数据xy帮助你识别精度范围外的任何值或低于基于当前数据类型。

    要查看一个特定变量的直方图,单击其直方图图标,

单独的数据类型定义的算法代码

而不是手动修改算法为每个数据类型检查的行为,不同的数据类型定义的算法。

修改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使用类型表。

  1. 第一运行检查表和算法之间的联系使用双打。在你宣布n,添加T = mytypes(“双”);

  2. 更新调用buildInstrumentedMex使用的类型T.x表中指定的数据类型:buildInstrumentedMex mysum args {0 (n, 1,“喜欢”,T.x), T}直方图

  3. x使用的类型T.x中指定的表:x =投(2 *兰德(n, 1) 1,‘喜欢’,T.x);

  4. 调用函数传入墨西哥人T:y = mysum_mex (x, T);

  5. 调用codegen传入T:codegen mysum args {x T}配置:自由报告

    这是更新后的测试脚本。

    % %建立仪器的墨西哥人T = mytypes (“双”);n = 10;buildInstrumentedMexmysumarg游戏{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}配置:自由报告

  6. 运行测试脚本,并点击链接打开代码生成报告。

    生成的C代码是一样的原始算法生成的代码。因为这个变量T用于指定类型和这些类型在代码生成时间常数;T不使用在运行时,不出现在生成的代码中。

生成定点代码

更新测试脚本以使用定点类型提出了早些时候和视图生成的C代码。

  1. 更新测试脚本以使用定点类型。取代T = mytypes(“双”);T = mytypes(固定的);然后保存脚本。

  2. 运行测试脚本和视图生成的C代码。

    这个版本的C代码不是很有效;它包含很多溢出处理。下一步是优化数据类型,避免溢出。

优化数据类型

使用缩放双打来检测溢出

比例之间混合双打浮点和定点数字。定点设计师™将它们存储在双打的缩放、标志和字长信息保留。因为所有的在双精度运算执行,你可以看到发生的任何溢出。

  1. 更新测试脚本使用了双打。取代T = mytypes(固定的);T = mytypes(“缩放”);

  2. 再次运行测试脚本。

    测试使用了双打和显示报告。没有检测到溢出。

    到目前为止,您已经运行测试脚本使用随机输入这意味着它是不可能的,测试执行算法的完整的操作范围。

  3. 找到输入的全部。

    范围(T.x)
    -1.000000000000000 - 0.999969482421875 DataTypeMode:定点:二进制扩展Signedness:签了字:16 FractionLength: 15

  4. 更新的脚本测试的负面边缘情况。运行mysum_mex与原来的随机输入和输入测试完整的范围和总结果。

    % %建立仪器的墨西哥人T = mytypes (“缩放”);n = 10;buildInstrumentedMexmysumarg游戏{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}配置:自由报告

  5. 再次运行测试脚本。

    测试运行和y溢出定点数据类型的范围。showInstrumentationResults提出了一种新的部分的长度11y

  6. 更新测试脚本使用了双打与新提出的类型y。在myTypes.m,“缩放”情况下,T。y= fi([],true,16,11,'DataType','ScaledDouble')

  7. 重新运行测试脚本。

    现在没有溢出。

为该定点类型生成代码

更新的数据类型表使用该定点类型和生成代码。

  1. myTypes.m,“固定”情况下,T。y= fi([],true,16,11)

  2. 更新测试脚本,mysum_test,用T = mytypes(固定的);

  3. 运行测试脚本,然后单击视图报告链接视图生成的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设置

生成的代码效率更高,利用定点数学(fimath)设置更适合C代码生成:包装溢出和地板上舍入。

  1. 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对象构造函数

  2. 更新测试脚本使用“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位的精度。

  3. 解决这个精度损失,更新单词的长度y32位,保持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);

  4. 更新测试脚本使用“fixed32”并再次运行脚本来生成代码。

    现在,生成的代码是非常有效的。

    int mysum (const短x [10]) {int y;int n;y = 0;(n = 0;n < 10;n + +) {y + = x [n];}返回y;}

有关更多信息,请参见优化算法