如何在 MATLAB 中更改浮点运算的舍入模式?

How to change the rounding mode for floating point operations in MATLAB?

我想更改 MATLAB 中浮点运算的舍入模式。根据IEEE 754-2008,舍入有5种策略:

MATLAB支持这5种策略吗?如何在MATLAB中更改浮点运算的舍入模式?

回答

有点。有一个未记录的 feature('setround') 函数调用,您可以使用它来获取或设置 Matlab 使用的舍入模式。

所以,可以做,但不应该做。 :)

WARNING: This is an undocumented, unsupported feature! Use at your own peril!

这个 feature('setround') 支持 5 种 IEEE-754 舍入模式中的 4 种:只有一种“最近”模式,我不知道它是“与偶数相关”还是“与零相关” .

支持的模式:

  • feature('setround') – 获取当前舍入模式
  • feature('setround', 0.5) – 向最近的舍入(不知道它是否与零相关或远离零)
  • feature('setround', Inf) – 向上舍入(朝向 +Inf)
  • feature('setround', 0) – 向零舍入
  • feature('setround', -Inf) – 向下舍入(向-Inf)

测试注意事项:IEEE-754 舍入模式不影响 round() 及其亲属。相反,它控制算术运算在浮点精度限制附近的行为方式。

示范[​​=35=]
%ROUNDINGEXAMPLE Demonstrates IEEE-754 Rounding Mode control
%
% This uses a completely undocumented and unsupported feature!
% Not for production use!

%% Setup
clear; clc

n = 2000;
X = ones(n)*1E-30; % matrix with n^2 elements
defaultRoundingMode = feature('setround'); % store default rounding mode

%%
feature('setround',0.5);
r1 = prettyPrint('Nearest', sum(X(:)));
%{
  sign   exponent                       mantissa
     0 01110110001 0011010101111100001010011001101001110101010000011110
     | \_________/ \__________________________________________________/
     |      |             ______________________|___________________________
     |      |            /                                                  \
(-1)^0 2^( 945 - 1023) 1.0011010101111100001010011001101001110101010000011110 = 4e-24
%}

%%
feature('setround',-Inf);
r2 = prettyPrint('To -Infinity', sum(X(:)));
%{
  sign   exponent                       mantissa
     0 01110110001 0011010101111100001010011001101001011100000111000110
     | \_________/ \__________________________________________________/
     |      |             ______________________|___________________________
     |      |            /                                                  \
(-1)^0 2^( 945 - 1023) 1.0011010101111100001010011001101001011100000111000110 = 4e-24
%}

%%
feature('setround',Inf);
r3 = prettyPrint('To Infinity', sum(X(:)));
%{
  sign   exponent                       mantissa
     0 01110110001 0011010101111100001010011001101010100011101100100001
     | \_________/ \__________________________________________________/
     |      |             ______________________|___________________________
     |      |            /                                                  \
(-1)^0 2^( 945 - 1023) 1.0011010101111100001010011001101010100011101100100001 = 4e-24
%}

%%
feature('setround',0);
r4 = prettyPrint('To zero', sum(X(:)));
%{
  sign   exponent                       mantissa
     0 01110110001 0011010101111100001010011001101001011100000111000110
     | \_________/ \__________________________________________________/
     |      |             ______________________|___________________________
     |      |            /                                                  \
(-1)^0 2^( 945 - 1023) 1.0011010101111100001010011001101001011100000111000110 = 4e-24
%}

%%
feature('setround',defaultRoundingMode);
r5 = prettyPrint('No accumulated roundoff error', 4e-24);
%{
  sign   exponent                       mantissa
     0 01110110001 0011010101111100001010011001101010001000111010100111
     | \_________/ \__________________________________________________/
     |      |             ______________________|___________________________
     |      |            /                                                  \
(-1)^0 2^( 945 - 1023) 1.0011010101111100001010011001101010001000111010100111 = 4e-24
%}

%% Helper function
function r = prettyPrint(s, r)
    fprintf('%s:\n%65.60f\n\n', s, r); 
end

我得到:

Nearest:
   0.000000000000000000000003999999999966490758963870373537264729

To -Infinity:
   0.000000000000000000000003999999999789077070014108839608005726

To Infinity:
   0.000000000000000000000004000000000118618095059505975310731249

To zero:
   0.000000000000000000000003999999999789077070014108839608005726

No accumulated roundoff error:
   0.000000000000000000000003999999999999999694801998206811298525

致谢

感谢 MathWorks 技术支持的 Ryan Klots 让我明白这一点并提供了很好的演示代码!

@HYF:我发现 feature('setround', 0.5) 导致四舍五入。 我检查了以下内容: a=1+2^-52 这意味着尾数看起来像这样: 1.0...01 其中最后一个 1 仍在尾数中。前导 1 不以 IIIE754 格式存储。 (我检查了 1+2^-52 == 1 但没有 1+2^-53 == 1

然后我计算了b = a + 2^-53。 如果不四舍五入,则 1.0...01|1 最后一位要四舍五入。 我发现以下内容为真:b==1+2^-51 我们有 b == 1.0...010.

我们有几种四舍五入模式的子模式: 这可以舍入到 inf、从 0 舍入或舍入到偶数。

接下来我们检查 -b==-1-2^-51 是否为真,这排除了到 inf 的舍入 仍然允许从 0 舍入或舍入到偶数。

然后我检查了1.5==1.5+2^-53
当然 1.5 = 1.10...0 二进制和 和 1.5+2^-53 = 1.10...0|1 没有四舍五入,最后一位要四舍五入。 从 0 舍入为 1.10...01 四舍五入为 1.10...0。 所以是后者。