LINUX.ORG.RU

Fortran странно складывает числа

 


0

3

Есть большой и длинный код, а в нем фрагмент:


function conv_check_2() result(diff_max)
	use globals
	implicit none
	real(8) diff_max
	real(8) :: diff, t1, t2, t3, t4	

	do i=2, nx-1		
		t1 = -get_n1(i, I_tilde(i))*A_emission
		t2 =  I_tilde(i)*(get_n0(i, I_tilde(i))*B01 - get_n1(i, I_tilde(i))*B10) 
		t3 = V01(i)*get_n0(i, I_tilde(i))*v_dens_e(i) 
		t4 = -V10(i)*get_n1(i, I_tilde(i))*v_dens_e(i)			
		diff =  t1 +t2 + t3 + t4
		write(*, '(5es16.8e3)') t1, t2, t3, t4,  diff

<...>

Последняя строчка выдает следующее: -4.47171865E+010 4.45362655E+010 1.80922022E+008 -1.04464889E+003 7.98239194E-006

То есть сумма намного меньше одного. Если те же самые числа сложить отдельно, используя тот же компилятор, то в сумме получается 6.51351074E+002. Что, ясное дело, и есть правильный ответ. Проверял gdb, действительно t1, t2, t3, t4 равны тому, чему и должны быть равны, а сумма их и вправду меньше одного. Как такое в принципе возможно? Почему одна и та же сумма, посчитанная в разных местах, равна разным числам? Я уже даже не представляю, куда смотреть в поисках ошибки.

★★★★

-4.47171865E+010 4.45362655E+010 1.80922022E+008 -1.04464889E+003

6.51351074E+002. Что, ясное дело, и есть правильный ответ

Странно, у меня их сумма порядка -22.6 получилась, но никак не 651. Складывал правда в табличном процессоре. В питоне столько же вышло. Результат хоть и зависит от порядка сложения, но меняется в 6-м знаке.

grem ★★★★★
()
Последнее исправление: grem (всего исправлений: 2)

Когда складываете отдельно, надо писать -4.47171865D+010 4.45362655D+010 1.80922022D+008 -1.04464889D+003 7.98239194D-006

Литералы с «E» — это real, которые обрезаются, а потом приводятся к double precision.

anonymous
()

Но скорее всего просто точности не хватает, т.к. сумма первых двух очень близка к значению третьего.

grem ★★★★★
()
Ответ на: комментарий от anonymous

В Большом коде числа объявлены real(8), то есть двойной точности. См. фрагмент.

hotpil ★★★★
() автор топика
Ответ на: комментарий от grem

Я складывал в столбик на бумажке и у меня получилось 651 примерно.

hotpil ★★★★
() автор топика
Ответ на: комментарий от quickquest

Очень остроумно. Если бы дело было в стандарте, то ответы везде были бы одинаковые, пусть и не правильные. Но сложение тех же чисел, с тем же компилятором, но в маленькой программке, которая ничего, кроме этого сложения не делает, дает другой, правильный ответ.

hotpil ★★★★
() автор топика
Ответ на: комментарий от hotpil

Если бы дело было в стандарте, то ответы везде были бы одинаковые

§9. Проблемы компьютерных вычислений, вызванные использованием стандарта IEEE754 (внизу вышеупомянутого стандарта).

quickquest ★★★★★
()
Ответ на: комментарий от quickquest

1d12 - не такое уж большое число, ему далеко до границы, про которую там говориться.

hotpil ★★★★
() автор топика

Если кому интересно, вот правильный ответ. Следующий код его демонстрирует:

program demo

real(8) u1, u2, u3, u4, u
real(8) t1, t2, t3, t4, t
t1 = -0.447171D+011
t2 = 0.4453626D+011
t3 = 0.1809220D+009
t4 = -0.104464D+004

t = t1+t2+t3+t4
write(6, '(5es16.8)') t1, t2, t3, t4, t

u1 = -0.447171865016260D+011
u2 = 0.445362655242332D+011
u3 = 0.180922022041715D+009
u4 = -0.104464886130413D+004

u = u1+u2+u3+u4
write(6, '(5es16.8)') u1, u2, u3, u4, u

end program

Результат:

 -4.47171000E+10  4.45362600E+10  1.80922000E+08 -1.04464000E+03  8.09553600E+04
 -4.47171865E+10  4.45362655E+10  1.80922022E+08 -1.04464886E+03  5.43145281E-05

То есть учитывая дополнительные знаки после запятой, получается разница в сумме аж на 9 порядков! Неожиданно, но правда.

hotpil ★★★★
() автор топика
Ответ на: комментарий от hotpil

Ничего неожиданного, я же писал, что ты складывает близкие по значению но разные по знаку числа, из-за этого и выползает ошибка из-за недостаточной точности представления. А их сумма опять же близка по модулю третьему числу и имеет другой знак.

grem ★★★★★
()
Последнее исправление: grem (всего исправлений: 1)
Ответ на: комментарий от grem

Неожиданно что разница аж в 9 порядков.

hotpil ★★★★
() автор топика
26 декабря 2017 г.

Попробуй посмотреть(!!!) свои (одни и те же) числа по формату

write(*, '(5es20.12e3)') t1, t2, t3, t4, diff

и

write(*, '(5es16.4e3)') t1, t2, t3, t4, diff

Программа суммирует реальные числа в переменных, а не то, что напечатано.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.