Блог пользователя Nickolas

Автор Nickolas, 12 лет назад, По-русски

Итак, разбор задач. Я старалась подбирать задачи так, чтобы каждая из них раскрывала какой-то аспект языка — особенность или часто используемый глагол. Если участник его узнавал/нагугливал, задача должна была стать очевидной.

153A - A + B

Сразу скажу, что приведенный в посте пример работет и в Custom test, и в ideone, и локально — если вводить числа по одному на строку и (внимание!) после второго тоже поставить перевод строки. Этот последний перевод строки не отображается в тестах, но на самом деле он там есть! И для COBOL это важно. Все тесты на Codeforces сгенерированы аккуратно, с переводом строки всюду, где нужно, поэтому при сабмите проблем возникать не должно было.

Самая очевидная особенность COBOL — это хранение чисел в десятичной записи заданной программистом ширины, со всеми последствиями. В данном случае внимание фокусировалось на том, что по умолчанию число выводится фиксированной ширины, при необходимости дополненное спереди нулями. От этих нулей и предлагалось избавиться. Авторское решение преобразовывало сумму в строку с ведущими нулями, а затем отбрасывало нули. Для этого их нужно было посчитать — скорее всего, с помощью глагола INSPECT ... TALLYING, который подсчитывает символы строки, соответствующие заданным условиям, и прибавляет их количество к заданной переменной. К коду сложения двух чисел достаточно дописать несколько строк:

       01 ZEROSCOUNT  PIC 99.
       01 SUMSTRING   PIC X(10).

       MOVE SUM TO SUMSTRING
       MOVE 1 TO ZEROSCOUNT
       INSPECT SUMSTRING TALLYING ZEROSCOUNT FOR LEADING "0"
       DISPLAY SUMSTRING(ZEROSCOUNT:11 - ZEROSCOUNT)

В COBOL символы строки и элементы массивов нумеруются с 1, поэтому начальное значение ZEROSCOUNT должно быть равно 1.

Можно было поступить и проще: объявить переменную C типа z(10)9, перенести результат в нее и выводить его без дальнейших ухищрений — этот формат дополняет число до нужной ширины не нулями, а пробелами.

153B - Двоичная запись

Следующая задача тоже комбинировала два важных элемента языка — глагол PERFORM UNTIL, использующийся для организации циклов, и глагол конкатенации строк STRING. Условие окончания цикла — N EQUAL 0, тут затей нет. Внимание нужно обратить на то, как конкатенируются строки: сначала текущая бинарная цифра, потом текущая бинарная запись числа. Аргументы STRING дополняются указанием DELIMITED BY, которое определяет, какую часть строки нужно использовать для конкатенации. Два основных режима — DELIMITED BY SIZE, когда используется вся переменная целиком независимо от ее реальной заполненности, и DELIMITED BY SPACE, когда используется часть переменной до первого пробела (или до конца заполненной части). Текущую цифру записи можно хранить в переменной размера 1 и использовать DELIMITED BY SIZE, а вот текущую запись лучше ограничивать пробелами (хотя это было бы более актуально, если бы конкатенация происходила в обратном порядке).

Код цикла, реализующего основную логику программы (да, совершенно не обязательно писать весь код в верхнем регистре :-)):

         perform until n equal 0
           divide n by 2 giving n remainder digit
           move digit to binary_digit
           string binary_digit  delimited by size
                  binary_number delimited by space
                  into str
           move str to binary_number
         end-perform.

153C - Шифр Цезаря

К этой задаче можно было подойти двумя способами. Первый, более типичный для СП, — пройтись по строке и преобразовать каждый символ отдельно. Авторское решение использовало второй, основанный на еще одном глаголе COBOL — INSPECT ... CONVERTING. Этот глагол позволяет пройти по строке, заменяя символы из первого аргумента на соответствующие им из второго. Задача шифрования с фиксированным ключом решалась бы вообще в один глагол, например, для ROT-13

inspect cipher
    converting 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
            to 'NOPQRSTUVWXYZABCDEFGHIJKLM'

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

153D - Изменение даты

Конечно, эту задачу можно решать вручную — разбить дату на день, месяц и год и прибавить/отнять один день нужное количество раз. Но в COBOL есть специальные функции и на этот случай — INTEGER-OF-DATE (преобразует дату из формата YYYYMMDD в количество дней, прошедших с 31 декабря 1600 года) и обратная ей DATE-OF-INTEGER. Остается только преобразовать входной формат даты в YYYYMMDD, прибавить shift к дате-количеству дней и применить обратное преобразование.

153E - Евклидово расстояние

Последняя задача раунда требовала работы с массивами, которые в COBOL называются таблицами. Пожалуй, самое в них сложное — разобраться с форматом их объявления. Моя структура данных выглядела вот так:

         01 n pic 99.
         01 points.
            02 occurs 2 to 50 times depending on n.
               03 x pic S999.
               03 y pic S999.

Символ S в объявлении числовой переменной указывает, что она может принимать отрицательные значения — без этого знак просто отбрасывается. DEPENDING ON N означает, что массив автоматически принимает размер, равный значению переменной N. Обращаться же к элементам массива предельно просто — x(i) и y(i).

Двойной цикл можно реализовать несколькими способами, самый простой — два вложенных цикла:

         perform varying i from 1 by 1 until i > n
           perform varying j from i by 1 until j > n
             compute dx = x(i) - x(j)
             compute dy = y(i) - y(j)
             compute d = dx * dx + dy * dy
             if d > maxd
               move d to maxd
           end-perform
         end-perform.

Наконец, последний элемент языка — вызов библиотечной функции SQRT:

         display function sqrt(maxd)
Разбор задач Surprise Language Round 5
  • Проголосовать: нравится
  • +34
  • Проголосовать: не нравится

»
12 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Кстати, строковые функции типа INSPECT и UNSTRING выглядят довольно современно. Если бы ещё всё остальное (объявление переменных и массивов, общая структура программы, циклы) не было так страшно...

»
12 лет назад, # |
  Проголосовать: нравится +9 Проголосовать: не нравится

Раунд, конечно же, классный вышел, но язык довоно непривычный. Особенно если не знаешь привычных форм операторов и все время используешь глаголы, это начинает раздражать. Тут уже не та халява, как с pike :)

И все же $ sudo apt-get remove open-cobol, надеюсь, я больше никогда не буду на нем что-либо писать

»
12 лет назад, # |
  Проголосовать: нравится +12 Проголосовать: не нравится

Thanks Nickolas, it was very fun

»
12 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Я надеюсь что следующий язык будет по современней *))

  • »
    »
    12 лет назад, # ^ |
      Проголосовать: нравится +20 Проголосовать: не нравится

    Определенно — хотя бы потому, что почти все существующие языки современней :-)