2015-01-02 2 views
3

Я новичок в программировании в Фортране. В настоящее время я использую cygwin и компилятор gfortran, работающий на моем ПК под управлением Windows XP. У меня трудности с какой-то простой математикой - программа, которую я написал, просто не будет делать математику. Код:Простая математическая ошибка в gfortran?

program convert 
real t 

t=0 
t=8320671.25 - 8000000.00 

write(*,*) t 
end 

Программа должна дать мне ответ «320671.25», но вместо этого дает мне 320671.00! Что я делаю неправильно?

ответ

3

Вы столкнулись с единственным пределом точности. Результатом вычитания является real*4, и его можно безопасно хранить в t. Значения , используемые в вычитании, однако, находятся за пределами диапазона real*4. Снаружи в диапазоне точности, в результате чего числа округляются до соответствия real*4 перед вычислением вычитания.

Попробуйте это, например:

program convert 
real t 

t=0 
t=8320671.25_8 - 8000000.00_8 

write(*,*) t 
end 

Прилагаемый _8 обеспечивает два числа двойной точности; результат затем преобразуется в реальный, прежде чем назначается t, но расчет теперь в двойной точности, и .25 «сохраняется» при вычитании.

+0

Thanks Evert! Это сработало! –

+0

Предполагая, что _8 означает, что 8 байтов кажутся скорее угрозой портабельности, чем использование «двойной точности». – agentp

+1

Чтобы быть справедливым, этот ответ был создан до того, как я добавил общий [tag: fortran]. Хотя он менее портативен (и даже если писать для gfortran, будучи портативным, это хорошо), это объясняет, почему возникает проблема. См. [M. Ответ С. Б.] (http://stackoverflow.com/a/27746544/3157076) для переносного способа. – francescalus

0

Хотя это не имеет значения для примера вы дали, если бы была больше разницы в величинах операндов, замените

real t 

с

double precision t 

В противном случае, разница была бы усечен до доступного хранилища.

Для вашего примера точность констант слишком мала. Значение с плавающей запятой, указанное как у вас (8320671.25 и 8000000.00), имеет тип real, который определяет «одиночную точность»: используется 32-битное представление значений с плавающей запятой, которые эквивалентны 6 to 7 decimal digits of precision. Double precision (с 1980-х годов) обычно представляет собой 64-битное представление с плавающей запятой, эквивалентное 15 to 17 decimal digits. Однако некоторые реализации могут выбрать для реализации double precision то же, что и real, хотя на совместимых с IEEE-754 машинах он обычно больше.

Чтобы сделать плавающей точкой постоянной двойной, написать D для показателя:

t = 8320671.25D0 - 8000000.00 

Заметим, что делает последующие операнды double precision не будет работать из-за выражения печатая правил языка Fortran:

t = 8320671.25 - 8000000.00D0 ! Wrong! Result is "real" 

или

t = 8320671.25 - 8D6   ! Wrong! Result is "real" 

Первый пример выводит результат 320671.250. Другие производят 320671.000 (если t - тип real) или 320671.00000000000, если t - тип double precision.

С 1940-х годов Fortran был реализован на различных архитектурах. На некоторых из них (например, VAX) параметры компиляции командной строки определяют, какой тип аппаратного обеспечения используется для real и для double precision. Архитектура DEC имела по крайней мере четыре разновидности с плавающей запятой (F-Float, D-Float, G-Float и H-Float), все из которых были разработаны задолго до IEEE-754. См. this для некоторой исторической перспективы развития IEEE-754.

+3

Нет, не используйте 'double precision'. Стандарт никогда не гарантировал предоставление 64-битных реалов, хотя большинство современных компиляторов действительно реализуют его как таковые. Гораздо лучше использовать либо явные 'kind', либо использовать ассоциированные стандартные параметры, такие как 'real64', определенные во внутреннем модуле' iso_fortran_env'. –

+1

немного суровый для downvote, учитывая пример, не обязательно должен быть 64 бит. – agentp

+0

@HighPerformanceMark: True. Реализация Cyber ​​использовала 60 бит для 'real' и' double precision'. Тип, используемый для предотвращения усечения, не должен быть гарантированно каким-либо конкретным размером, просто больше, чем во избежание того, что, очевидно, является 32-битным поплавком. – wallyk

2

Вот пример работы с использованием предложения High Performance Mark. Тип «8» - это не переносимый способ задания повторений двойной точности. Большинство компиляторов теперь поддерживают типы среды ISO Fortran, используемые в этом примере. Если у вас старый компилятор, вы можете использовать ISO_C_BINDING и тип c_double, которые были доступны дольше. Как сделал Эверт, важно указать типы констант. Расчет выполняется на RHS, затем присваивание производится переменной на LHS. Недостаточно, чтобы переменная на LHS имела достаточную точность.

program convert 

use, intrinsic :: ISO_FORTRAN_ENV 

real (real64) :: t 
t=8320671.25_real64 - 8000000.00_real64 
write(*,*) t 

end program convert 
Смежные вопросы