Форматированный вывод с ведущими нулями в Fortran
У меня есть некоторые десятичные числа, которые мне нужно записать в текстовый файл с ведущими нулями, когда это необходимо. Я сделал некоторые исследования по этому поводу, и все, что я видел, предлагает что-то вроде:
REAL VALUE
INTEGER IVALUE
IF (VALUE.LT.0) THEN
IVALUE = CEILING(VALUE)
ELSE
IVALUE = FLOOR(VALUE)
ENDIF
WRITE(*,1) IVALUE, ABS(VALUE)-ABS(IVALUE)
1 FORMAT(I3.3,F5.4)
Как я понимаю, части IF
и ABS
должны позволить этому работать для всех значений на -100 < VALUE < 1000. Если я установил VALUE = 12.3456
, вышеприведенный код должен вывести "012.3456" в качестве вывода, и это произойдет. Однако, если у меня есть что-то вроде VALUE = -12.3456
, я получаю "(3 звездочки).3456" в качестве вывода. Я знаю, что звездочки обычно появляются, когда в выражении FORMAT
недостаточно символов, но в этом примере должно быть достаточно 3 (1 символ для "-" и два символа для "12" ). Я еще не тестировал это с чем-то вроде VALUE = -9.876
, но я ожидаю, что результат будет "-09.8760".
Что-то не так в моем понимании того, как это работает? Или существует ли какое-то другое ограничение этой техники, которое я нарушаю?
UPDATE: Хорошо, я изучил это еще немного, и это похоже на комбинацию отрицательного значения и формата I3.3
. Если VALUE является положительным, и у меня есть I3.3
, он будет ставить ведущие нули, как ожидалось. Если VALUE отрицательный, и у меня есть только I3
в качестве моего формата, я получаю правильный вывод значения, но он будет дополнен пробелами перед отрицательным знаком вместо заполнения нулями после отрицательного значения (так что -9.8765 выводится как "- 9.8765", но это ведущее пространство ломает то, что я использую .txt файл, так что это неприемлемо).
Ответы
Ответ 1
Проблема заключается в дескрипторе редактирования целочисленных данных. С I3.3
вам требуется не менее 3 цифр, а ширина поля равна 3. Нет знака минус. Используйте I4.3
или, в Fortran 95 и выше, I0.3
.
Ответ на ваше редактирование: используйте I0.3
, он использует минимальное количество необходимых символов.
Но, в конце концов, вы, вероятно, захотите этого: WRITE(*,'(f0.3)') VALUE
Ответ 2
Конечно, я мог бы получить то, что искал, немного изменив его на
REAL VALUE
INTEGER IVALUE
IF (VALUE.LT.0) THEN
WRITE(*,1) FLOOR(ABS(IVALUE)), ABS(VALUE)-FLOOR(ABS(VALUE))
1 FORMAT('-',I2.2,F5.4)
ELSE
WRITE(*,2) FLOOR(VALUE), ABS(VALUE)-FLOOR(BS(VALUE))
2 FORMAT(I3.3,F5.4)
ENDIF
Но это чувствует себя намного clunkier, и на самом деле я попытаюсь написать несколько значений в одной строке, что приведет к действительно беспорядочным блокам IF
или сложному движению курсора, которые я бы хотел избегайте, если это вообще возможно.
Ответ 3
как еще один способ скинуть кошку. Я бы предпочел не делать арифметические данные, а просто работать с форматом:
character*8 fstring/'(f000.4)'/
val=12.34
if(val.gt.1)then
write(fstring(3:5),'(i0)')6+floor(log10(val))
elseif(val.lt.-1)then
write(fstring(3:5),'(i0)')7+floor(log10(-val))
elseif(val.ge.0)
write(fstring(3:5),'(i0)')6
else
write(fstring(3:5),'(i0)')7
endif
write(*,fstring)val
просто для удовольствия с современным fortran, который поддерживает функции символов, которые вы можете свернуть в функции, и в итоге получится такая конструкция:
write(*,'('//fstring(val1)//','//fstring(val2)//')')val1,val2