Точность расчетов

Я делаю расчет на Фортране для переменной двойной точности, и после расчета переменная получает значение -7.217301636365630e-24.

Однако, когда я делаю те же вычисления в Matlab, переменная просто получает значение 0. Есть ли способ повысить точность MatLAB при выполнении вычислений, чтобы я также мог получить что-то порядка 7e-24?

В идеале это было бы то, что я мог бы применить ко всем вычислениям в скрипте, а не только к одной переменной. Что-то похожее на использование format long.

Для меня такая точность имеет решающее значение, поскольку мне нужно определить, действительно ли переменная отрицательна или нет.


Я добавил код. Он довольно длинный, но я не мог его урезать, не отбрасывая переменные и их точность. Последний член, Ax(i,:,:), я хотел бы иметь очень высокой точностью. Таким образом, важные вещи появляются только в последней строке.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% CONSTANTS
clc
clear all

sym_weight     = [4/9, 1/9,1/9,1/9,1/9, 1/36,1/36,1/36,1/36];


dir_x  = [  0,   1,  0, -1,  0,    1,  -1,  -1,   1];
dir_y  = [  0,   0,  1,  0, -1,    1,   1,  -1,  -1];



ly = 11; lx = ly;
xC = 5; yC=xC;    

density_high = 1.0;
density_low = 0.1;
radius  = 2;
interface_w = 1;
sigma_st = 0.0001;


beta  = 12*sigma_st/(interface_w*(density_high-density_low)^4);
kappa = 1.5*sigma_st*interface_w/(density_high-density_low)^2;





saturated_density = 0.5*(density_high+density_low);
for x=1:lx
    for y=1:ly
        for i=1:9
            fIn(i, x, y) = sym_weight(i)*density_high;
            gIn(i, x, y) = 3*sym_weight(i);

            test_radius = sqrt((x-xC)^2 + (y-yC)^2);
            if(test_radius <= (radius+interface_w))
                fIn(i, x, y) = sym_weight(i)*( saturated_density - 0.5*(density_high-density_low)*tanh(2*(radius-sqrt((x-xC)^2 + (y-yC)^2))/interface_w) );
            end
        end
    end
end




density_2d = ones(lx)*saturated_density;
for i=1:lx
    density_aux(:,:,i) = abs(density_2d(:, i)');
end



density_local             = sum(fIn);
L_density_local           = (+1.0*(circshift(density_local(1,:,:), [0, +1, +1]) + circshift(density_local(1,:,:), [0, -1, +1]) + circshift(density_local(1,:,:), [0, +1, -1]) + circshift(density_local(1,:,:), [0, -1, -1])) + ...
                             +4.0*(circshift(density_local(1,:,:), [0, +1, +0]) + circshift(density_local(1,:,:), [0, -1, +0]) + circshift(density_local(1,:,:), [0, +0, +1]) + circshift(density_local(1,:,:), [0, +0, -1])) + ...
                             -20.0*density_local(1,:,:));
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%




chem_pot   = 4*beta*(density_local-density_low).*(density_local-density_high).*(density_local-density_aux) - kappa*L_density_local/6;






for i=3
    Ax(i,:,:)            =     (+circshift(chem_pot(1,:,:), [0,-2*dir_x(i),-2*dir_y(i)]) -             chem_pot(1,:,:));                                          
end 

person BillyJean    schedule 25.04.2015    source источник
comment
Вы должны будете показать нам свой код. Числа этого диапазона не должны быть проблемой вообще.   -  person beaker    schedule 25.04.2015
comment
@beaker Это очень длинный сценарий. Я могу попробовать сделать минимальный пример, если это требуется. Я думал, что это можно исправить с помощью простой команды, такой как format long   -  person BillyJean    schedule 25.04.2015
comment
format long повлияет только на отображение числа, а не на его значение. Я предполагаю, что вы уже сделали это, и он все еще отображает 0.   -  person beaker    schedule 25.04.2015
comment
@стакан Это правда. Я попытаюсь сделать небольшой пример, потому что реальный код очень длинный. Я также выполняю вычисления для многих переменных, и всем им нужна такая высокая точность, поэтому было бы неплохо использовать одну команду (если она существует).   -  person BillyJean    schedule 25.04.2015
comment
Если вы еще этого не делаете, сделайте ваши переменные удвоенными. Где-то в расчетах должно быть где-то, что промежуточное значение устанавливается равным 0.   -  person beaker    schedule 25.04.2015
comment
Matlab уже выполняет вычисления по умолчанию для значений двойной точности ... единственный способ повысить точность - использовать арифметика переменной точности   -  person Hoki    schedule 25.04.2015
comment
@beaker Я думал, что они по умолчанию двойные? Если нет, то как мне установить переменную в double?   -  person BillyJean    schedule 25.04.2015
comment
your_variable=double(your_variable) будет следить за тем, чтобы они считались двойными (но это действительно тип по умолчанию, если вы не укажете что-то еще)   -  person Hoki    schedule 25.04.2015
comment
@Hoki Я добавил небольшой пример кода, показывающий термин, в котором что-то идет не так. Спасибо   -  person BillyJean    schedule 25.04.2015
comment
Итак, все, что находится перед последними четырьмя или пятью строками, создает одинаковые значения с плавающей запятой в FORTRAN и Matlab? Имейте в виду, что такие функции, как abs, sqrt, tanh и т. д. (и даже деление), возможно, не будут давать идентичный вывод с плавающей запятой для одних и тех же входных данных на разных языках. Суммирование членов в другом порядке также может привести к другому результату. Я также предполагаю, что вы подтвердили, что эта проблема не связана с ошибкой ни в одной из версий.   -  person horchler    schedule 25.04.2015
comment
@horchler да, до 19-го знака после запятой. Когда я выполняю команду найти Ax, некоторые элементы Ax округляются до 0 в MatLAB, но имеют значения порядка 1e-24 в Фортране. Кроме того, просто невозможно, чтобы запись Ax была равна 0, если подумать о том, как она устроена математически. Маленький да, но не 0.   -  person BillyJean    schedule 25.04.2015
comment
@Hoki Спасибо, что взглянули на это. Я использую i=3, поэтому он должен сместиться   -  person BillyJean    schedule 25.04.2015
comment
@Hoki Когда я вывожу запись из density, после этого я получаю только 9 цифр. Если я использую, например, vpa(density(1,1,1), 25), он добавляет 25 цифр. Как я могу сделать 25 цифр по умолчанию для всех переменных в скрипте?   -  person BillyJean    schedule 25.04.2015
comment
извините за путаницу по поводу i. Тем не менее, если вы посмотрите на первый член двух ваших членов (тот, что с циркульным сдвигом, и прямой), там много равных членов (я насчитал 49). Поэтому, если эти термины должны быть разными, точность теряется не во время последнего вычитания, а раньше. Я не знаком с vpa, но полагаю, вам придется объявлять все важные переменные по отдельности.   -  person Hoki    schedule 25.04.2015


Ответы (1)


Вы не показали код Фортрана, но имейте в виду, что в Фортране, когда вы делаете это:

 density_low = 0.1

Литерал 0.1 имеет одинарную точность, независимо от типа density_low. Все эти литералы должны быть выражены как 0.1D0 или 0.1_k, где k — соответствующее целое число.

(Извините, если вы это знали, но это распространенная ошибка)

person agentp    schedule 26.04.2015