![]() |
|
![]() ![]() ![]() |
|
kamre |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 330 Регистрация: 24.3.2006 Репутация: нет Всего: 13 |
Подскажите, что нужно написать в строке форматирования, чтобы числа выводились так:
Смысл в том, чтобы не было лишних нулей и пробелов. Хотя бы лишние ведущие пробелы то можно убрать? |
|||
|
||||
popovda |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 290 Регистрация: 9.6.2006 Где: Москва Репутация: нет Всего: 6 |
Вот что:
10 format(F8.2) Здесь 8 - общее количество цифр в выводе + дес. точка 2 - кол-во знаков после запятой Лучше так: 10 format('a = ',F8.2) или 10 format(x,F8.2) -------------------- С уважением, Попов Д.А. |
|||
|
||||
kamre |
|
||||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 330 Регистрация: 24.3.2006 Репутация: нет Всего: 13 |
С F8.2 не получается:
А нужно, чтобы было вот так:
Вообще, смысл этого все таков: мне нужно выводить числа в таком виде (11111.22, 22.11111, ...) Так вот, все эти лишние нули и особенно ведущие пробелы очень не красивым такой вывод делают. |
||||
|
|||||
popovda |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 290 Регистрация: 9.6.2006 Где: Москва Репутация: нет Всего: 6 |
Ага. Понял. Нужно выводить числа разной длинны целой и дробной частей, но без лишних пробелов и нулей. А я то на 1-ый пример смотрел и не понял.
Здесь два варианта: 1. Преобразование число->строка. Ну это простая задачка. И есть плюс: это более универсальный подход - можно повторным проходом по строке контролировать вывод лишних нулей в конце числа. 2. По-фортрановски: сгенерировать с помощью внутреннего файла форматную строку. Как это делается можно посмотреть или у Рыжикова (Современный Фортран или Фортран PowerStation для инженеров), или у Бартеньева. Это классический пример. -------------------- С уважением, Попов Д.А. |
|||
|
||||
kamre |
|
||||||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 330 Регистрация: 24.3.2006 Репутация: нет Всего: 13 |
Насчет лишних нулей в конце - ладно, пусть будут.
Сейчас главное убрать лишние пробелы в начале, т.к. это именно они портят весь вид! Про варианты: 1. преобразование самому что-ли предлагается написать? неужели фортран совсем не умеет не выводить лишние ведущие пробелы? может быть есть какие-то дескрипторы, чтобы указать на это? я читал про форматированный ввод-вывод, ничего про это не нашел. 2. т.е. придется подсчитывать количество цифр до запятой (и, возможно, после) и составлять форматную строку? На фортран я перешел с c/c++. И мне не очень понятно, как написать аналог вот такого вывода чисел:
чтобы на экран вывелось:
Добавлено @ 22:07 Ура, ура! Вот оно:
|
||||||
|
|||||||
Cr@$h |
|
||||
![]() Исследователь ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1693 Регистрация: 3.4.2005 Где: Санкт-Петербург, Россия Репутация: 1 Всего: 41 |
Чтобы отводить на число ровно столько знаков, сколько в этом числе есть, нужно знать, сколько знаков после запятой, а сколько до. Плюс не забывать про знак самого числа. Не советую пользоваться метками (а занчит и декларативным оператором format). В Фортране в любых ситуациях можно обойтись без меток и только, наверное, в случае format это может оказаться чуть побольше по коду (например, один и тот же специикатор формата задавать несколько раз в каждом оперторе write. Ну и что. Зато без меток, и лапши нет.).
Фактически, да. И в этом тебе тут помогут. Пиши "такой же" дескриптор: f0.5 ![]() Спасибо за задачку. Я ещё подумаю. Даже странно, что в тему по Fortran я печатаю только шестым постом. Добавлено @ 22:32
Бартеньев, могу поспорить. ![]() |
||||
|
|||||
popovda |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 290 Регистрация: 9.6.2006 Где: Москва Репутация: нет Всего: 6 |
Признаюсь. Не знал про спецификатор F0.k, но если это из Бартеньева, то я так же не уверен, что это стандарт 95. Бартеньев очень жестко привязан к линейке CVF. Про некоторые расширения языка относительно стандарта и моменты реализации он умалчивает.
Насчет меток и оператора format. Нда. Согласен. Это последний камень преткновения в Ф. относительно меток. Что делать - привычка ![]() -------------------- С уважением, Попов Д.А. |
|||
|
||||
Cr@$h |
|
||||||||
![]() Исследователь ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1693 Регистрация: 3.4.2005 Где: Санкт-Петербург, Россия Репутация: 1 Всего: 41 |
Проверил. Это F95. В нём можно писать и i0 для той жже цели при целых числах. Вот жалко, нельзя f0.0, что нам и надо вообще-то ![]() ![]()
В книге 2005 г. в этом смысле всё более менее нормально, а так ты прав.
Да. Ну, если что, напомню: полностью заменяется программированием спецификатора. Плюс есть расширение во могих реализациях:
где n -- целочисленное выражение. А так, можно использовать только буквальные константы (и без угловых скобок, естественно). P.S. В Философии программирования есть немного занимательная тема "Кого это вы 'go to'!? или Нужны ли goto, как и стоит ли их обходить?". Что-то я давно не заходил на неё. Там есть ещё о чём поговорить. Это сообщение отредактировал(а) Cr@$h - 23.9.2006, 22:17 |
||||||||
|
|||||||||
Cr@$h |
|
|||
![]() Исследователь ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1693 Регистрация: 3.4.2005 Где: Санкт-Петербург, Россия Репутация: 1 Всего: 41 |
Я здесь упомянул об расширении над стандартом языка: в дескрипторах преобразования везде вместо буквальных констант можно использовать целочисленные выражения заключённые в угловые скобки.
Это позволяет не прибегать к программированию спецификации формата, чтобы напрямую подставить в дескриптор преобразования значения этих переменных n и m (или целочисленных выражений). Рассматриваемое расширение, хоть и является расширением над стандартом F03 (на сколько я знаю), позволяет часто подобным образом сократить код по выводу чисел. Использовать его следует на своё усмотрение (например, не использовать для переносимости кода). Я же покажу один любопытный код с этим расширением. Для этого поговорим об симметричных матрицах, но это уже отдельная тема сюжетной серии "Этюды для Fortran-программистов": Сюжет 2. Симметричные матрицы: построение типа данных, работа с ним и визуализация. Это сообщение отредактировал(а) Cr@$h - 28.9.2006, 00:56 |
|||
|
||||
Cr@$h |
|
||||||||||||||||||||||||||||||||||||||||
![]() Исследователь ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1693 Регистрация: 3.4.2005 Где: Санкт-Петербург, Россия Репутация: 1 Всего: 41 |
Наконец, выкроил время. Давайте разберём фундаментально задачу по кирпичикам. Уже было предложено куча идей, и по большей части осталось их только объективно реализовать.
Имеется код на С++:
Его задача -- вывести в консоль в скобках числа, соддержащиеся в массиве a, и вот как он это делает:
Нам же поставлена задача: реализовать подобный вывод на Fortran. Ну, что, kamre, покажем C++-программистам, как шла эволюция языков? На основе того, что мы уже обсудили и предложили, сформировалось пять реализаций. Рассмотрим их сразу с примерами кода на Fortran. Заметим, что в оригинале используется тип double, давайте учитывать это. Переменные этого типа могут иметь 15 значащих разрядов (в принципе, всегда их имеют). 1. Использование дескриптора преобразования, введённого в F95 Также, как и в С++, в Fortran 95 введён дескриптор преобразования, позволяющий не задавать общее число позиций для вывода числа, а предоставить динамическую обработку этого: требуется задать только число знаков после запятой. Он выглядит аналогично сишному (.5lf): f0.x, где x -- число разрядов после запятой. Общее число позиций будет определяться самим числом; если значащих разрядов после запятой будет меньше, чем x, то необходимые заполнятся нулями при выводе. Напишем соответствующий код на Fortran:
Да, вот так просто. В консоли мы увидим требуемый текст:
Если писать не в общем виде, как в исходном примере, то это будет виглядеть ещё проще:
Здесь мы разрешили типизацию по умолчанию implicit none, убрали константу R_ для разновидности типа вещественного числа, сделали массив a статическим и убрали переменную-длину массива N. Это плохой стиль и в дальнейшем мы не будем его применять, так что пускай никто не дуется на размер кода. Итак, у С++ на подобную операцию ушло 7 строк кода, у Fortran -- 1. Куда уж меньше. Если оставаться честными, то только второй вариант кода удовлетворяет стандарту F03, ведь мы использовали целочисленное выражение в дескрипторе формата: <N>. Хорошо, хорошо, код можно сделать и переносимым. Запрограммируем спецификацию формата, вот и всё:
Тут мы добавили строку character(80) descriptor и запись в неё: write( descriptor, '(a, i0, a)' ) '("(" ', N - 1, '(f0.5, ", ") f0.5, ")")'. Её значением стало: ("(" 1(f0.5, ", ") f0.5, ")"), которое мы затем использовали как дескриптор преобразования. Недостатки подхода. Остаются нули в разрядах после запятой. Фактически, мы должны были бы писать f0.15, т.к. после запятой могут оказаться все 15 значащих разрядов (это для real(8), не забываем), ведь мы не знаем, сколько в действительности значащих разрядов после запятой у какого числа. Так что правильный код будет выглядеть так (заменили f0.5 на f0.15):
От этого весь вывод "портится":
А что делать? Ведь мы могли занести в массив числа, меньшие 0, и используя все 15 значащих разрядов. Откуда мы знаем, что в массиве "за числа"? Недостаток подхода на лицо. Достоинства подхода. Простота реализации: требует всего несколько строк, даже одной элегантной строки при использовании расширения. Этот подход можно и удобно применять, если обладать некоторой информацией о том, сколько максимум значащих разрядов после запятой (в десятичной форме) используется числами массива. 2. Преобразование числа в строку с удалением ведущих пробелов Очень просто. Пишем число в строку и удаляем в ней ведущие пробелы. Код пишем сразу в стандарте и в общем виде. Если что, знаем как убрать строку дескриптора формата, используя расширение над языком.
Важно сделать несколько замечаний по коду.
Если сравнить с предыдущим подходом (ведь мы будем смотреть на взрослый вариант):
то сразу видно отличие. В первом варианте нам приходится отводить 15 разрядов под знаки после запятой, т.к. заранее не известно, сколько их там у каждого числа. В этом же варианте вывода мы загоняем сперва число в строку, убираем ведущие пробелы и выводим число как часть строки без завершающих пробелов. И именно при загоне числа в строку: write(Strings(i), * ) a(i), вы используем дескриптор преборазования по умолчанию. Он же выводит все 15 разрядов числа и ставит запятую, где надо. Блягодаря этому мы не выводим разрядов числа после запятой, которые не представлены в числе. Недостатки подхода. Используем массив строк. Это требует некоторой дополнительной памяти. Хотя, всё можно было сделать в одном цикле, обходясь всего одной строкой. Длина строк в массиве должна быть не меньше, чем 15+15+2. На каждое число отводится 16(+1) разрядов, отсюда завершающие пробелы могут появляться, если элементу массива присваивалось число с нулевыми разрядами на конце (например, число 3,14 выведится как 3,140.0, где 12 нулей на конце). Достоинства подхода. На каждое число отводится 16(+1) разрядов, ни больше, ни меньше. Здесь не надо думать, сколько разрядов выводить после запятой, компилятор выводит всё 8-мибитное представление числа. Число никак из-за этого не искажается на конце. Нет ведущих пробелов. Как приспособить дескриптор по умолчанию к первому подходу, не понятно. Тут появляются ведущие пробелы: ведь 15 разрядов отводится на знаки до запятой, и, если их меньше, появятся ведущие пробелы. Если кто знает, как убирать здесь ведущие пробелы, не используя строк, то будет совсем здорово. Из-за отсутствия искажеий чисел этот подход можно развить дальше. 3. Преобразование числа в строку с удалением ведущих пробелов и завершающих нулей Используем предыдущий подход. После получения строки с числом без ведущих пробелов удаляем из неё завершающие нули: заменяем их на пробелы, чтобы последние потом вместе со всеми отсечь Trim'ом. Запишем код в функциональном стиле: для замены завершающих нулей на пробелы напишем элементную функцию, чтобы подставлять туда сразу весь массив строк Strings.
Добавили элементную функцию DeleteZeros и её вызов Strings = DeleteZeros( Strings ). При вызове этой функции на её значение будет тратиться память, если это кому-то принципиально, то можно её подставить прямо в код (хотя, я догадываюсь, что компилятор сам это сделает при разрешении на подстановку (inlining)):
С другой стороны, если мы хотим выделить операцию удаления завершающих нулей в отдельную процедуру и быть уверенными, что копий строк (например, результат функции) создаваться не будет, то можно использовать элементную подпрограмму:
В любом случае при параллельном выполннии программы вызовы элементной функции DeleteZeros в первом случае или выполнение итераций цикла DeleteZeros во втором случае или вызовы элементной подпрограммы DeleteZeros в третьем будут проходить параллельно. Вот, что мы видим на экране:
Красиво, правда? Как раз то, чего мы добивались. Недостатки подхода. Как и прежде, используем массив строк. Это требует некоторой дополнительной памяти. Хотя, всё можно было сделать в одном цикле, обходясь всего одной строкой, но из-за этого потеряем распараллеливаемые участки кода. Достоинства подхода. Получили то, что хотели: нет ни ведущих пробелов, ни завершающих нулей у чисел. 4. Преобразование числа в строку с удалением ведущих пробелов и вычислением длины числа без завершающих пробелов Если обратить внимание на третий подход, то он хорошо всем, но делает некоторую лишнюю работу: мы находим каждый завершающий нуль, преобразовываем его в пробел, который всё равно удалим при выводе функцией Trim. Фактически, по строке числа ходим дважды. Вместо этого предлагается, запомнить позицию самого левого завершающего нуля и вывести строку до него. Нужно будет завести дополнительный массив целых чисел только.
Что же мы видим на экране? Да всё тот же пейзаж:
Сделаем несколько замечаний.
Достоинства подхода. Получили то, что хотели: нет ни ведущих пробелов, ни завершающих нулей у чисел. 5. Вычисление числа разрядов после запятой без завершающих пробелов (брутальный метод) Посчитаем для каждого числа, сколько разрядов после запятой нам надо вывести и подставим это значение в дескриптор преобразования.
Важно сделать несколько замечаний и здесь:
Недостатки подхода. Используем массив строк и массив целых чисел. Это требует некоторой дополнительной памяти. Хотя, всё можно было сделать в одном цикле, обходясь всего одной строкой и числом, но из-за этого потеряем распараллеливаемые участки кода. Решение слишком фундаментально: мы считаем число разрядов после запятой без завершающих нулей, всё равно используем строки, но при выводе от них отказываемся. Достоинства подхода. Получили то, что хотели: нет ни ведущих пробелов, ни завершающих нулей у чисел. Заключение и вывод Для задачи мы увидели пять различных реализаций, но только три из них делают вывод изящно и аккуратно.
Если нужно будет обходится без дополнительных массивов, то придётся всё выводить в одном цикле, а значит вывод в две строки в четвёртом методе не будет преимуществом, т.к. его просто не будет. Есть ещё одно отличие у двух последних подходов: один выводит числа, а другой -- строки. Что касается скорости: четвёртый метод проходит справа по строке до первого ненулевого символа, но требует удаления ведущих пробелов, пятый метод проходит справа до десятичной точки, но не требует удаления ведущих пробелов. Можно сказать, что, если вам не важно небольшое изящество кода, то пятый метод является лучшим.
Это сообщение отредактировал(а) Cr@$h - 3.10.2006, 04:43 |
||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||
![]() ![]() ![]() |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Fortran | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |