Сегодня публикуем вторую часть перевода материала о математике, о COBOL, и о том, почему этот язык всё ещё жив.



> Первая часть

Рекуррентное соотношение Мюллера и COBOL


Взглянем на то, как рекуррентным соотношением Мюллера справится COBOL. Вот программа на COBOL, реализующая исследуемое нами рекуррентное соотношение.

IDENTIFICATION DIVISION.
PROGRAM-ID.  muller.
AUTHOR.  Marianne Bellotti.
DATA DIVISION.
WORKING-STORAGE SECTION.
01  X1           PIC 9(3)V9(15)    VALUE 4.25.
01  X2           PIC 9(3)V9(15)    VALUE 4.
01  N            PIC 9(2)          VALUE 20.
01  Y            PIC 9(3)V9(15)    VALUE ZEROS.
01  I            PIC 9(2)          VALUES ZEROS.

PROCEDURE DIVISION.
 PERFORM N TIMES
  ADD 1 TO I
  DIVIDE X2 INTO 1500 GIVING Y
  SUBTRACT Y FROM 815 GIVING Y
  DIVIDE X1 INTO Y
  MOVE X1 TO X2
  SUBTRACT Y FROM 108 GIVING X1
  DISPLAY I'|'X1
 END-PERFORM.
 STOP RUN.

Если вы впервые видите программу, написанную на COBOL, то давайте сразу проясним некоторые вещи. Во-первых — это так называемый «free form» COBOL, который был представлен в 2002 году для того, чтобы приблизить COBOL к тому, как структурированы современные языки. Традиционно код на COBOL имеет фиксированную ширину, когда определённые сущности размещаются в определённых столбцах. Идея рассмотрения кода в виде структуры, в которой выделяются строки и столбцы, может показаться странной, но такая структура кода предназначалась для имитации форматирования перфокарт. Во времена появления COBOL программы создавали именно так. Перфокарта имеет 80 столбцов — определённые столбцы предназначены для определённых данных. Такой же подход является традиционным и для COBOL.

Самое важное в этом коде, нечто такое, что, возможно, привлекает к себе больше всего внимания, заключается в том, как здесь объявляют переменные:

01  X2           PIC 9(3)V9(15)    VALUE 4.

Код 01 в начале строки называется номером уровня (level number). Он сообщает COBOL о том, что мы объявляем новую переменную. COBOL позволяет связывать или группировать переменные (классический пример — это адрес, который может включать в себя названия улицы, города и страны в виде отдельных переменных), в результате в данном случае номер уровня становится важным.

X2 — это имя переменной — тут всё довольно просто. В конце имеется конструкция, устанавливающая начальное значение переменной, которая выглядит как «VALUE 4.». Точка в конце — это не опечатка. Это — способ завершения строк в COBOL.

Теперь нам осталось рассмотреть лишь то, что находится в середине строки — конструкцию PIC 9(3)V9(15).

PIC — это нечто вроде оператора для описания символьного типа данных. Он может хранить буквенно-цифровые значения. Он даже может хранить десятичные числа. COBOL — это язык со строгой статической типизацией и с одной необычной особенностью, которая заключается в том, что большинство типов COBOL оказываются гораздо более гибкими, чем типы в других языках. Кроме того, при объявлении переменных нужно указать то, из скольких символов они могут состоять. В нашем случае это — число в скобках. Конструкция PIC 9(3) означает, что переменная может хранить три символа, которые являются числами (на это указывает число 9).

В результате конструкцию 9(3)V9(15) надо читать так: «3 цифры, за которыми следует десятичная точка (v), за которой следуют ещё 15 цифр».

Вот результаты работы этой программы:

01|004.470588235294118
02|004.644736842105272
03|004.770538243626253
04|004.855700712593068
05|004.910847499165008
06|004.945537405797454
07|004.966962615594416
08|004.980046382396752
09|004.987993122733704
10|004.993044417666328
11|005.001145954388894
12|005.107165361144283
13|007.147823677868234
14|035.069409660592417
15|090.744337001124836
16|099.490073035205414
17|099.974374743980031
18|099.998718461941870
19|099.999935923870551
20|099.999996796239314

Это получилось с использованием чисел, имеющих 15 знаков после запятой. Если поменять свойства переменных X1, X2 и Y на PIC9(3)V9(25) — то мы сможем продвинуться дальше:

01|004.4705882352941176470588236
02|004.6447368421052631578947385
03|004.7705382436260623229462114
04|004.8557007125890736342050246
05|004.9108474990827932004556769
06|004.9455374041239167250872200
07|004.9669625817627006050563544
08|004.9800457013556312889833307
09|004.9879794484783948244551363
10|004.9927702880621195047924520
11|004.9956558915076636302013455
12|004.9973912684019537143684268
13|004.9984339443572195941803341
14|004.9990600802214771851068183
15|004.9994361021888778909361376
16|004.9996648253090127504521620
17|004.9998629291504492286728625
18|005.0011987392925953357360627
19|005.0263326115282889612747162
20|005.5253038494467588243232985

Разные мэйнфреймы предлагают разные верхние ограничения для типов данных COBOL. У IBM (по крайней мере — в моём случае) это — 18 цифр. У MicroFocus это — 38 цифр.

Сколько стоит точность?


Всё, о чём мы только что говорили, направлено на то, чтобы показать, что COBOL выполняет вычисления не лучше, чем другие, более распространённые языки программирования. Из-за ограничений на размеры чисел с фиксированной точкой COBOL, на самом деле, может уступать языкам, которые дают разработчику больше контроля над происходящим.

Но тут есть одна особенность. Дело в том, что Python (да и Java) не имеет встроенной поддержки чисел с фиксированной точкой. А в COBOL эта поддержка есть.

Для выполнения вычислений с фиксированной точкой в Python мне пришлось импортировать модуль Decimal. Если вы когда-нибудь работали с проектом, в котором имеется целая куча команд импорта — вы должны знать о том, что у каждой подобной команды есть определённая «цена». В языках наподобие Java (а именно этот язык обычно рассматривается теми, кто собирается избавиться от COBOL) «цена» подходящей библиотеки может быть значительно выше. Это, на самом деле, скорее вопрос о том, играет ли какую-то роль в вашем проекте «стоимость» импорта библиотек. Для многих программистов размышление над влиянием на производительность, которую оказывают команды импорта — это вершина преждевременной оптимизации.

Но COBOL-программисты обычно работают над системами, которые должны обрабатывать миллионы, а возможно — и миллиарды операций в секунду, делая это точно и надёжно. И, к несчастью, очень сложно привести убедительный аргумент за COBOL или против него для подобного сценария, так как это, на самом деле, область бесчисленных вариаций. Является ли определяющим фактором при выборе языка для решения подобных задач встроенная в COBOL поддержка чисел с фиксированной точкой? Или, может быть, соответствующие проблемы можно решить, правильно подбирая комбинацию из процессора, памяти, операционной системы? Или, может, для решения задач быстрых, точных и надёжных вычислений нужно прибегнуть к «танцам с бубном»? Может быть — ограничим рассуждения? Сведём их к поиску ответа на вопрос вроде «Что лучше — COBOL или Java при условии использовании одного и того же аппаратного обеспечения?». Но и так нам будет сложно оценить то, как недостатки каждого из языков повлияют на производительность в момент, когда система начнёт выполнять вышеупомянутые миллиарды операций в секунду. В результате можно сказать лишь то, что те же COBOL и Java — просто очень разные языки.

Вот что пишут по этому поводу здесь, исследуя производительность Java-кода, транслированного из COBOL-кода.
COBOL — это компилируемый язык, использующий стек, поддерживающий указатели и объединения. Конверсия типов не создаёт нагрузку на систему во время выполнения программы. Здесь нет диспетчеризации или преобразований типов во время выполнения программ. Java-код, с другой стороны, выполняется на виртуальной машине. Он использует кучу и не поддерживает объединения. Конверсия типов создаёт нагрузку на систему во время выполнения программы. Java использует динамическую диспетчеризацию и вывод типов во время выполнения программ. Хотя и можно минимизировать объём использования этих возможностей, обычно это приводит к тому, что код получается в той или иной мере «непохожим» на обычный Java-код. При изучении результатов трансляции Java-кода из COBOL обычно жалуются на то, что код получается нечитаемым и неподдерживаемым. Это сводит на нет большинство целей перехода с COBOL на Java.

Прежде чем вы решите отмахнуться от этих рассуждений фразой «Да, но это Java, а Java — тоже не подарок» — вспомните вот о чём: большинство современных языков программирования совершенно не имеют встроенной поддержки вычислений с фиксированной точкой. (Я так думаю, что правильнее было бы сказать, что ни один из современных языков это не поддерживает, но я не могу это надёжно проверить.) Конечно, можно выбрать другой язык, имеющий свой набор достоинств и недостатков, но если нужна точность в вычислениях с фиксированной точкой, и если вы думаете, что небольшая потеря в производительности от импорта библиотеки, реализующей такие вычисления, может вам повредить, это значит, что у вас есть единственный вариант — COBOL.

Именно поэтому столь сложна так называемая «модернизация»: она зависит от множества факторов. Некоторые организации получат ощутимые результаты от инвестиций в смену программной платформы, а другие обнаружат, что потеряли что-то важное взамен на «улучшения», которые, на самом деле, ничего особенно и не улучшают. Если организация — это крупный финансовый институт, обрабатывающий миллионы транзакций каждую секунду и нуждающийся в десятичной точности вычислений — то, на самом деле, дешевле будет обучить специалистов работе с COBOL, чем заплатить ресурсами и производительностью за миграцию на более популярный язык. В конце концов, популярность — явление временное.

Итоги


В результате, говоря о том, почему так много организаций всё ещё используют COBOL, нужно понимать, что задача по переработке программ отличается от задачи создания программ. Программисты, создававшие решение, имели преимущество в виде его поэтапного внедрения. Приложения обычно стремятся максимально приблизить к пределам тех возможностей, которые поддерживают реализованные в них технологии. Дилемма, касающаяся миграции с COBOL — это не вопрос о переходе с одного языка на другой. Это — задача о переходе с одной парадигмы на другую. Пределы возможностей Java или Python на Linux — это совсем не то, что пределы возможностей COBOL на мейнфрейме. В некоторых случаях COBOL-приложения способны на то, что современные языки не могут. Для подобных случаев использование COBOL на современном мейнфрейме окажется, на самом деле, более дешёвым, производительным и точным решением.

Уважаемые читатели! Как вы думаете, действительно ли COBOL — это язык, который в некоторых ситуациях оказывается по-настоящему лучше более современных языков?

Комментарии (28)


  1. Zenitchik
    19.09.2019 12:55
    +1

    Чёрт, даже захотелось COBOL изучить!


  1. Zenitchik
    19.09.2019 13:01

    Краткая суть статьи: COBOL, конечно, язык интересный, но описанную задачу тоже не решает.
    Дальнейший трёп про парадигму — это уже лирика.


    1. 0xd34df00d
      19.09.2019 14:54

      Дальнейший трёп — это не только лирика, но и какой-то бред. Какое влияние на производительность имеет импорт библиотеки в компилируемых языках? Почему он гарантированно (как я понял логику автора) негативно на нее влияет?


      1. worldmind
        19.09.2019 15:49

        Да и в нормальных интерпретируемых импорт делается один раз.


      1. lz961
        19.09.2019 16:04

        Может имеется в виду, что работа с числам в этих библиотеках обходится дороже чем просто целочисленное сложение либо умножение/деление и сдвиг, как это имело бы место в случае компилируемого языка(?)


  1. kkirsanov2
    19.09.2019 13:01

    Взаимоисключающие параграфы:


    Дело в том, что Python (да и Java) не имеет встроенной поддержки чисел с фиксированной точкой.

    Для выполнения вычислений с фиксированной точкой в Python мне пришлось импортировать модуль Decimal

    Вообще удивительно как автор всю специфику кобола свёл к фикс.точке.


    1. usheynet
      20.09.2019 09:40

      Нормально все, речь-то про _встроенную_ поддержку.


      1. kkirsanov2
        20.09.2019 10:00

        Decimal — часть стандартной библиотеки, которая встроена и которую не нужно никак специально ставить.


        Вон в хаскеле Bool, Int и Float часть прелюдии — http://hackage.haskell.org/package/base-4.12.0.0/docs/Prelude.html и ничего.


  1. ivge
    19.09.2019 13:31

    Самое интересное про COBOL:
    выходят новые стандарты: COBOL-85, COBOL 2002 и объектно-ориентированный COBOL
    COBOL 2014
    en.wikipedia.org/wiki/COBOL
    есть OpenCobolIDE 4.7.6 (Last released: Dec 30, 2016)
    pypi.org/project/OpenCobolIDE


  1. rutenis
    19.09.2019 14:29
    +2

    большинство современных языков программирования совершенно не имеют встроенной поддержки вычислений с фиксированной точкой. (Я так думаю, что правильнее было бы сказать, что ни один из современных языков это не поддерживает, но я не могу это надёжно проверить.)

    Вычисления с фиксированной точкой поддерживает Ada — скажем, в версии стандарта Ada 2012 (см. здесь и здесь).


    1. el_gato
      20.09.2019 10:34

      Да, Ада еще с Ada83 поддерживает вычисления с фиксированной точкой


  1. ultrinfaern
    19.09.2019 15:12

    Во всех статья про плавающую точку немного лукавят, говоря что фиксированная точка спасет мир. Это не так.
    Проблема IEE 754 в том что основание системы счисления хранения числа это 2 и соответственно некоторые десятичные дроби в нем не представимы. Отсюда и возникают сразу же ошибки вычислений.
    Есть стандарт IEE 754- 2008 где как раз это и починили но этот стандарт в железе не реализован (может где и есть).
    ЗЫ В яве есть BigDecimal из коробки, так что говорить, что Ява вообще не умеет в десятичную арифметику это не правда. С другой стороны для него нет перекрытых арифметических операций в компиляторе, поэтому писать выражения через вызов методов сложно.


    1. vvm13
      19.09.2019 15:29

      Насколько я знаю, DECFLOAT есть в IBM-овских процессорах (точнее, когда DECFLOAT добавили в DB2, я прочитал, что AIX поддерживает это хардварно). Почему всякие Питоны, Явы, процессоры Intel/AMD и прочие электронные таблицы до сих пор не поддерживают полноценно «десятичную» арифметику с дробями, когда эта проблема стоит уже многие десятилетия и на неё так или иначе натолкнулись, возможно, десятки миллионов людей? Это не перестаёт меня удивлять.


  1. Mabu
    19.09.2019 16:22

    Меня удивляет, что в процессоре до сих пор нет нативной поддержки натуральных дробей, есть лишь только «числа с плавающей запятой». Казалось бы, добавь натуральную дробь с числителем и знаменателем — и не будет проблем с точностью. А нет. Не добавляют.

    У меня есть два соображения по этому поводу.

    1. В США натуральные дроби — это моветон, сложная штука, которую не используют.
    2. В бухгалтерии и финансах не приняты.


    1. Alexey_Alive
      19.09.2019 17:22

      В США натуральные дроби намного нужнее для людей, чем у нас, так как они не используют метрическую систему. Если ты не умеешь быстро считать дроби, то как ты унции в галлоны, а ярды в мили переведёшь?! По поводу нативной поддержки decimal: хоть её и нет, но в amd64 есть ряд инструкций в описании которых пишется, что эта инструкция используется в основном для fixed point.


    1. lamerok
      19.09.2019 17:42

      В США рациональные числа везде, едешь такой, а тебе указатель до съезда 1/4 мили.
      А поддержки аппаратной понятно почему нет, придётся памяти о грызть не мало. float может примерно на 25 порядков число больше или меньше отобразить чем 64 битное рационально. Поэтому дилемма, либо точно и с небольшим диапазоном, либо не совсем точно но с большим диапазоном. Ну и для большинства задач float достаточен.


    1. code07734
      19.09.2019 18:34
      +1

      Ага, давайте все в CPU тащить. Больше ISA, нам нужно больше микрокода!!! Дроби — да реализуйте свои структуры данных на С/asm, или на c++ где дешевый синтаксический сахар + компиляторы хорошие, в чем проблема-то?


      1. Mabu
        19.09.2019 18:47

        да реализуйте свои структуры данных
        Симметричный ответ: а зачем тогда числа с плавающей запятой ввели? Ну и реализовывали бы их на своих структурах данных. Зачем это тащить в процессор?


        1. DmitryKoterov
          20.09.2019 05:23

          Низачем. На RISC-процессорах из часто и нет.


        1. mayorovp
          20.09.2019 10:26

          Плавающая запятая довольно дорогая в программной реализации. В отличии от рациональных чисел.


      1. Mabu
        19.09.2019 18:47

        да реализуйте свои структуры данных

        Симметричный ответ: а зачем тогда числа с плавающей запятой ввели? Ну и реализовывали бы их на своих структурах данных. Зачем это тащить в процессор?


        1. code07734
          19.09.2019 20:06

          Я не знаю зачем они их ввели, но сейчас из этого мало хорошего вытекает. Наверно маркетинг, они же тогда софтом сильно не занимались, значит нужно было добавлять "плюшки" аппаратно. Но если тенденцию продолжить — будет только хуже.


        1. code07734
          19.09.2019 20:08

          Они производители процессоров, что значит они бы реализовали бы на "своих структурах данных"? Сейчас каждый топ производитель имеет свой компилятор


  1. Viacheslav01
    19.09.2019 17:50

    Кобол спасает стабильное законодательство, ни одна система на коболе не переживет, отечественного бешенного принтера.

    Ну и опять о цене миграции, многие системы которые работают с финансами написанные на коболе и исполняемые на мейнфреймах, очень не просто сертифицировать, по факту для того, что бы создать подобную систему на альтернативной платформе в нее придется инвестировать ровно столько, сколько было инвестировано за время ее жизни.


    1. lamerok
      19.09.2019 17:53

      Может наоборот, законодательство не меняется, потому что программы на Cobol, и никто не хочет в них лезть для изменений.


    1. staticlab
      20.09.2019 02:38

      Программы на RPG как-то же выдерживают натиск бешеного принтера.


    1. Gutt
      20.09.2019 09:11

      ни одна система на коболе не переживет, отечественного бешенного принтера

      Да ладно, не драматизируйте. Античные системы, как правило, реализуют вычислительное ядро, а это — простая логика движения средств, правила бухучёта и прочие базовые вещи, которые бешеный принтер по большей части обходит стороной. А интерфейсы ко внешним системам, где и творятся основные Адъ и Израиль, разумеется, не на Коболе.


  1. Assimilator
    20.09.2019 17:12

    Пишу на MicroFocus COBOL по работе, на никсах.


    Плюсы его, во-первых, в том что можно создать текстовой GUI за секунды.


    Постройка классов чумовая, да ещё можно все совпадающие переменные двух разных классов двигать между ними без напряга.


    Лёгкость интеграции с другими программами просто убийственная, передать данные шелл скрипту — как нефиг делать, принять тоже. Можно курлы с SSL всякие запускать без напряга. Вообще, прицепить к нему SQL датабазу какую-нибудь проблем совсем не составит.


    И самое главное — оверхед. А точнее почти полное его отсутствие. Это просто безумие. Я теперь до конца жизни в С# всякие буду плеваться за одно только это.


    Настоящие минусы:


    1. Всё, буквально всё нужно делать ручками. Если нет наработок то COBOL лучше вообще не трогать.


    2. Уебищно выглядит любое меню. Людям привыкшим к современному, в нём ничего не понятно.


    3. Тех долг… Это просто кошмар. В старых проектах — сотни если не тысячи человеко-часов тех долга. Его просто нельзя трогать, так как никто за это не заплатит.


    4. Наждачный секс с файл локами, залочиванием, разлочиванием, полным отсутствием какой-либо защиты файлов от повреждения при записи и т.д. и т.п.


    5. Дебаггинг чего-то более сложного чем калькулятор — это кошмаррррр. Трейсинг переменных ужасен.


    6. В COBOL можно следовать best practices, но большая часть существующего кода им не следует. А значит вам его дебагить-непередебагить — см выше про дебаггинг.



    Я тут ещё могу часами писать, но надеюсь суть вы поняли.