Как изменить режим округления для операций с плавающей запятой в MATLAB? - PullRequest
6 голосов
/ 15 апреля 2019

Я хочу изменить режим округления для операций с плавающей запятой в MATLAB.Согласно IEEE 754-2008, существует 5 стратегий округления:

  • округление до ближайшего, привязка к четному
  • округление до ближайшего, связывание от нуля
  • округление до нуля
  • округление вверх (к положительной бесконечности)
  • округление вниз (к отрицательной бесконечности)

Поддерживает ли MATLAB эти 5 стратегий?Как изменить режим округления для операций с плавающей запятой в MATLAB?

1 Ответ

3 голосов
/ 20 апреля 2019

Ответ

Вид. Существует недокументированный вызов функции feature('setround'), который вы можете использовать для получения или установки режима округления, используемого Matlab.

Итак, это может быть сделано, но вы не должны этого делать. :)

ВНИМАНИЕ: это недокументированная, неподдерживаемая функция! Используйте на свой страх и риск!

Этот feature('setround') поддерживает 4 из 5 режимов округления IEEE-754: есть только один «ближайший» режим, и я не знаю, «привязан ли он к четному» или «связан с нулем».

Поддерживаемые режимы:

  • feature('setround') - Получить текущий режим округления
  • feature('setround', 0.5) - округлить до ближайшего (не знаю, связано ли оно с четным или нулевым)
  • feature('setround', Inf) - округление вверх (в сторону + Inf)
  • feature('setround', 0) - округлить до нуля
  • feature('setround', -Inf) - округлить вниз (в сторону -Inf)

Примечание по тестированию: режим округления IEEE-754 не влияет на round() и его родственников. Скорее, оно определяет, как арифметические операции ведут себя в пределах точности с плавающей запятой.

Демонстрация

%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 за то, что он прямо мне помог и предоставил хороший демонстрационный код!

...