Есть ли в Fortran 90 лучшее назначение с двойной точностью?

В Fortran 90 (с использованием gfortran в Mac OS X), если я присваиваю значение переменной с двойной точностью без явной привязки к типу, точность не «принимается». Я имею в виду, если я запустил следующую программу:

program sample_dp

implicit none

integer, parameter :: sp = kind(1.0)
integer, parameter :: dp = kind(1.0d0)

real(sp) :: a = 0.
real(dp) :: b = 0., c = 0., d = 0.0_dp, e = 0_dp

! assign values
a = 0.12345678901234567890
b = 0.12345678901234567890
c = DBLE(0.12345678901234567890)
d = 0.12345678901234567890_dp

write(*,101) a, b, c, d
101 format(1x, 'Single precision: ',  T27, F17.15, / &
           1x, 'Double precisison: ', T27, F17.15, / &
           1x, 'Double precision (DBLE): ', T27, F17.15, / &
           1x, 'Double precision (_dp): ',  T27, F17.15)

end program

Получаю результат:

Single precision:        0.123456791043282
Double precision:        0.123456791043282
Double precision (DBLE): 0.123456791043282
Double precision (_dp):  0.123456789012346

Результат с одинарной точностью начинает округляться с 8-го десятичного знака, как и ожидалось, но только переменная с двойной точностью, которую я явно назначил с помощью _dp, сохраняет все 16 цифр точности. Это кажется странным, поскольку я ожидал (я относительно новичок в Фортране), что переменная с двойной точностью автоматически будет иметь двойную точность. Есть ли лучший способ назначить переменные с двойной точностью или мне нужно явно ввести их, как указано выше?


person tomshafer    schedule 26.05.2011    source источник
comment
Обратите внимание, что инициализация переменной e выполняется с помощью целочисленной константы; 0_dp относится к целочисленному типу с числом вида dp. К сожалению, во многих компиляторах числа типа вещественных и целых чисел перекрываются, поэтому вы не получите ошибку времени компиляции из-за ошибки (я предполагаю, что это было непреднамеренно).   -  person eriktous    schedule 27.05.2011


Ответы (2)


Действительное число, не помеченное как двойная точность, будет считаться одинарной точностью. Просто потому, что через некоторое время вы присваиваете его переменной двойной точности или конвертируете в двойную точность, это не означает, что значение будет «волшебным» иметь двойную точность. Он не заглядывает вперед, чтобы увидеть, как это значение будет использовано.

person MRAB    schedule 26.05.2011
comment
Значит, вы имеете в виду, что тот факт, что я присваиваю значение контейнеру с двойной точностью, не имеет значения, если я явно не скажу, что это значение с двойной точностью? - person tomshafer; 27.05.2011
comment
Правильный. Как я уже сказал, не стоит заглядывать в будущее, чтобы увидеть, как это значение будет использовано позже. Он видит настоящий литерал, он не помечен как двойная точность, поэтому предполагает его одинарную точность. - person MRAB; 27.05.2011
comment
@tomshafer: важно получить четкое представление о том, как оценивается оператор присваивания. Во-первых, RHS оценивается полностью в соответствии с правилами приоритета; на каждом шаге, если это выражение в смешанном режиме, выполняется необходимое неявное преобразование типа. Только после полной оценки RHS результат присваивается LHS, опять же с неявным преобразованием типа, если это необходимо. - person eriktous; 27.05.2011
comment
Спасибо, ребята, в этом гораздо больше смысла. - person tomshafer; 27.05.2011

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

Как заявил MRAB в своем правильном ответе, выражение всегда вычисляется без какого-либо контекста, поэтому

 0.12345678901234567890

является плавающим литералом по умолчанию (одинарной) точности, независимо от того, где он появляется. То же самое и с числами с плавающей запятой в экспоненциальной форме.

 0.12345678901234567890E0

это также число точности по умолчанию.

Если кто-то хочет использовать константу двойной точности, можно использовать D вместо E в приведенной выше форме. Даже если такая константа двойной точности присваивается переменной точности по умолчанию, она сначала обрабатывается как число двойной точности, а затем преобразуется в точность по умолчанию.

То, как вы используете в своем вопросе (с использованием обозначения вида и нескольких констант вида), является более общим и современным, но принцип тот же.

 0.12345678901234567890_sp

является числом вида sp и

 0.12345678901234567890_dp

является числом вида dp, и не имеет значения, где они появляются.

Как показывает ваш пример, дело не только в назначении. В соответствии

 c = DBLE(0.12345678901234567890)

сначала число 0.12345678901234567890 - точность по умолчанию. Затем он преобразуется в двойную точность с помощью DBLE, но это делается после того, как некоторые цифры уже потеряны. Затем этот новый номер двойной точности присваивается c.

person Vladimir F    schedule 06.03.2017
comment
Этот вопрос является повторяющейся целью для многих похожих вопросов, и это дополнительное объяснение полезно. - person Ross; 08.03.2017