«МК-Про»: два регистра в одном

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

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

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

Идея в том, что два целых числа с известными диапазонами можно упаковать в одно число: одно — в целую часть, другое — в дробную. Тогда извлечь их можно операциями нахождения целой части (K [x]) и дробной части (K {x}), причём дробную часть потом часто можно и не домножать: транслятор может заменить всю арифметику с ней так, что всё будет работать ожидаемым образом, но вместо диапазона 0…9 будет использоваться диапазон 0…0,9.

В эталонной программе, о которой идёт речь, все регистры заняты под завязку, и эта оптимизация должна работать в связке с другой: в дробной части будет храниться счётчик, а в целой — опорное число для адреса перехода, которое, например, будет менять знак в зависимости от условия. Сам адрес считается по подобранной формуле.

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

Вчера я остановился на том, что решатель должен перебирать функции, в том числе тригонометрические: именно они обычно дают самый толковый результат. Но в «МК-61» и в C++ они дают немного разные результаты.

В общем, зарядил я «Кодекс», чтобы он покопался в микрокоде калькулятора и алгоритмически повторил код, реализующий тригонометрию в Си++. Цель была обозначена, на мой взгляд, очень чётко. Но не зря я говорю, что нейросеть иногда похожа на джина, который всё, что можно понять двояко, вывернет вам во вред.

Когда я уходил спать, всё работало как часы — нейросеть копалась в ПЗУ калькулятора, сравнивала реализацию с эталоном, разбиралась почему ошибки. Утром я первым делом полез в этот код, чтобы посмотреть что получилось. А там…

А там, как говорят поляки «wygląda jak gówno, a smakuje jeszcze lepiej» — «выглядит как говно, а на вкус ещё лучше». Пятьдесят тысяч строк отвратительного лапшекода, сгенерированного программно из ПЗУ «МК-61».

Сеть на каком-то этапе поняла, что цель не приближается, написала автогенератор этой дичи, убедилась, что все тесты позеленели и успокоилась.

Читайте также

Комментарии 48

Алексей Сугоняев № 1
можно хранить еще больше переменных, 8 тетрад мантиссы, берем по 2 и вносим XYZT 4 переменные от 0 до 99, в принципе конечно больше потому что возможны символы от A до F, но как хранилище чисел до сотни вполне сойдет. Делим на 100, 10000 и 1000000, берем целую часть
Евгений Степанищев автор № 2
восстановление обойдётся очень дорого, нужны компактные пути (в одну команду) для восстановления
Алексей Сугоняев № 3
даже с frac или int буде слишком дорого по времени, переменную нужно извлечь изменить и обратно вложить. Если на это пошли то проблема в свободной памяти встала в полный рост.
Алексей Сугоняев № 5
для целой части да, а вот для дробной нужна дополнительная константа 0.01 например
Евгений Степанищев автор № 6
а, ну да. но выигрыш, судя по всем, есть
Алексей Сугоняев № 7
выигрыш конечно будет храним константы в отдельных регистрах, а в виде int.frac какие то не большие по размеру значения, поэтому я и предложил идти дальше и оперировать на разрядах без переноса
x+-10000, X+-100, X+-1 уже три переменные в одном иксе. Извлечь x/1000000, x/100000, x/100.
Алексей Сугоняев № 9
число 756120, содержит три переменные 75, 61, 20 доступ к ним осуществляется вызовом подпрограммы, где 100 или 10000 вшиты в код подпрограммы. Складывать или вычитать тоже можно через вызов ПП и не только с 1 если уверен что переноса не будет.
Алексей Сугоняев № 19
10 шагов что бы извлечь серединку, края должны быть проще
Евгений Степанищев автор № 21
10 команд — это 10% памяти
Алексей Сугоняев № 22
и возможность хранить в три раза больше чисел
Евгений Степанищев автор № 23
это если все регистры заняты и память есть, как правило ситуация другая — регистров нет и памяти уже почти нет…

потому что память большие программы (которые требуют регистров) выжирают под логику
Алексей Сугоняев № 27
00. 4
01. F10^x
02. :
03. K{x}
04. 2
05. F10^x
06. *
07. K[x]
08. C/П
Евгений Степанищев автор № 29
попробую подумать над этим
Алексей Сугоняев № 30
у меня такое ощущение что наши спортивные программисты смогли бы и лучше :) шагов в шесть уложить
Алексей Сугоняев № 34
Ну и конечно самое очевидное
00. ИП4
01. :
02. K{x}
03. ИП2
04. *
05. K[x]
06. С/П
1
Евгений Степанищев автор № 35
если программа небольшая, а все регистры заняты — вполне себе способ
Алексей Сугоняев № 36
Как всегда сильно зависит от типов данных и их кол-ва
Евгений Степанищев автор № 37
так они ж (типы) прописываются

[Вложение не попало в экспорт: вложение]
Алексей Сугоняев № 38
Евгений Степанищев, да я в общем о том насколько высока необходимость в таком типе данных 0..99, зависит от решаемой задачи. Скажем какой нибудь классический тест 8 ферзей или шашки, вполне себе вписывается в такое решение
Алексей Сугоняев № 41

[01.07.2026 8:08] Roman Krupenko: работает в программе:

ВП 4 — К{x} B^ ВП 2 К[x] С/П

[01.07.2026 8:25] Hs On: Число XXYYZZ может начинаться нулями?
Если да, то подойдут только арифметические методы.
Если нет, то можно с помощью логических операций:
Пх0 КΛ К{х} 3 F10x × С/П,
в регистре 0 хранится число 80FF00XX, где X — любая цифра.

1
Алексей Сугоняев № 42
Наши спортсмены добавили еще два способа в Вашу копилку
арифметический
00. ВП
01. /-/
02. 4
03. K{x}
04. B^
05. ВП
06. 2
07. K[x]
08. С/П
логический
00. ИП0
01. K^
02. k{x}
03. 3
04. F10x
05. *
06. С/П
Регистр П0 содержит число маску 80FF00XX, где X любая цифра, например 80FF077 (FF это две пустышки)
В логическом методе требование не должно быть ведущих нулей то есть хранение вида 002943 как трех переменных недопустимо, решается просто храним всегда с ведущей единичкой которая не влияет на содержимое трех переменных
то есть 1002943
1
Алексей Сугоняев № 45
И так есть еще более короткий способ являющийся модификацией последнего логического метода. Но расход еще один регистр R0=80FF077 R1=1000.
Код:
00. Пх0
01. К^
02. K{x}
03. Пх1
04. ×
05. С/П
1
Алексей Сугоняев № 46
Спортсмены бьют рекорды и дарят нам к минимальным 5 шагам еще и бесплатный переход на адрес 06, по КПП или КБП номер регистра в котором будет хранится константа. Код
00. ПхE
01. КΛ
02. К{х}
03. ПхE
04. ×
05. С/П
В регистр Е заносится значение 10FF, регистр можно любой но его ценность как регистра по которому можно сделать переход растет поэтому от 7 до Е ЕМНИП, без авто инкремента и декремента по косвенному переходу.
Внос значения 10FF в регистр
11088
В↑
11077
KV
K{x}
ВП
4
П(номер регистра)
для подготовки константы