{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "Блоги: заметки с тегом bc",
    "_rss_description": "Автоматически собираемая лента заметок, написанных в блогах на Эгее",
    "_rss_language": "ru",
    "_itunes_email": "",
    "_itunes_categories_xml": "",
    "_itunes_image": false,
    "_itunes_explicit": "no",
    "home_page_url": "https:\/\/blogengine.ru\/blogs\/tags\/bc\/",
    "feed_url": "https:\/\/blogengine.ru\/blogs\/tags\/bc\/json\/",
    "icon": false,
    "authors": [
        {
            "name": "Илья Бирман",
            "url": "https:\/\/blogengine.ru\/blogs\/",
            "avatar": false
        }
    ],
    "items": [
        {
            "id": "136673",
            "url": "https:\/\/bolknote.ru\/all\/kovyryayu-bc\/",
            "title": "Ковыряю bc",
            "content_html": "<p>Ковырял сегодня <tt>bc<\/tt> на досуге, ту версию, которая помощнее. Что-то не очень мне нравится как он написан. Я добавлял в язык одну конструкцию и одну функцию. Конструкцию удалось добавить быстро, а с функцией я возился не один час.<\/p>\n<p>На скриншоте — количество мест, в которые пришлось её прописать. И только в одном из этих мест хранится её реализация. Взял за образец другие объявленные функции, поэтому не имею не малейшего понятия почему так много где пришлось её прописывать, не успел разобраться.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2025.07.17@2x.webp\" width=\"1000\" height=\"231\" alt=\"\" \/>\n<\/div>\n<p>Лучше расскажу что именно я придумал добавить в язык. В <tt>bc<\/tt> есть несколько глобальных переменных, которые очень много на что влияют. Две, наверное, самые важные — это <tt>ibase<\/tt> и <tt>scale<\/tt>. Очень часто их приходится сохранять в начале и восстанавливать в конце своих функций, особенно библиотечных.<\/p>\n<p>У более продвинутого <tt>bc<\/tt> есть специальный ключ, который, если его указать, меняет это поведение — при входе в каждую функцию значения этих и других глобальных переменных будут записываться в специальный стек, а на выходе — восстанавливаться оттуда.<\/p>\n<p>Но библиотечные функции, всё одно, пишут, для универсальности, не рассчитывая на то, что этот флаг установлен. Вот, например, библиотечная функция косинуса:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">define c(x){\n    auto b,s\n    b=ibase\n    ibase=A\n    s=scale\n    scale*=1.2\n    x=s(2*a(1)+x)\n    scale=s\n    ibase=b\n    return(x\/1)\n}<\/code><\/pre><p>Вот я и подумал, чтобы бы неплохо придумать директиву, при указании которой такой стек, для помеченной ею функции, всегда включался бы; а кроме того, была бы полезна функция, которая восстановила бы значения глобальных переменных ещё до выхода из функции. Иногда это необходимо, чтобы вернуть число в соответствии с установленными в них параметрами.<\/p>\n<p>Функция косинуса с этими новыми возможностями выглядела бы так:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">define stack c(x){\n    ibase=A\n    scale*=1.2\n    x=s(2*a(1)+x)\n    pop_stack()\n    return(x\/1)\n}<\/code><\/pre><p>Завтра ещё потестирую и попробую закинуть код автору <tt>bc<\/tt>, вдруг понравится изменение.<\/p>\n<p><i>Добавлено позднее<\/i>: Автор <tt>bc<\/tt> <a href=\"https:\/\/github.com\/gavinhoward\/bc\/pull\/93#issuecomment-3099251028\">написал<\/a>, что идея у меня интересная, но его жизнь серьёзно изменилась и теперь он не будет заниматься проектом бесплатно. Видимо крепко его прижало. Учитывая низкую популярность <tt>bc<\/tt>, можно сказать, что этот проект умер, если у него не найдётся новый мантейнер, что маловероятно.<\/p>\n",
            "date_published": "2025-07-18T00:25:53+05:00",
            "date_modified": "2025-07-23T10:41:17+05:00",
            "tags": [
                "bc",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Fri, 18 Jul 2025 00:25:53 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "136673",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "136318",
            "url": "https:\/\/bolknote.ru\/all\/nedokumentirovannye-vozmozhnosti-bc\/",
            "title": "Недокументированные возможности bc",
            "content_html": "<p>У той версии утилиты <tt>bc<\/tt>, которая является частью проекта <i>GNU<\/i>, есть ряд недокументированных возможностей, про которые я узнал, исследуя её исходный код.<\/p>\n<p>Я уже <a href=\"https:\/\/bolknote.ru\/all\/igra-viselica-na-bc-pod-linuks\/\">писал<\/a> про недокументированную и сломанную функцию <tt>random()<\/tt>, которая починена в новой версии <a href=\"https:\/\/bolknote.ru\/all\/pochinili-random-v-bc\/\">моими усилиями<\/a>. Но кроме этого, есть ещё две вещи отсутствующие в документации.<\/p>\n<p>Во-первых, у самой утилиты есть ключ <nobr><tt>-c<\/tt><\/nobr>, показывающий байт-код, в который переводится программа на языке <tt>bc<\/tt>. Во-вторых, есть альтернативный синтаксис для передачи массива по ссылке — кроме символа <tt>*<\/tt>, как везде, есть нестандартный символ <tt>&amp;<\/tt>.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2025.06.17@2x.webp\" width=\"1000\" height=\"310\" alt=\"\" \/>\n<\/div>\n<p>Но это я сам нашёл, руками. Стало интересно посмотреть, что могут найти языковые модели. Для исследования я выбрал редактор кода «Курсор» и модель <i>Claude Sonnet 4<\/i>.<\/p>\n<p>С первого захода «Клод» нашёл много всего, но бо́льшая часть — вполне обычные возможности, присутствующие в документации. Засучил рукава, порылся в найденном. Кроме мусора там нашлось и полезное — ключ и функцию <tt>random()<\/tt> он нашёл, но про символ <tt>&amp;<\/tt> не упомянул.<\/p>\n<p>Пришлось подтолкнуть — поместить в контекст нужный файл (<tt>bc.y<\/tt>) и спросить нет чего-то недокументированного в нём. Со второго раза «Клод» обнаружил искомое, правда, и в этот раз добавил в список много пунктов не по делу.<\/p>\n<p>С минимальным участием человека нашлись все недокументированные возможности о которых я знаю — три из трёх, правда эти жемчужины пришлось искать вручную в кучке навоза.<\/p>\n<p>Какой вывод?<\/p>\n<p>Я считаю, что это, в определённом смысле, успех — «Клод» помог мне вычленить искомое гораздо быстрее, чем в своё время это сделал я. Да, без моей подсказки третью возможность он не нашёл, но и задача очень и очень нетривиальная.<\/p>\n",
            "date_published": "2025-06-17T20:03:31+05:00",
            "date_modified": "2025-06-28T12:20:17+05:00",
            "tags": [
                "bc",
                "ИИ",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Tue, 17 Jun 2025 20:03:31 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "136318",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "136003",
            "url": "https:\/\/bolknote.ru\/all\/pochinili-random-v-bc\/",
            "title": "Починили random() в bc",
            "content_html": "<p>Вышла версия утилиты <tt>bc<\/tt>, в которую я присылал патч для исправления <a href=\"https:\/\/bolknote.ru\/all\/gnu-bc-i-random\/\">проблемы<\/a> с функцией для получения случайных значений. Исправление попало в версию 1.08.2.<\/p>\n<p>Интересно, что в авторы исправления меня не записали, зато поблагодарили, записав имя и фамилию русскими буквами, хотя в конце письма я подписался латиницей:<\/p>\n<blockquote>\n<p>Thu Apr 10 12:59:31 PDT 2025 Ken Pizzini &lt;ken@gnu.org&gt;<br \/>\nbc\/execute.c: Call srandom(time(NULL)) to seed the random number generator with something other than a built-in constant.  Thanks to Евгений Степанищев for the bug report.<\/p>\n<\/blockquote>\n",
            "date_published": "2025-05-29T15:54:54+05:00",
            "date_modified": "2025-05-29T16:23:47+05:00",
            "tags": [
                "bc"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Thu, 29 May 2025 15:54:54 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "136003",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "135778",
            "url": "https:\/\/bolknote.ru\/all\/ide-cursor\/",
            "title": "«Курсор»",
            "content_html": "<p>Что-то я опять по кривой Гартнера свалился на дно разочарования в «Курсоре» — это редактор, где можно программировать с помощью нейросетей. Из семи последних задач «Курсор» запорол все семь, да ещё как эпично! Задачи, на мой взгляд, я описывал понятно — так, как описал бы живому программисту.<\/p>\n<p>Чтобы отойти от разочарования, решил как-то реабилитировать технологию в своих глазах, тем более, что некоторые мои задачи нейросети всё-таки выполняют. Взял <a href=\"https:\/\/github.com\/gavinhoward\/bc\/blob\/master\/gen\/lib2.bc\">библиотеку функций<\/a> из продвинутой реализации <tt>bc<\/tt>, чтобы попробовать портировать её на версию <i>GNU<\/i>.<\/p>\n<p>Попросил три понятных изменения сделать, любой дурак справится:<\/p>\n<ul>\n<li>a@b заменить на вызов функции <tt>floor(a, b)<\/tt>, которую я написал;<\/li>\n<li>a$ заменить на вызов <tt>floor(a, 0)<\/tt>;<\/li>\n<li>там, где оператор <tt>else<\/tt> перенесен на другую строку от конструкции <tt>if<\/tt>, надо либо заэкранировать перенос через обратный слеш, либо вернуть <tt>else<\/tt> на одну строку с <tt>if<\/tt>.<\/li>\n<\/ul>\n<p>Задача простая, но даже тут «Курсор» накосячил, не справившись с подсчётом скобок. В итоге, тщательно проверял все замены и считал скобки я сам. К чёрту такую автоматизацию, по сумме, я бы сам быстрее сделал.<\/p>\n<p>Раньше я бы к этому спокойно отнёсся, но в последнее время раздражительность повысилась — мёрзну и всё время на грани простуды. Отопление давно отключили, а на улице резко похолодало — снег уже несколько раз шёл. Но, видимо, недостаточно холодно, чтобы включать отопление обратно.<\/p>\n<p>Вокруг очень многие болеют пневмонией, это ещё что такое, откуда? Я уверен, что слово «пневмония» я слышал за прошедшие два года больше, чем за всю прошлую жизнь. Сам я всё время кашляю, хотя не чувствуется, что болею, временами только какая-то слабость накатывает.<\/p>\n",
            "date_published": "2025-05-09T11:35:04+05:00",
            "date_modified": "2025-05-09T11:18:19+05:00",
            "tags": [
                "bc",
                "ИИ",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Fri, 09 May 2025 11:35:04 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "135778",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "135632",
            "url": "https:\/\/bolknote.ru\/all\/krossplatformennost-i-bc\/",
            "title": "Кроссплатформенность и bc",
            "content_html": "<p>Как мы все знаем, в мире существует две версии <tt>bc<\/tt> — более скромная по возможностям версия <i>GNU<\/i>, которая используется в Линуксе, и более развитая, которая, например, используется в командной строке МакОСи.<\/p>\n<p>Они довольно серьёзно различаются — когда я писал игру «<a href=\"https:\/\/github.com\/bolknote\/bc-hangman\">Виселица<\/a>» на этом языке, мне пришлось сделать две версии для разных синтаксисов.<\/p>\n<p>В принципе, можно писать кроссплатформенно, если использовать подмножество, которое поддерживают обе версии, но есть одна неприятность — функция получения случайного числа в гну-версии называется <tt>random()<\/tt>, а в более продвинутой — <tt>rand()<\/tt> (точнее там их целое семейство, но функции <tt>random()<\/tt> там нет).<\/p>\n<p>Поскольку в языке нет способа узнать определена функция или нет, нужно каким-то образом отличать одну версию от другой и вызывать, в зависимости от результата, ту или другую функцию.<\/p>\n<p>Каким же образом мы можем это сделать?<\/p>\n<p>Вначале я возлагал надежду на переменную <tt>seed<\/tt>. В <i>GNU<\/i> её нету, то есть она содержит ноль, а в продвинутой версии она содержит инициализирующее значение. Как будто этого вполне достаточно, но, во-первых, никто не обещает, что она по какой-то случайности не получит нулевое значение, а во-вторых, её вполне могут реализовать в версии <i>GNU<\/i>. Нужно что-то принципиально другое, что в будущем не будет работать иначе, правка или реализация которого сломала бы обратную совместимость.<\/p>\n<p>Такую особенность я нашёл — она заключается в приоритете обработки операции отрицания, которая записывается как восклицательный знак.<\/p>\n<p>Из-за этой разницы две версии по-разному вычисляют конструкцию <tt>!1+1<\/tt>. В продвинутой версии порядок выполнения следующий: <tt>(!1)+1<\/tt>, что даёт нам единицу, а в гнушной приоритет другой и конструкция выполнится так: <tt>!(1+1)<\/tt>, что даёт нам ноль.<\/p>\n<p>Основываясь на этом, мы можем написать универсальную функцию для получения случайного числа:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">define rnd() {\n    \/* Checking the bc version *\/\n    if (!1+1) {\n        return rand()\n    } else {\n        return random() * random()\n    }\n}<\/code><\/pre><p>P. S. Надо помнить, что в гну-версии функция получения случайного числа сломана, но <a href=\"https:\/\/bolknote.ru\/all\/gnu-bc-i-random\/\">есть надежда<\/a>, что скоро её починят и ей можно будет пользоваться.<\/p>\n<p>P. P. S. Я умножаю <tt>random()<\/tt> на <tt>random()<\/tt>, чтобы хоть немного выровнять по диапазону значений <tt>rand()<\/tt> и <tt>random()<\/tt>.<\/p>\n",
            "date_published": "2025-04-21T21:04:35+05:00",
            "date_modified": "2025-04-21T22:24:21+05:00",
            "tags": [
                "bc",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Mon, 21 Apr 2025 21:04:35 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "135632",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "135565",
            "url": "https:\/\/bolknote.ru\/all\/gnu-bc-i-random\/",
            "title": "GNU bc и random()",
            "content_html": "<p>Я не задумывался об этом раньше, но это здорово сбивает с толку, что в мире есть две различающиеся версии <i>bc<\/i> — одна является частью проекта <i>GNU<\/i> и поставляется в дистрибутивах Линукса, а вторая развивается другим коллективом авторов и входит, например, в состав МакОСи.<\/p>\n<p>Я уже поучаствовал в разработке последней — предложил <a href=\"https:\/\/bolknote.ru\/all\/uskorenie-operaciy-v-bc\/\">изменение<\/a> ускоряющее некоторые операции и <a href=\"https:\/\/bolknote.ru\/all\/popravil-oshibku-v-bc\/\">исправил одну ошибку<\/a>, а теперь, пока был отпуске, внёс вклад и в версию проекта <i>GNU<\/i>.<\/p>\n<p>Как я <a href=\"https:\/\/bolknote.ru\/all\/igra-viselica-na-bc-pod-linuks\/\">как-то писал<\/a> в этой версии есть недокументированная и бесполезная функция <tt>random()<\/tt>, которая возвращает всегда одно и то же число, так как автор забыл проинициализировать генератор случайных чисел.<\/p>\n<p>Я подумал — чем чёрт не шутит? Если предложить своё исправление и в этот проект, то, может, его тоже примут? Так как открытого репозитория кода у <i>bc<\/i> проекта <i>GNU<\/i> нет, свой патч я отправил на почту мантейнеру.<\/p>\n<p>Он ответил почти сразу, поблагодарил за исправление бага и написал, что сейчас же внесёт исправление в код. Так что, вероятно, следующая версия <i>bc<\/i> выйдет уже с нормально работающей функцией <tt>random()<\/tt>!<\/p>\n",
            "date_published": "2025-04-14T21:23:55+05:00",
            "date_modified": "2025-04-14T21:23:51+05:00",
            "tags": [
                "bc",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Mon, 14 Apr 2025 21:23:55 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "135565",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "135334",
            "url": "https:\/\/bolknote.ru\/all\/strannosti-bc\/",
            "title": "Странности bc",
            "content_html": "<p>Чем больше узнаёшь <tt>bc<\/tt>, тем больше в нём находишь странностей. Особенно меня поражают массивы.<\/p>\n<p>Например, как вы думаете, чему равна длина массива, в который мы ещё ни разу не инициализировали? Правильно, единице. Почему? Да чёрт его знает, так в коде написано:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">void\nbc_array_init(BcVec* a, bool nums)\n{\n    BC_SIG_ASSERT_LOCKED;\n\n    \/\/ Set the proper vector.\n    if (nums) bc_vec_init(a, sizeof(BcNum), BC_DTOR_NUM);\n    else bc_vec_init(a, sizeof(BcVec), BC_DTOR_VEC);\n\n    \/\/ We always want at least one item in the array.\n    bc_array_expand(a, 1);\n}<\/code><\/pre><p>Или вот такой код:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">define void f(*a[]) {\n    . = a[99]\n}\n\nf(b[]); length(b[])<\/code><\/pre><p>Чему будет равна длина массива <tt>b[]<\/tt>?<\/p>\n<p>Правильный ответ — она будет равна ста. Потому что в функции, куда мы передали этот массив по ссылке, происходит чтение из 99-го (массивы начинаются с нуля) элемента. В коде <tt>bc<\/tt> ясно сказано:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">\/\/ The bc spec says that if an element is accessed that does not\n\/\/ exist, it should be preinitialized to 0. Well, if we access\n\/\/ an element *way* out there, we have to preinitialize all\n\/\/ elements between the current last element and the actual\n\/\/ accessed element.\nif (v-&gt;len &lt;= idx)\n{\n    BC_SIG_LOCK;\n    bc_array_expand(v, bc_vm_growSize(idx, 1));\n    BC_SIG_UNLOCK;\n}<\/code><\/pre><p>Как только идёт обращение к несуществующему элементу массива, неважно, для чтения или записи, он получается значение «ноль».<\/p>\n<p>В этих случаях я даже уже и не понимаю — баги это или нет. Вроде нет, но выглядит контринтуитивно.<\/p>\n",
            "date_published": "2025-03-26T01:15:37+05:00",
            "date_modified": "2025-03-26T01:14:59+05:00",
            "tags": [
                "bc",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Wed, 26 Mar 2025 01:15:37 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "135334",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "135321",
            "url": "https:\/\/bolknote.ru\/all\/popravil-oshibku-v-bc\/",
            "title": "Поправил ошибку в bc",
            "content_html": "<p>Вчера часа проснулся около часа ночи, сна ни в одном глазу. Ворочался-ворочался, думаю надо бы заняться чем-нибудь, мозг утомить. Решил почитать исходный код <tt>bc<\/tt>. Он остался у меня с того раза, когда я <a href=\"https:\/\/bolknote.ru\/all\/uskorenie-operaciy-v-bc\/\">коммитил туда<\/a> своё предложение по ускорению функции <tt>band()<\/tt>.<\/p>\n<p>Бродил по коду туда-сюда, читал случайные куски, пока не дошёл до кусочка, проверяющего дублирующиеся параметры у функции. Вот это место:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">for (i = 0; i &lt; f-&gt;autos.len; ++i)\n{\n\t\/\/ Get the auto.\n\tBcAuto* aptr = bc_vec_item(&amp;f-&gt;autos, i);\n\n\t\/\/ If they match, barf.\n\tif (BC_ERR(idx == aptr-&gt;idx &amp;&amp; type == aptr-&gt;type))\n\t{\n\t\tconst char* array = type == BC_TYPE_ARRAY ? &quot;[]&quot; : &quot;&quot;;\n\n\t\tbc_error(BC_ERR_PARSE_DUP_LOCAL, line, name, array);\n\t}\n}<\/code><\/pre><p>Посмотрел что тут происходит и заметил, что в перечислении, описывающем виды параметров, вообще-то три значения — скаляр, массив и массив, передающийся по ссылке. При этом код выше написан так, как будто их только два. Небольшой тест показал, что так и есть. Следующий код должен порождать ошибку, между тем, он выполняется как ни в чём не бывало:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">define a(*t[], t[]) {}<\/code><\/pre><p>Подумал, что уже достаточно утомился, чтобы лечь спать, но не тут-то было! Стоило закрыть глаза, как мозг начал продумывать как поизящнее исправить этот баг. Пришлось снова открыть ноутбук и <a href=\"https:\/\/github.com\/gavinhoward\/bc\/pull\/89\">править<\/a>.<\/p>\n<p>Уже утром я прочитал сообщение по моему коммиту — автор <tt>bc<\/tt> попросил отформатировать код и написать небольшой тест. Я всё исправил и теперь ещё немного моего кода есть в этой прекрасной утилите!<\/p>\n",
            "date_published": "2025-03-25T10:55:32+05:00",
            "date_modified": "2025-03-25T11:23:59+05:00",
            "tags": [
                "bc",
                "программирование",
                "си"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Tue, 25 Mar 2025 10:55:32 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "135321",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "134969",
            "url": "https:\/\/bolknote.ru\/all\/prinyali-kommit-v-bc\/",
            "title": "Приняли коммит в bc",
            "content_html": "<p>Как-то быстро и неожиданно мой коммит, <a href=\"https:\/\/bolknote.ru\/all\/uskorenie-operaciy-v-bc\/\">ускоряющий<\/a> функцию <tt>band()<\/tt>, <a href=\"https:\/\/github.com\/gavinhoward\/bc\/pull\/88\">приняли<\/a> в репозиторий <tt>bc<\/tt>. Что ещё круто, основываясь на той же идее, автор ускорил функции <tt>bnotn()<\/tt>, <tt>bor()<\/tt> и <tt>bxor()<\/tt>. Я тоже думал ими заняться, если мой коммит примут, а он уже сам всё сделал. Отлично!<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2025.03.01@2x.webp\" width=\"1000\" height=\"240\" alt=\"\" \/>\n<\/div>\n",
            "date_published": "2025-03-01T14:11:29+05:00",
            "date_modified": "2025-03-01T14:41:50+05:00",
            "tags": [
                "bc",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Sat, 01 Mar 2025 14:11:29 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "134969",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "134889",
            "url": "https:\/\/bolknote.ru\/all\/uskorenie-operaciy-v-bc\/",
            "title": "Ускорение операций в bc",
            "content_html": "<p>Как вы помните, я недавно устроил себе суточный хакатон, писал «<a href=\"https:\/\/bolknote.ru\/all\/doom-na-bc\/\">Дум<\/a>» на <tt>bc<\/tt>. Получился он тогда довольно медленным, особенно когда на экране было много объектов. Сейчас я его потихоньку оптимизирую, но так как профилирования в <tt>bc<\/tt> не существует, двигаюсь наугад.<\/p>\n<p>По сути я до сих пор не знаю, на что там уходит больше всего времени, но иногда выбираю час-другой посмотреть какие операции ещё можно ускорить. Что, в целом, обычно, положительно сказывается на производительности.<\/p>\n<p>В стандартной библиотеке <tt>bc<\/tt> есть много функций, написанных нативно. Их, как правило, удаётся так или иначе ускорить, поэтому я решил посмотреть что у меня из такого ещё используется. Взор пал на функцию <tt>band()<\/tt>, особенно в форме <tt>(band(a, b) && 1)<\/tt>, то есть там, где всё, что меня интересует — установлен бит или нет. У меня в коде было несколько таких мест.<\/p>\n<p>Написал свой вариант по мотивам того кода, который используется в стандартной библиотеке:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">define check_bit(x, y) {\n    auto result, m[]\n    result = 0\n    scale = 0\n\n    while (x &amp;&amp; y) {\n        x = divmod(x, 2, m[])\n        if (m[0]) {\n            y = divmod(y, 2, m[])\n            result += m[0]\n        } else {\n            y \/= 2\n        }\n    }\n    return result\n}<\/code><\/pre><p>Получилось быстрее почти в два с половиной раза. Саму операцию <tt>band()<\/tt> тоже удалось ускорить в 1,7 раза, в «чистом» виде она у меня в коде тоже есть. Думаю, может сделать коммит в код <tt>bc<\/tt>?<\/p>\n<p><i>Добавлено:<\/i> <a href=\"https:\/\/github.com\/gavinhoward\/bc\/pull\/88\">коммит сделал<\/a>. Но беда — автор <tt>bc<\/tt> в примечании к репозиторию на «Гитхабе» написал, что с «Гитхаба» он ушёл. К сожалению, то место, куда он ушёл не работает. Так что коммит пришлось залить на «Гитхаб», больше-то некуда.<\/p>\n",
            "date_published": "2025-02-26T23:11:19+05:00",
            "date_modified": "2025-02-27T21:02:23+05:00",
            "tags": [
                "bc",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Wed, 26 Feb 2025 23:11:19 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "134889",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "134747",
            "url": "https:\/\/bolknote.ru\/all\/uluchshenie-v-slovare-na-bc\/",
            "title": "Улучшение в словаре на bc",
            "content_html": "<p>За последние недели мой уровень в <tt>bc<\/tt> очень сильно вырос. Я стал видеть вещи в своих прежних проектах, которые можно сделать проще и изящнее. Но, кажется, мой рост остановился. Интересно, достиг ли я потолка? Или, может, стал ли я сеньором в этом? Не пора ли мне учить других? Открыть курсы, поднимать сообщество? Вопросы без ответов!<\/p>\n<p>В общем, открыл сегодня, пока ехал в такси, исходник своего <a href=\"https:\/\/bolknote.ru\/all\/anglo-russkiy-slovar-na-bc\/\">англо-русского словаря<\/a>, написанного на <tt>bc<\/tt>, и пришло мне в голову очевидное — не нужно хранить слова в десятичных числах, они длинные и непонятные, надо хранить их как они есть — в виде слов, ведь у нас в <tt>bc<\/tt> есть 36-ричная система счисления, то есть десять цифр и 26 букв.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2025.02.20@2x.webp\" width=\"1000\" height=\"300\" alt=\"\" \/>\n<\/div>\n<p>Почему же я раньше-то до такой простой штуки не додумался? Всё приходит с опытом.<\/p>\n<p><i>Добавлено<\/i>: грустно — на скриншоте обнаружил ошибки в словаре, который я использую.<\/p>\n",
            "date_published": "2025-02-20T21:51:09+05:00",
            "date_modified": "2025-02-21T11:47:04+05:00",
            "tags": [
                "bc",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Thu, 20 Feb 2025 21:51:09 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "134747",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "134710",
            "url": "https:\/\/bolknote.ru\/all\/bystry-koren-iz-summy-kvadratov\/",
            "title": "Быстрый корень из суммы квадратов",
            "content_html": "<p>Я недавно писал как ускорял свой «<a href=\"https:\/\/bolknote.ru\/all\/doom-na-bc\/\">Дум<\/a>» для <tt>bc<\/tt>. В частности я заменял тригонометрические функции их менее точными, но более быстрыми, аналогами.<\/p>\n<p>Роман Парпалак <a href=\"https:\/\/bolknote.ru\/all\/uskorenie-trigonometricheskih-funkciy-v-bc\/#:~:text=Роман%20Парпалак\">посоветовал способ<\/a> ускорения вычисления квадратного корня из суммы квадратов. Аппроксимация там через формулу <tt>0,96 × x + 0,4 × y<\/tt> при <tt>x<\/tt> ≥ <tt>y<\/tt>. Погрешность должна быть не более 4%.<\/p>\n<p>Выглядит здорово, я замерил — производительность вырастает в восемь раз, заманчиво, но если посмотреть абсолютную погрешность там она почти 5,5 единиц. Это как будто бы очень много. Я даже нарисовал график разницы между корнем и аппроксимацией в «Днунипере».<\/p>\n<p><video src=\"\/pictures\/2025.02.19@2x.mp4\" autoplay playsinline width=500 height=400 loop muted><\/video><\/p>\n<p>Заменять я не буду, но знать о такой возможности полезно, спасибо, Роман!<\/p>\n",
            "date_published": "2025-02-19T15:55:21+05:00",
            "date_modified": "2025-02-23T13:32:36+05:00",
            "tags": [
                "bc",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Wed, 19 Feb 2025 15:55:21 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "134710",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "134355",
            "url": "https:\/\/bolknote.ru\/all\/doom-na-bc\/",
            "title": "Doom на bc",
            "content_html": "<p>Давно хотел повысить градус безумия своих приложений и изобразить что-нибудь трёхмерное в терминале. Изначально я планировал использовать для этого <i>ASCII<\/i>-графику, но вспомнил, что немного <a href=\"https:\/\/bolknote.ru\/all\/4432\/\">экспериментировал с выводом<\/a> растра в консоли и решил замахнуться на пиксельное изображение.<\/p>\n<p>Писать начал, разумеется, на одном из самых далёких от вывода графики на экран языков — <tt>bc<\/tt>, я ведь теперь всё на нём пишу (ха-ха). Для работы с  графикой в нём нет буквально ни-че-го! Попутно решить считать это хакатоном — дал себе сутки на реализацию. В итоге, писать начал утром, а закончил в три ночи.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2025.02.13.1@2x.webp\" width=\"350\" height=\"210\" alt=\"\" \/>\n<div class=\"e2-text-caption\">Что получилось в конечном счёте: экранчик игры, внизу набранные очки, количество оставшихся врагов, полоска здоровья, выше головы поверженных противников<\/div>\n<\/div>\n<p>Как вообще устроен вывод графики в текстовый терминал? Надо сказать, что как правило, терминал у нас текстовый число номинально. Да, там выводятся какие-то символы, но в конечном счёте терминал выводит их готовыми картинками на графический экран, а не алфавитно-цифровой, как встарь.<\/p>\n<p>Обычно мы отсылаем в терминал какие-то символы и он их отображает, а как же передать ему графику? Для этого придумали несколько несовместимых способов. Моя любимая программа для работы в терминале <i>iTerm2<\/i> придумала собственный. Графику в этом формате можно передать в терминал специальной текстовой командой:<\/p>\n<pre class=\"e2-text-code\"><code class=\"nginx\">ESC ] 1337 ; File = [необязательные параметры] : изображение в формате base64 ^G<\/code><\/pre><p>Хорошо, с этим разобрались. Но как нарисовать картинку именно из <tt>bc<\/tt>? Тут надо решить несколько очевидных проблем.<\/p>\n<p>Во-первых, графику надо как-то хранить внутри программы. Тут выбора особо нет, со структурами данных в <tt>bc<\/tt> негусто, — картинка будет храниться в одномерном массиве, где строки изображения будут последовательно записываться одна за другой.<\/p>\n<p>Во-вторых, нужно написать свою реализацию кодирования <tt>base64<\/tt>. Это, конечно, дело техники, но требует усилий. Тут, кстати, очень помогла обнаруженная в описании языка функция <tt>asciify()<\/tt>, которая переводит код символа в сам символ.<\/p>\n<p>В-третьих, и самое интересное, — нужно выбрать какой-то простой бинарный формат, в котором будет формироваться графика. Тут я сразу подумал о <i>BMP<\/i>, так как  в 2005-м году делал <a href=\"https:\/\/bolknote.ru\/all\/278\/\">библиотеку для работы<\/a> с ним на <i>PHP<\/i>.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2025.02.13.2@2x.webp\" width=\"1000\" height=\"315\" alt=\"\" \/>\n<div class=\"e2-text-caption\">Сохранившийся скриншот, где я пытаюсь аккуратно расписать для себя формат <i>BMP Core<\/i><\/div>\n<\/div>\n<p><i>BMP<\/i> — это, как водится во многих старых форматах, внутренне не один формат хранения графики, а несколько. В данном случае я взял самый простой и примитивный — <i>BMP Core<\/i> с индексированной палитрой из двух цветов.<\/p>\n<p>Его плюс — у него очень простой заголовок и его относительно дёшево формировать. Тем более, что мне не хотелось возиться со сжатием, количество вычислений для этого могло превысить все разумные пределы.<\/p>\n<p>Теперь надо было решить что же я буду писать. На самом деле к этому моменту я уже внутренне определился. В начале двухтысячных локальный фурор произвела игрушка «<a href=\"https:\/\/web.archive.org\/web\/20031205101316\/http:\/\/www.wolf5k.com\/\"><i>Wolf5k<\/i><\/a>», написанная на ДжаваСкрипте. Чтобы понять, чем она крута, надо знать, что ДжаваСкрипт тогда графику выводить не умел — не существовало ни тега <tt>CANVAS<\/tt>, ни, тем более, <i>WebGL<\/i> или <i>WebGPU<\/i>.<\/p>\n<p>Изображение формировалось в текстовом формате <i>XBM<\/i>, которое, через весьма остроумный хак, показывалось в браузере. На настоящий момент поддержки этого формата давно уже нет ни в одном современном браузере.<\/p>\n<p>Это как будто могло быть очень символично — сделать порт игрушки, которая выводила свою графику на языке, для этого в те годы непригодном, на язык, который так же непригоден для этого сейчас.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2025.02.13.3@2x.webp\" width=\"1000\" height=\"292\" alt=\"\" \/>\n<div class=\"e2-text-caption\">Вот и весь исходный код «<i>Wolf5k<\/i>»<\/div>\n<\/div>\n<p>К несчастью, исходный код игры обфусцирован и, когда я в самом начале сел за его чтение, был в отчаянии — мне казалось, что за отведённый самому себе суточный срок разобраться не получится. К счастью, раскопки в веб-архиве принесли в сетях <a href=\"https:\/\/web.archive.org\/web\/20041208223205\/http:\/\/www.icarusindie.com\/DoItYourSelf\/javascript3D\/deobfwolk5k.php\">частично деобфусцированный<\/a> исходник. С ним я и начал работать.<\/p>\n<p>Не буду описывать все сложности, с которыми пришлось столкнуться, но примерно к полуночи у меня получился код, который умел рендерить картинку покадрово — к тому времени я ещё не решил проблему опроса клавиатуры и мой «игрок» просто крутился на одном месте. В рендере я увидел несколько проблем, но не критичных.<\/p>\n<p>Самой большой проблемой была производительность. Но это я отложил на следующий день — решил, что работающая, но немного глючащая и сильно подтормаживающая игра, написанная за сутки — удовлетворительный результат. До окончания хакатона мне предстояло решить ещё одну проблему — проблему опроса клавиатуры.<\/p>\n<p>«<i>Wolf5k<\/i>» — динамичная игра, а во всём языке <tt>bc<\/tt> единственная функция ввода — <tt>read()<\/tt>, которая требует нажатия на «Энтер» после каждого ввода. Такой себе интерактив.<\/p>\n<p>В самом языке это никак не решить, так что, признаюсь, тут я немного смухлевал — написал на <tt>zsh<\/tt> запускающую часть, которая сама читает клавиатуру и пересылает нажатия в <tt>bc<\/tt>, «нажимая» на «Энтер»:<\/p>\n<pre class=\"e2-text-code\"><code class=\"bash\">#!\/bin\/zsh\nx=\/*\nwhile {}; do\n    v=\n    read -rs -k1 -t0.4 v\n\n    case &quot;${v:l}&quot; in\n        [wasdljkm\\ ]) printf &quot;%d\\n&quot; &quot;&#039;${v:l}&quot;;;\n        *)    echo 0;;\n    esac\ndone | bc -g -Ll -f &quot;$0&quot;\nexit; *\/1\n\/* тут программа на bc *\/<\/code><\/pre><p>Да, не очень честно, но какой выбор?<\/p>\n<p>К трём ночи у меня была игрушка, в которой всё работало на три с плюсом, особенно, если на экране было не так много объектов. Правда, при поворотах враги иногда пропадали, а иногда взлетали и улетали за пределы экрана. Но в <i>это<\/i> уже можно было играть.<\/p>\n<p>У меня был соблазн опубликовать её на следующий же день, но хорошо, что я дал коду «отлежаться». Во-первых, успел пофиксить все баги, во-вторых, придумал несколько трюков для ускорения, <a href=\"https:\/\/bolknote.ru\/all\/uskorenie-trigonometricheskih-funkciy-v-bc\/\">один из которых<\/a> описал вчера.<\/p>\n<p>Результат <a href=\"https:\/\/github.com\/bolknote\/bc-doom\">выложил в свой репозиторий<\/a>. Несмотря на то, что это порт «<i>Wolf5k<\/i>», игра называется <i>BC-Doom<\/i>, а не <i>BC-Wolf<\/i>, потому что как-то так повелось, — называть все подобные трёхмерные игрушки «Думом», а про «Вульф» уже никто и не помнит, как мне кажется.<\/p>\n",
            "date_published": "2025-02-13T23:30:24+05:00",
            "date_modified": "2025-04-09T09:52:48+05:00",
            "tags": [
                "bc",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Thu, 13 Feb 2025 23:30:24 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "134355",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "134267",
            "url": "https:\/\/bolknote.ru\/all\/uskorenie-trigonometricheskih-funkciy-v-bc\/",
            "title": "Ускорение тригонометрических и прочих функций в bc",
            "content_html": "<p>Интересно, что вся стандартная библиотека (подключаемая через ключ <tt>-l<\/tt>) для <tt>bc<\/tt> написана нативно. С одной стороны, это не очень-то здорово, так как не использует всю мощь современных процессоров для вычисления различных функций, с другой стороны, эти функции можно свободно переопределить, если мы готовы пожертвовать точностью.<\/p>\n<p>Я тут потихоньку ускоряю одну из своих программ на <tt>bc<\/tt>, но все «низко висящие фрукты» я уже подобрал. Добрался до тригонометрических функций. Во внутренней библиотеке косинус <a href=\"https:\/\/github.com\/gavinhoward\/bc\/blob\/master\/gen\/lib.bc#L120\">выражается через синус<\/a>, так что, если ускорить синус, то ускорится сразу и косинус.<\/p>\n<p>Посмотрел разные реализации, в итоге портировал функцию, которую взял из одной из <a href=\"https:\/\/habr.com\/ru\/companies\/ruvds\/articles\/584460\/\">статей на «Хабре»<\/a>, получилось так (используется многочлен Чебышёва):<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">define mod(a, b) {\n    auto s, m\n    s = scale; scale = 0; m = a$ % b$; scale = s; return m\n}\n\ndefine s(x) {\n    auto sign, xf, per, xx, y\n\n    x *= 0.63661977236758134308\n    if (sign = (x &lt; 0)) x = -x\n\n    xf = x$\n    x -= xf\n\n    if (mod(xf, 2)) x = 1 - x\n\n    per = mod(xf \/ 2, 2)\n    xx = x * x\n    y = x * (1.5707903005870776 + xx * (-0.6458858977085938 + \\\n    xx*(0.07941798513358536 - 0.0043223880120647346 * xx)))\n\n    if (sign != per) return -y\n    return y\n}<\/code><\/pre><p>Расхождение со встроенной в <tt>bc<\/tt> реализацией начинается в седьмом знаке, это более чем достаточно для меня, зато вычисление синуса ускорилось больше, чем в четыре раза.<\/p>\n<p><i>Добавлено позднее<\/i>: ещё я заменил функцию нахождения логарифма по основанию десять. Логарифмом я находил количество разрядов числа, чтобы потом вывести его на экран, так что его легко было заменить на цикл с подсчётом порядка делением. Разница в производительности — больше, чем в 60 раз.  Код теперь выглядит так:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">define cnt_digits(x) {\n    auto i, s\n    s = scale; scale = 0\n\n    for (i = 0; x \/= 10; i++){}\n    scale = s; return i\n}<\/code><\/pre>",
            "date_published": "2025-02-12T21:56:02+05:00",
            "date_modified": "2025-02-13T09:44:45+05:00",
            "tags": [
                "bc",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Wed, 12 Feb 2025 21:56:02 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "134267",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "134183",
            "url": "https:\/\/bolknote.ru\/all\/neobychnaya-sistema-schisleniya-v-bc\/",
            "title": "Необычная система счисления в bc",
            "content_html": "<p>В моём временно любимом <tt>bc<\/tt> есть интересная, но не сразу понятная особенность работы с числами. Даже в режиме ввода десятичных чисел принимаются буквы в верхнем регистре, то есть число может состоять из цифр в диапазонах 0…9 и <i>A<\/i>…<i>Z<\/i>. Буквы при этом обозначают цифры от десяти до тридцати пяти.<\/p>\n<p>Но так как режим десятичный, результирующее значение числа, содержащего буквы, вычисляется необычно. Я специально не описываю словами, ниже скажу почему. Принцип на картинке, думаю, понятно как всё получается.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2025.02.11@2x.webp\" width=\"1000\" height=\"377\" alt=\"\" \/>\n<\/div>\n<p>Мне стало интересно решить задачу конвертации десятичных чисел в такую необычную систему. Из самого принципа следует, что десятичное число может быть представлено несколькими способами, так что придумать можно куда больше одного алгоритма.<\/p>\n<p>Сегодня на работе, пока обедали с братишкой, пытались в режиме обсуждения решить задачу в уме. Потратили на это почти весь обед, в конце я перенёс то, что придумалось, в код программы:<\/p>\n<pre class=\"e2-text-code\"><code class=\"python\">def convert(num):\n    if num == 0: return 0\n    out, orig_num = &quot;&quot;, num\n\n    while num:\n        num, r = divmod(num, 10)\n        v = min(2 if r &gt; 5 else 3, num)\n        if (digit := v * 10 + r) &gt; 9:\n            out = chr(digit - 10 + ord(&#039;A&#039;)) + out\n        else:\n            out = str(digit) + out\n\n        num -= v\n\n    return out if len(out) &lt; len(str(orig_num)) else orig_num<\/code><\/pre><p>А потом мы решили развлечься ещё одним способом — аккуратно сформулировать эту задачу в тексте и решить её искусственным интеллектом. Взяли топовые сети — ЧатГПТ, ДипСик и так далее.<\/p>\n<p>Я намеренно не показываю получившийся промпт, вдруг вы захотите тоже попробовать, но скажу сразу — с первого или даже пятого раза сформулировать задачу так, чтобы хоть какая-нибудь нейросеть решила её правильно у нас не получилось. Я, в итоге, сдался, а братишка добился-таки код, который её решает, от ДипСика. Листинг, правда, получился вдвое длиннее, чем у меня.<\/p>\n<p>Из этого можно сделать важный и почему-то не всем очевидный вывод: иногда задачу проще решить самому, потому что сформулировать её нейросети — очень сложное занятие.<\/p>\n<p>А если посмотреть чуть глубже, то можно додуматься вот до чего. В ближайшее время искусственный интеллект не убьёт профессию программиста, а просто её модифицирует. Сейчас программисты описывают задачу, переведённую ими в алгоритм, на языке программирования, а в будущем буду описывать её на натуральных языках.<\/p>\n",
            "date_published": "2025-02-11T22:05:21+05:00",
            "date_modified": "2025-02-11T22:05:08+05:00",
            "tags": [
                "bc",
                "python",
                "ИИ"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Tue, 11 Feb 2025 22:05:21 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "134183",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "134018",
            "url": "https:\/\/bolknote.ru\/all\/eschyo-nemnogo-pro-random-v-bc\/",
            "title": "Ещё немного про random() в bc",
            "content_html": "<p>Как я уже рассказывал, <tt>bc<\/tt> под «Линуксом» очень старый, — на всех машинах, куда у меня есть доступ, установлена версия 1.07.1 2017-го года. Непонятно с чем связан такой консерватизм, но чем богаты. В этой версии отсутствует до печального много удобных вещей, например, функция для получения случайного числа.<\/p>\n<p>Ранее я <a href=\"https:\/\/bolknote.ru\/all\/igra-viselica-na-bc-pod-linuks\/\">обнаружил<\/a> недокументированную функцию <tt>random()<\/tt>, но генератор случайных чисел в линуксовом <tt>bc<\/tt> не инициализируется и функция выдаёт на старте всегда одно и тоже число. Её можно покрутить снаружи случайное число раз и это исправляет ситуацию, но способ, который я тогда придумал для этого, так себе.<\/p>\n<p>Сегодня, пока ехал в такси, придумывал ещё более так себе способы это сделать.<\/p>\n<p>Мысль моя крутилась вокруг запуска через утилиту <tt>env<\/tt>. В мире командной строки так частенько делают, так что этот способ как будто бы чуть более честный, так шелл тут не используется:<\/p>\n<pre class=\"e2-text-code\"><code class=\"bash\">#!\/usr\/bin\/env -S -i seed_=&quot;0${XDG_SESSION_ID};while(seed_--).=random()#&quot; bc \/proc\/self\/environ\nprint random()\nquit()<\/code><\/pre><p>Здорово, правда?<\/p>\n<p>Вся чёрная магия сосредоточена в первой строке. Файл <tt>\/proc\/self\/environ<\/tt> формируется в «Линуксе» для каждого запущенного процесса и содержит унаследованные переменные окружения. Так как там много ненужного нам мусора, очищаем его целиком при помощи ключа <tt>-i<\/tt> утилиты <tt>env<\/tt>.<\/p>\n<p>Далее мы создаём переменную окружения <tt>seed_<\/tt>, а внутри её формируем небольшую программу, которая запустится до нашего кода. Для <tt>bc<\/tt> результат будет выглядеть так:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">seed_=0123456\nwhile(seed_--).=random()\n#^@\nprint random()\nquit()<\/code><\/pre><p>Я развернул односрочную программу в многострочную для удобства.<\/p>\n<p>Вместо <tt>123456<\/tt>, конечно, будет подставлено число из переменной окружения <tt>$XDG_SESSION_ID<\/tt>, которая содержит число. Ноль там впереди, чтобы не случилось ничего страшного, если эта переменная в вашем дистрибутиве «Линукс» отсутствует.<\/p>\n<p>Мне кажется, это неплохой способ, жаль только что содержимое <tt>$XDG_SESSION_ID<\/tt> остаётся одинаковым на всём протяжении жизни сессии. То есть, если запустить программу несколько раз в одном и том же окне терминала, случайные числа будут генерироваться всегда в одной и той же последовательности.<\/p>\n<p>В конце файла <tt>\/proc\/self\/environ<\/tt> всегда есть символ с кодом ноль, который мог бы нам всё испортить, но мы спрятали его за символом комментария — <tt>#<\/tt>.<\/p>\n<p>Как видно, функция <tt>random()<\/tt> вызывается <tt>seed_<\/tt> раз, что позволяет остановиться на каком-то случайном значении. Точка (<tt>.<\/tt>), которой я присваиваю <tt>random()<\/tt>, — специальная переменная <tt>bc<\/tt>. У неё есть значение, но, фактически, её частенько используют, чтобы присвоить куда-нибудь ненужные возвращаемые значения; иначе они попадут на экран.<\/p>\n<p>Несложно додуматься до похожего способа, который позволяет читать число из какого-нибудь файла в системе. Нужно только, чтобы оно было там одно. Надо создать файл с содержимым <tt>seed_=\\<\/tt> и подключить его до файла с числом. Файлы подключаются через перевод строки, действие которого отменяет слеш, так что число, опять же, попадёт в переменную <tt>seed_<\/tt>. Дальше всё как в предыдущем примере.<\/p>\n",
            "date_published": "2025-02-06T22:07:29+05:00",
            "date_modified": "2025-02-06T23:06:23+05:00",
            "tags": [
                "bc",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Thu, 06 Feb 2025 22:07:29 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "134018",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "133982",
            "url": "https:\/\/bolknote.ru\/all\/anglo-russkiy-slovar-na-bc\/",
            "title": "Англо-русский словарь на bc",
            "content_html": "<p>Пока писал «Виселицу» на <tt>bc<\/tt>, в процессе немало с ним экспериментировал. Обратил внимание на то, какой он шустрый. Я не делал прямых сравнений, но сложилось такое впечатление. Подмывало как-то потестировать скорость поплотнее, но забил.<\/p>\n<p>Позже, не справившись с исследовательским зудом, решил попробовать сделать на нём что-то нарочито многострочное, чтобы проверить насколько быстро он работает. Так как набивать несколько тысяч строк — руки отвалятся, придумал сделать англо-русский словарь, тем более, что обрабатывать ввод одиночных английских слов я <a href=\"https:\/\/bolknote.ru\/all\/igra-viselica-na-bc-pod-linuks\/\">уже научился<\/a>.<\/p>\n<p>Сделал так же, как в версии под «Линукс» — <tt>bc<\/tt> переводится на ввод 36-ричных чисел. В таком режиме слова у нас становятся числами.<\/p>\n<p>Правда есть проблема — под «Мак» слова надо вводить исключительно в верхнем регистре, иначе они трактуются как имена переменных. Можно было бы создать, конечно, кучу переменных, но это работает не очень — некоторые английские слова совпадают с ключевыми словами языка.<\/p>\n<p>Так что я поступил иначе — проверяю версию <tt>bc<\/tt> и, если она достаточной новая (как под «Маком»), запускаю <tt>bc<\/tt> через <tt>tr<\/tt>, который заменяет буквы в нижнем регистре на буквы в верхнем. В этом случае, начало программы выглядит так:<\/p>\n<pre class=\"e2-text-code\"><code class=\"bash\">#!\/bin\/sh\nc=\/*\ntr -u a-z A-Z | bc -R &quot;$0&quot;\nexit; *\/1<\/code><\/pre><p>Похожий пролог я уже использовал в прошлый раз, когда надо было «накрутить» рандомизирующую функцию.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2025.02.05@2x.webp\" width=\"1000\" height=\"331\" alt=\"\" \/>\n<\/div>\n<p>Сам словарь нашёлся в интернете. Чтобы не заливать в свой репозиторий чужую интеллектуальную собственность, я сделал <tt>make<\/tt>-файл, генерирующий мне программу на <tt>bc<\/tt> — словарь скачивается, распаковывается и обрабатывается специально написанной программой на Пайтоне. В итоге получается программа на пятьдесят тысяч с гаком строк.<\/p>\n<p>В результате всё работает шустро, несмотря на линейный поиск. Я вообще не замечаю проблем с производительностью у <tt>bc<\/tt>, любопытно. Умели же делать!<\/p>\n<p>Чтобы минимизировать программу по объёму, я сделал два цикла, а останов поиска делаю через <tt>break<\/tt> — он позволяет выйти из внутреннего цикла к началу внешнего:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">while(c) while (c) {\nibase=36;c=read();ibase=A\n\nif(c==19976){&quot;Несколько&quot;;break}\n\/* тут очень много строк *\/\nif(c==2813515210532){&quot;Сухарь&quot;;break}\nif(c==2174201762){&quot;Зигота&quot;;break}\n&quot;Неизвестное слово&quot;;}\nquit()<\/code><\/pre><p>Ноль используется для выхода — у меня в <tt>Makefile<\/tt> есть небольшой тест, вот он и использует ноль, чтобы прекратить выполнение получившейся программы.<\/p>\n<p>Результат, как обычно, можно увидеть в <a href=\"https:\/\/github.com\/bolknote\/bc-enru-dictionary\">моём репозитории<\/a>.<\/p>\n",
            "date_published": "2025-02-05T22:15:07+05:00",
            "date_modified": "2025-02-06T00:06:26+05:00",
            "tags": [
                "bc",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Wed, 05 Feb 2025 22:15:07 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "133982",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "133947",
            "url": "https:\/\/bolknote.ru\/all\/igra-viselica-na-bc-pod-linuks\/",
            "title": "Игра «Виселица» на bc под «Линукс»",
            "content_html": "<p>Я планировал заняться адаптацией «<a href=\"https:\/\/bolknote.ru\/all\/igra-viselica-na-bc\/\">Виселицы<\/a>» на <tt>bc<\/tt> под «Линукс» на следующий день, то есть сегодня, но не выдержал и вчера просидел над этим почти до полуночи. Линуксовый <tt>bc<\/tt>, конечно, гораздо скромнее по возножностям, было где поломать мозг, но больше всего времени я, кажется, потратил на рандомизацию.<\/p>\n<p>Я вчера писал уже, что в документации для линуксового <tt>bc<\/tt> нет упоминаний функций для генерации случайных чисел, но чтение исходников показало, что документации не всегда можно верить. Функция есть, называется она <tt>random()<\/tt>, но не работает так как хочется — при вызове генерирует всегда одну и ту же последовательность.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2025.02.04.1@2x.webp\" width=\"600\" height=\"122\" alt=\"\" \/>\n<\/div>\n<p>Видимо, её забыли правильно проинициализировать. Непонятно почему за столько лет это нельзя исправить, ведь новые версии <a href=\"https:\/\/www.gnu.org\/software\/bc\/\">иногда выходят<\/a>, правда в списке изменений последних версий сплошь какая-то косметика.<\/p>\n<p>Так как никаких способов исправить ситуацию, не меняя исходный код <tt>bc<\/tt>, я не обнаружил, решил обойтись хаком — при запуске вызвать <tt>random()<\/tt> случайное количество раз, чтобы в коде моей программу его внутреннее состояние тоже стало случайным.<\/p>\n<p>Для этого я изменил способ запуска программы — сделал его шелл-скриптом, который передаёт в <tt>bc<\/tt> на инициализации цикл, генерирующий случайное количество вызовов <tt>random()<\/tt>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"bash\">#!\/bin\/bash\nx=\/*\nBC_LINE_LENGTH=0 bc -l -q &lt;(\/usr\/bin\/seq -f &quot;x=random()+%g&quot; $RANDOM) &quot;$0&quot;\nexit; *\/1<\/code><\/pre><p>Обвязка с комментарием сделана так, чтобы и шелл, и <tt>bc<\/tt> не увидели в коде ничего странно и не выдали ошибку синтаксиса, а вся мякотка происходит в строке <tt>\/usr\/bin\/seq -f &quot;x=random()+%g&quot; $RANDOM<\/tt>. Команда <tt>seq<\/tt> генерирует последовательность <tt>x=random()+число<\/tt> столько раз, сколько указано в переменной <tt>$RANDOM<\/tt>. <tt>$RANDOM<\/tt> — это специальная переменная шелла, которая содержит случайное значение.<\/p>\n<p>Подстановка <tt>%g<\/tt> необходима, чтобы заработал шаблон в параметре команды <tt>seq<\/tt>, без этого она ругается на неправильный аргумент.<\/p>\n<p>Ещё одной крупной проблемой стали строки — в этой версии <tt>bc<\/tt> не поддерживается присваивание их переменным. Из-за этого код пришлось сильно переделать.<\/p>\n<p>Для вывода, вместо кучи переменных, пришлось сделать функцию, которая выводит букву по её коду через горку условий. Код получился похожим на то место, где я выбираю слово по номеру:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">define void print_letter(c) {\n    if(!--c){&quot;a&quot;}\n    if(!--c){&quot;b&quot;}\n    if(!--c){&quot;c&quot;}\n    \/* …тут все 26 букв *\/\n    if(!--c){&quot;y&quot;}\n    if(!--c){&quot;z&quot;}\n}<\/code><\/pre><p>Я не стал ставить <tt>return<\/tt>, чтобы сделать функцию более визуально компактной, тем более, что на производительность мне, по большому счёту, наплевать.<\/p>\n<p>Кстати, ввод удалось сильно упростить, перейдя на тридцатишестиричную систему исчисления, где все английские буквы соответствую числам:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">define read_letter() {\n    auto z, b\n    b = ibase\n    ibase = 36\n\n    z = read()\n    ibase = b\n    return z - 9\n}<\/code><\/pre><p>Переменная <tt>ibase<\/tt> отвечает за систему исчисления при вводе чисел.<\/p>\n<p>Таким образом, численное исчисление получили не только все одиночные буквы, но и все слова. В теории, это можно использовать для ввода одиночных команд на английском языке. Я использую это свойство, чтобы распознать команду <tt>exit<\/tt>.<\/p>\n<p>Остальные проблемы решались попроще. Ещё я немного поломал голову чем заменить <tt>ceil<\/tt> (округление вверх), потом догадался прибавить единицу и, выставив через специальную переменную <tt>scale<\/tt> нулевую точность для цифр после запятой, разделил получившееся значение на один, чтобы отбросить дробную часть:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">define word_len(c) {\n    auto r\n    scale=10\n    r = l(c) \/ l(256) + 1\n    scale=0\n    return r\/1\n}<\/code><\/pre><p>Функцию логарифма <tt>log()<\/tt> тут пришлось заменить на натуральный логарифм <tt>l()<\/tt> — это одна из немногих математических функций, которые поддерживаются в этой версии <tt>bc<\/tt>.<\/p>\n<p>Остальные замены довольно тривиальны, я писал о них ещё <a href=\"https:\/\/bolknote.ru\/all\/igra-viselica-na-bc\/\">в прошлый раз<\/a>. Результат положил отдельным файлом <a href=\"https:\/\/github.com\/bolknote\/bc-hangman\">в моём репозитории<\/a>.<\/p>\n",
            "date_published": "2025-02-04T14:25:00+05:00",
            "date_modified": "2025-02-04T12:14:41+05:00",
            "tags": [
                "bc",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Tue, 04 Feb 2025 14:25:00 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "133947",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "133926",
            "url": "https:\/\/bolknote.ru\/all\/igra-viselica-na-bc\/",
            "title": "Игра «Виселица» на bc",
            "content_html": "<p>После того как я <a href=\"https:\/\/bolknote.ru\/all\/99-butylok-kalkulyator-bc\/\">написал<\/a> «бутылки пива» на <tt>bc<\/tt>, стало интересно попробовать написать на этом языке какую-нибудь игру. На этом попроще я не первый, есть, например, очень годный <a href=\"https:\/\/habr.com\/ru\/articles\/132840\/\">пасьянс<\/a>, но попробовать сделать что-то своё тоже хочется.<\/p>\n<p>В силу специфики обработки ввода <tt>bc<\/tt>, писать нужно что-то пошаговое — фоновое выполнение не поддерживается, программа может работать только от ввода до ввода. Долго не размышляя, я как-то сразу решил написать игру «Виселица». Я её уже <a href=\"https:\/\/bolknote.ru\/tags\/hangman-game\/\">писал<\/a> под «Флиппер», если помните.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2025.02.03@2x.webp\" width=\"1000\" height=\"275\" alt=\"\" \/>\n<div class=\"e2-text-caption\">Игровой процесс игры «Веселица», написанной на <tt>bc<\/tt><\/div>\n<\/div>\n<p>На пути к успеху сразу начались трудности. Несмотря на то, что в <tt>bc<\/tt> есть многообещающая функция <tt>read()<\/tt>, оказалось, что с её помощью можно вводить только выражения языка и числа. В вышеупомянутом «пасьянсе» автор обошёлся числами, а мне нужны буквы, иначе играть будет невозможно.<\/p>\n<p>К счастью, «выражения» — это ещё и переменные. Если задать значения всем однобуквенным переменным, мы сможем определить какую именно букву нажал пользователь.<\/p>\n<p>К тому же можно ещё сразу сделать таблицу, которая позволит нам рисовать клавиатуру, так как других способов вывести последовательно буквы в языке нет.<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">a=1;b=2;c=3;d=4;e=5;f=6;g=7;h=8;i=9;j=10;k=11;l=12;m=13;n=14;o=15;p=16;q=17;r=18;s=19;t=20\nu=21;v=22;w=23;x=24;y=25;z=26\n\nco[a]=&quot;a&quot;;co[b]=&quot;b&quot;;co[c]=&quot;c&quot;;co[d]=&quot;d&quot;;co[e]=&quot;e&quot;;co[f]=&quot;f&quot;;co[g]=&quot;g&quot;;co[h]=&quot;h&quot;;co[i]=&quot;i&quot;;co[j]=&quot;j&quot;\nco[k]=&quot;k&quot;;co[l]=&quot;l&quot;;co[m]=&quot;m&quot;;co[n]=&quot;n&quot;;co[o]=&quot;o&quot;;co[p]=&quot;p&quot;;co[q]=&quot;q&quot;;co[r]=&quot;r&quot;;co[s]=&quot;s&quot;;co[t]=&quot;t&quot;\nco[u]=&quot;u&quot;;co[v]=&quot;v&quot;;co[w]=&quot;w&quot;;co[x]=&quot;x&quot;;co[y]=&quot;y&quot;;co[z]=&quot;z&quot;\n\nexit = -1<\/code><\/pre><p>Заодно я задал значение переменной <tt>exit<\/tt>, это слово пользователь может ввести, чтобы выйти.<\/p>\n<p>Весь интерфейс рисуется при помощи управляющих последовательностей, благо хоть тут проблем нет — указываешь коды прямо в строке и всё работает.<\/p>\n<p>Кстати о строках. В языке они присутствуют, но, по большому счёту, сделать с ними ничего нельзя. Например, в игре нужна функция поиска буквы в строке или хотя бы получения символа по индексу. Ничего такого нет даже в помине. Как тогда быть?<\/p>\n<p>Единственное решение, которое приходит в голову — кодировать слова, как числа. 26 букв легко умещаются в один байт, поэтому можно кодировать по байту на цифру. Я написал функцию на несколько тысяч строк, которая содержит закодированные слова и возвращает одно из них, в зависимости от аргумента:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">define get_word(c) {\n    if(!--c) return 4328588043\n    if(!--c) return 4328588820\n    \/* и так далее *\/\n    if(!--c) return 437194509\n\n    return -c\n}\n\nword = get_word(irand(get_word(0)) + 1)<\/code><\/pre><p>Как видно, если передать в функцию ноль, она вернёт количество элементов, это полезно для того, чтобы знать до какого предела генерировать случайное число.<\/p>\n<p>Функция <tt>irand<\/tt>, используемая тут, является расширением <tt>bc<\/tt>, у меня на «Маке» она поддерживается, но под «Линуксом» её нет, так же как и вообще любой другой функции для работы со случайными числами.<\/p>\n<p>С такими «строками» можно уже как-то работать, например, считать длину, чтобы вывести подходящее количество «окошек», в которых будут появляться буквы:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">define word_len(c) {\n    scale=10\n    return ceil(log(c, 256), 0)\n}<\/code><\/pre><p>Или вывести на печать:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">define void print_word(c) {\n    auto word, i, mod\n\n    scale=0\n    for (i = 0; c; i++) {\n        c = divmod(c, 256, mod[])\n        word[i] = mod[0]\n    }\n\n    while (i--) {\n        print co[word[i]]\n    }\n}<\/code><\/pre><p>В общем, всё как с обычными строками, только чуть-чуть очень сильно неудобно.<\/p>\n<p>Остальное, в общем-то, писать было просто — логика игры очень простая, пишется за несколько минут. На результат можно посмотреть в <a href=\"https:\/\/github.com\/bolknote\/bc-hangman\">моём репозитории<\/a> на «Гитхабе».<\/p>\n<p>В теории, игру можно портировать и на «Линукс», надо только избавиться от хранения строк в переменных, заменить генерацию случайных чисел на внешний генератор, заменить <tt>log()<\/tt> на <tt>l()<\/tt>, а <tt>divmod()<\/tt> на деление и взятие модуля и избавиться от <tt>length()<\/tt> — массив в качестве аргумента в «Линуксе» не поддерживается.<\/p>\n",
            "date_published": "2025-02-03T21:43:04+05:00",
            "date_modified": "2025-02-04T01:53:33+05:00",
            "tags": [
                "bc",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Mon, 03 Feb 2025 21:43:04 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "133926",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "133908",
            "url": "https:\/\/bolknote.ru\/all\/99-butylok-kalkulyator-bc\/",
            "title": "99 бутылок: калькулятор bc",
            "content_html": "<p>Разбирал одну старенькую научную статью с некоторым количеством математики, а внутри увидел вычисления на <tt>bc<\/tt>.<\/p>\n<p>Не особо с ним знаком, но несколько раз пользовался, даже не вникая что он умеет. Честно говоря, не помню зачем он мне тогда понадобился, наверное надо было что-то вычислить в консоли. Из статей в интернете, где он иногда вскользь упоминался, я знал, что это навороченный калькулятор, но не знал насколько.<\/p>\n<p>В общем, оказалось, там внутри целый язык программирования, с циклами, ветвлениями, локальными переменными, строками, массивами и числам. Поддерживаются даже пользовательские функции. Решил попробовать написать на нём очередную «песню о пиве».<\/p>\n<p><b>82. bc<\/b> — интерактивный интерпретатор Си-подобного языка, появившийся ещё в 1975 году как интерфейс для утилиты <tt>dc<\/tt>, на котором «песню о пиве» я <a href=\"https:\/\/bolknote.ru\/all\/99-bottles-dc\/\">уже писал<\/a>. Утилита <tt>dc<\/tt> выполняла вычисления с произвольной точностью, используя обратную польскую запись, а <tt>bc<\/tt> предоставила более привычный Си-подобный синтаксис, транслируя его в команды <tt>dc<\/tt>. В 1991 году утилита <tt>bc<\/tt> была стандартизирована <i>POSIX<\/i>, и сегодня существует несколько её реализаций.<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">\/* Beer song. Evgeny Stepanischev, Jan 2025 *\/\n\ndefine void bottles(b) {\n    if (b) print b else print &quot;No&quot;\n    &quot; bottle&quot;\n    if (b-1) print &quot;s&quot;\n    &quot; of beer&quot;\n}\n\nfor(beer = 99; beer;) {\n    bottles(beer); &quot; on the wall, &quot;\n    bottles(beer); print &quot;!\\n&quot;\n\n    print &quot;Take one down, pass it around,\\n&quot;\n    bottles(--beer); print &quot; on the wall!\\n\\n&quot;\n}\n\nprint &quot;No more bottles of beer on the wall,\\n&quot;\nprint &quot;No more bottles of beer!\\n&quot;\nprint &quot;Go to the store and buy some more,\\n&quot;\nbottles(99); &quot; on the wall!&quot;<\/code><\/pre><p>Единственное, что вызвало у меня затруднение — это как сделать так, чтобы функция ничего не возвращала. Дело в том, что функции в <tt>bc<\/tt> по-умолчанию возвращают число. Если не указано какое, вернётся ноль. А в глобальном контексте то, что возвращается из функции будет напечатано на экране. Поэтому у меня выводился лишний ноль. Чтобы это исправить, нужно в определение функции добавить ключевое слово <tt>void<\/tt>.<\/p>\n<p>Никаких других сложностей с этой программой у меня не возникло, язык простой, хорошо продуманный, лёгок в освоении.<\/p>\n<p><i>Добавлено позднее<\/i>: как оказалось, у языка есть свои особенности о которых нелишне знать. Например, подключение математической библиотеки меняет точность, определяемую переменной <tt>scale<\/tt>, что влияет, например, на операцию вычисления модуля, она начинает работать иначе.<\/p>\n<p>Другая странность — операции сдвига работают в десятичной системе. Не понимаю какой от этого толк. Например, <tt>1&lt;&lt;2<\/tt> даст <tt>100<\/tt>.<\/p>\n",
            "date_published": "2025-02-02T19:42:38+05:00",
            "date_modified": "2025-03-22T00:34:00+05:00",
            "tags": [
                "99",
                "bc",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Sun, 02 Feb 2025 19:42:38 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "133908",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        }
    ],
    "_e2_version": 4079,
    "_e2_ua_string": "Aegea 11.0 (v4079e)"
}