Расчёт процентов по вкладу
Разбираем одну из самых частых COBOL-задач в банке: начислить проценты на остаток вклада.
Начисление процентов — это когда банк раз в месяц (или в год) добавляет к вашему вкладу небольшую сумму, рассчитанную от остатка на счёте и процентной ставки.
Зачем эта задача вообще существует
Представь банк, в котором миллион вкладчиков. Каждую ночь где-то в дата-центре запускается программа, которая проходит по всем счетам и досчитывает проценты — кому-то за месяц, кому-то за квартал. Эта программа не должна зависать, не должна ошибаться в копейках и должна отработать за отведённое окно времени, обычно несколько часов. Именно для таких задач и создавался COBOL ещё в 1959 году, и именно поэтому банки до сих пор доверяют ему миллиарды долларов расчётов.
Задача на первый взгляд простая — школьная формула процентов. Но в реальном банковском коде она обрастает деталями: как хранить деньги без ошибок округления, как проверить входные данные, как красиво напечатать отчёт. Разберём всё по шагам.
Как хранят деньги в COBOL
Первое, что удивляет новичков: в COBOL для денег не используют обычные числа с плавающей точкой (как float в других языках). Дробные числа с плавающей точкой имеют свойство накапливать крошечные ошибки округления — и если так считать проценты миллиону вкладчиков, банк за год потеряет (или найдёт лишними) реальные деньги. Поэтому в COBOL деньги описывают через специальную конструкцию PIC (сокращение от picture — «картинка», то есть шаблон числа) с фиксированной точкой.
01 WS-VKLAD.
05 WS-OSTATOK PIC 9(7)V99.
05 WS-STAVKA PIC 9(2)V9(4).
05 WS-PROCENTY PIC 9(7)V99.
05 WS-NOVYY-OSTATOK PIC 9(7)V99.Что здесь происходит. 01 — это уровень записи, в COBOL данные организуют в виде дерева, и группа WS-VKLAD объединяет все поля вклада. Уровень 05 — вложенные поля этой группы. PIC 9(7)V99 означает: 7 цифр до запятой (9(7) — семь девяток подряд, каждая девятка — это одна десятичная цифра), буква V — это подразумеваемая десятичная точка (она не хранится физически, компьютер просто «помнит», где она должна быть), и ещё 2 цифры после неё. Итого поле WS-OSTATOK может хранить сумму от 0 до 9 999 999,99 — вполне достаточно для остатка на вкладе. А WS-STAVKA PIC 9(2)V9(4) хранит процентную ставку вроде 7,5000% с четырьмя знаками после запятой — так точнее, чем в обычных деньгах.
Сам расчёт: оператор COMPUTE
Теперь, когда поля описаны, посчитаем проценты. В COBOL для арифметики есть отдельный оператор COMPUTE — он позволяет писать формулы почти как в математике, вместо того чтобы городить отдельные ADD, MULTIPLY и DIVIDE команды одна за другой.
MOVE 15000.00 TO WS-OSTATOK.
MOVE 7.5000 TO WS-STAVKA.
COMPUTE WS-PROCENTY = WS-OSTATOK * WS-STAVKA / 100
ON SIZE ERROR
DISPLAY "ОШИБКА: переполнение при расчёте процентов"
END-COMPUTE.
COMPUTE WS-NOVYY-OSTATOK = WS-OSTATOK + WS-PROCENTY.
DISPLAY "Остаток: " WS-OSTATOK.
DISPLAY "Проценты: " WS-PROCENTY.
DISPLAY "Новый остаток: " WS-NOVYY-OSTATOK.Разберём построчно. MOVE 15000.00 TO WS-OSTATOK кладёт остаток 15 000 рублей в поле — MOVE в COBOL это как присваивание = в других языках, только читается «переместить значение туда-то». Дальше COMPUTE WS-PROCENTY = WS-OSTATOK * WS-STAVKA / 100 — это и есть формула процентов: остаток умножаем на ставку и делим на 100 (потому что ставка задана в процентах, а не в долях). Обрати внимание на конструкцию ON SIZE ERROR — это встроенная защита COBOL: если результат вычисления не поместится в отведённое под него поле (например, если бы у нас было слишком много цифр), программа не упадёт молча и не обрежет число — она выполнит блок ON SIZE ERROR и сообщит об ошибке. Такая защита от переполнения — не необязательная роскошь, а стандартная практика в банковском коде, потому что «тихо потерянные» деньги в отчёте недопустимы. Заканчивается блок словом END-COMPUTE — в COBOL многие операторы имеют такие явные «закрывающие» слова, чтобы не было путаницы, где заканчивается один блок кода и начинается следующий код программы.
Вывод:
Остаток: 0015000.00
Проценты: 0001125.00
Новый остаток: 0016125.00Обрати внимание: числа выводятся с ведущими нулями (0015000.00 вместо 15000.00) — это прямое следствие того, как мы описали поле через PIC 9(7)V99: оно всегда занимает ровно 7 цифр до точки, независимо от того, сколько цифр реально «значащие». Для банковских отчётов это даже удобно — все суммы в колонке выровнены по ширине.
Практический пример: расчёт для нескольких вкладов
А теперь усложним: пусть у нас не один вклад, а несколько, с разными ставками в зависимости от типа вклада. Это уже ближе к реальности — банк не начисляет всем одинаковый процент.
01 WS-TIP-VKLADA PIC X(10).
01 WS-STAVKA-ITOG PIC 9(2)V9(4).
EVALUATE WS-TIP-VKLADA
WHEN "STANDARD"
MOVE 5.5000 TO WS-STAVKA-ITOG
WHEN "PREMIUM"
MOVE 8.2000 TO WS-STAVKA-ITOG
WHEN "NAKOPIT"
MOVE 9.7500 TO WS-STAVKA-ITOG
WHEN OTHER
MOVE 0.0000 TO WS-STAVKA-ITOG
DISPLAY "Неизвестный тип вклада: " WS-TIP-VKLADA
END-EVALUATE.EVALUATE — это аналог switch или конструкции «если-иначе-если» из других языков, только по-COBOLовски многословный и очень читаемый. Он проверяет значение поля WS-TIP-VKLADA (тип X(10) означает текстовую строку из 10 символов, буква X — «любой символ», в отличие от 9, которая означает только цифры) и в зависимости от него подставляет нужную ставку. Ветка WHEN OTHER обязательно нужна на случай, если в данные попало что-то непредвиденное — опечатка в справочнике или битые данные из другой системы. Без такой защитной ветки программа могла бы просто пропустить расчёт молча, а на банковском мейнфрейме молчаливо пропущенный расчёт — это прямая финансовая ошибка, которую потом неделями ищут аудиторы.
Частые ошибки
Первая и самая обидная ошибка — забыть про ON SIZE ERROR. Без него при переполнении COBOL по умолчанию просто обрежет старшие разряды числа, и в отчёте окажется неверная сумма без единого предупреждения. Вторая ошибка — перепутать V (подразумеваемая точка) с реальной десятичной точкой в описании PIC: если написать PIC 9(7).99 вместо PIC 9(7)V99, компилятор выдаст ошибку, потому что точка в PIC-описании имеет другой смысл. Третья частая ошибка новичков — забыть, что деление в целочисленной арифметике COBOL может терять точность, если не задать достаточно знаков после запятой у промежуточных полей: если посчитать проценты с точностью до 2 знаков, а потом умножить результат на что-то ещё, накопленная погрешность может быть заметна на больших суммах. Поэтому в банковских программах промежуточные поля обычно делают точнее, чем финальный результат, и округляют только на последнем шаге.
Итоги
- Деньги в COBOL хранят в полях с фиксированной точкой через
PIC 9(n)V9(m)— это защищает от ошибок округления, которые копятся при работе с миллионами счетов. - Оператор
COMPUTEсчитает формулы, аON SIZE ERROR— обязательная защита от переполнения в финансовых расчётах. EVALUATE— удобный способ выбрать ставку или логику в зависимости от типа вклада, с обязательной веткойWHEN OTHERдля непредвиденных данных.- В банковском коде важнее не скорость написания, а предсказуемость и отсутствие тихих ошибок — отсюда вся эта «многословность» COBOL.