如何在 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
。
所以是后者。
我想更改 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
%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
。
所以是后者。