Можно ли в Fortran печатать данные в табличном виде без потери информации, когда требуется больше места, чем указано?
Например, рассмотрим программу
! format.f90
program main
real(8) :: arr(5)
arr = [0.0, 1.111, 22.22, 333.3, 444444444444444444.44]
print '(F10.3)', arr
end program main
Тогда по умолчанию вывод для последней записи будет заменен звездочками, указывающими на нехватку места.
>> ifort format.f90 -o format.bin
>> ./format.bin
0.000
1.111
22.220
333.300
**********
Для сравнения, спецификаторы формата в стиле C автоматически увеличивают ширину столбца, когда это необходимо, например.
// format.c
#include <stdio.h>
int main () {
double arr[5] = {0.0, 1.111, 22.22, 333.3, 444444444444444444.44};
for(int i=0; i<5; i++) {
printf("%10.3f\n", arr[i]);
}
}
>> gcc format.c -o format.bin
>> ./format.bin
0.000
1.111
22.220
333.300
444444444444444416.000
Можно ли получить такое поведение в Фортране со встроенными функциями?
Варианты, которые не соответствуют требованиям
Дескриптор G. Дескриптор G
позволяет надежно выводить данные в удобном для чтения табличном формате и автоматически добавлять экспоненты при необходимости. Однако это также приводит к пустой трате места, если экспоненциальные числа не нужны и не выстраивают запятую. Например, при переключении F10.3
на G11.4,"¶"
(знак абзаца добавлен для выделения):
>> ifort format.f90 -o format.bin
>> ./format.bin
0.000 ¶
1.111 ¶
22.22 ¶
333.3 ¶
0.4444E+18¶
Создание API форматирования на основе спецификатора F0
. Спецификатор F0.3
разрешает вывод переменной ширины, но не позволяет указывать минимальную ширину. Эту проблему можно решить с помощью функции-оболочки, похожей на leftpad, но встроенное или широко используемое решение было бы предпочтительнее, поскольку у него больше шансов на фактическое использование в кодовой базе. Например:
! format.f90
program main
real(8) :: arr(5)
integer :: i
arr = [0.0, 1.111, 22.22, 333.3, 444444444444444444.44]
! more complicated print statement, because 'float2char'
! cannot be 'elemental' due to needing the 'alloctable' property.
print '(A)', (float2char('(F0.3)', 10, arr(i)), i=1,5)
contains
function float2char(format, width, value) result(r)
character(:), allocatable :: r
character(*), intent(in) :: format
integer, intent(in) :: width
real(8), intent(in) :: value
character(64) :: buffer ! better: calculate size from value?
write(buffer, format) value
allocate(character(max(width, len_trim(buffer))) :: r)
r(:) = trim(buffer) ! (:) needed to prevent reallocation in recent compilers
r(:) = adjustr(r)
end function float2char
end program main
>> ifort format.f90 -o format.bin
>> ./format.bin
.000
1.111
22.220
333.300
444444452740661248.000
F10.3
число222.2
будет напечатано как␣␣␣222.200
, сG10.4
оно будет напечатано как␣␣␣␣␣␣222.2
, а1.111
будет напечатано как␣␣␣␣␣␣1.111
, так что запятая не будет выровнена по одному и тому же столбцу. 06.03.2020