Форматированный вывод с ведущими нулями в 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