<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
  xmlns:atom="http://www.w3.org/2005/Atom">

<channel>

<title>Блоги: заметки с тегом bc</title>
<link>https://blogengine.ru/blogs/tags/bc/</link>
<description>Автоматически собираемая лента заметок, написанных в блогах на Эгее</description>
<author></author>
<language>ru</language>
<generator>Aegea 11.0 (v4079e)</generator>

<itunes:subtitle>Автоматически собираемая лента заметок, написанных в блогах на Эгее</itunes:subtitle>
<itunes:image href="" />
<itunes:explicit>no</itunes:explicit>

<item>
<title>Ковыряю bc</title>
<guid isPermaLink="false">136673</guid>
<link>https://bolknote.ru/all/kovyryayu-bc/</link>
<pubDate>Fri, 18 Jul 2025 00:25:53 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/kovyryayu-bc/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Ковырял сегодня &lt;tt&gt;bc&lt;/tt&gt; на досуге, ту версию, которая помощнее. Что-то не очень мне нравится как он написан. Я добавлял в язык одну конструкцию и одну функцию. Конструкцию удалось добавить быстро, а с функцией я возился не один час.&lt;/p&gt;
&lt;p&gt;На скриншоте — количество мест, в которые пришлось её прописать. И только в одном из этих мест хранится её реализация. Взял за образец другие объявленные функции, поэтому не имею не малейшего понятия почему так много где пришлось её прописывать, не успел разобраться.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2025.07.17@2x.webp" width="1000" height="231" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Лучше расскажу что именно я придумал добавить в язык. В &lt;tt&gt;bc&lt;/tt&gt; есть несколько глобальных переменных, которые очень много на что влияют. Две, наверное, самые важные — это &lt;tt&gt;ibase&lt;/tt&gt; и &lt;tt&gt;scale&lt;/tt&gt;. Очень часто их приходится сохранять в начале и восстанавливать в конце своих функций, особенно библиотечных.&lt;/p&gt;
&lt;p&gt;У более продвинутого &lt;tt&gt;bc&lt;/tt&gt; есть специальный ключ, который, если его указать, меняет это поведение — при входе в каждую функцию значения этих и других глобальных переменных будут записываться в специальный стек, а на выходе — восстанавливаться оттуда.&lt;/p&gt;
&lt;p&gt;Но библиотечные функции, всё одно, пишут, для универсальности, не рассчитывая на то, что этот флаг установлен. Вот, например, библиотечная функция косинуса:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;define c(x){
    auto b,s
    b=ibase
    ibase=A
    s=scale
    scale*=1.2
    x=s(2*a(1)+x)
    scale=s
    ibase=b
    return(x/1)
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Вот я и подумал, чтобы бы неплохо придумать директиву, при указании которой такой стек, для помеченной ею функции, всегда включался бы; а кроме того, была бы полезна функция, которая восстановила бы значения глобальных переменных ещё до выхода из функции. Иногда это необходимо, чтобы вернуть число в соответствии с установленными в них параметрами.&lt;/p&gt;
&lt;p&gt;Функция косинуса с этими новыми возможностями выглядела бы так:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;define stack c(x){
    ibase=A
    scale*=1.2
    x=s(2*a(1)+x)
    pop_stack()
    return(x/1)
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Завтра ещё потестирую и попробую закинуть код автору &lt;tt&gt;bc&lt;/tt&gt;, вдруг понравится изменение.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Добавлено позднее&lt;/i&gt;: Автор &lt;tt&gt;bc&lt;/tt&gt; &lt;a href="https://github.com/gavinhoward/bc/pull/93#issuecomment-3099251028"&gt;написал&lt;/a&gt;, что идея у меня интересная, но его жизнь серьёзно изменилась и теперь он не будет заниматься проектом бесплатно. Видимо крепко его прижало. Учитывая низкую популярность &lt;tt&gt;bc&lt;/tt&gt;, можно сказать, что этот проект умер, если у него не найдётся новый мантейнер, что маловероятно.&lt;/p&gt;
</description>
</item>

<item>
<title>Недокументированные возможности bc</title>
<guid isPermaLink="false">136318</guid>
<link>https://bolknote.ru/all/nedokumentirovannye-vozmozhnosti-bc/</link>
<pubDate>Tue, 17 Jun 2025 20:03:31 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/nedokumentirovannye-vozmozhnosti-bc/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;У той версии утилиты &lt;tt&gt;bc&lt;/tt&gt;, которая является частью проекта &lt;i&gt;GNU&lt;/i&gt;, есть ряд недокументированных возможностей, про которые я узнал, исследуя её исходный код.&lt;/p&gt;
&lt;p&gt;Я уже &lt;a href="https://bolknote.ru/all/igra-viselica-na-bc-pod-linuks/"&gt;писал&lt;/a&gt; про недокументированную и сломанную функцию &lt;tt&gt;random()&lt;/tt&gt;, которая починена в новой версии &lt;a href="https://bolknote.ru/all/pochinili-random-v-bc/"&gt;моими усилиями&lt;/a&gt;. Но кроме этого, есть ещё две вещи отсутствующие в документации.&lt;/p&gt;
&lt;p&gt;Во-первых, у самой утилиты есть ключ &lt;nobr&gt;&lt;tt&gt;-c&lt;/tt&gt;&lt;/nobr&gt;, показывающий байт-код, в который переводится программа на языке &lt;tt&gt;bc&lt;/tt&gt;. Во-вторых, есть альтернативный синтаксис для передачи массива по ссылке — кроме символа &lt;tt&gt;*&lt;/tt&gt;, как везде, есть нестандартный символ &lt;tt&gt;&amp;amp;&lt;/tt&gt;.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2025.06.17@2x.webp" width="1000" height="310" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Но это я сам нашёл, руками. Стало интересно посмотреть, что могут найти языковые модели. Для исследования я выбрал редактор кода «Курсор» и модель &lt;i&gt;Claude Sonnet 4&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;С первого захода «Клод» нашёл много всего, но бо́льшая часть — вполне обычные возможности, присутствующие в документации. Засучил рукава, порылся в найденном. Кроме мусора там нашлось и полезное — ключ и функцию &lt;tt&gt;random()&lt;/tt&gt; он нашёл, но про символ &lt;tt&gt;&amp;amp;&lt;/tt&gt; не упомянул.&lt;/p&gt;
&lt;p&gt;Пришлось подтолкнуть — поместить в контекст нужный файл (&lt;tt&gt;bc.y&lt;/tt&gt;) и спросить нет чего-то недокументированного в нём. Со второго раза «Клод» обнаружил искомое, правда, и в этот раз добавил в список много пунктов не по делу.&lt;/p&gt;
&lt;p&gt;С минимальным участием человека нашлись все недокументированные возможности о которых я знаю — три из трёх, правда эти жемчужины пришлось искать вручную в кучке навоза.&lt;/p&gt;
&lt;p&gt;Какой вывод?&lt;/p&gt;
&lt;p&gt;Я считаю, что это, в определённом смысле, успех — «Клод» помог мне вычленить искомое гораздо быстрее, чем в своё время это сделал я. Да, без моей подсказки третью возможность он не нашёл, но и задача очень и очень нетривиальная.&lt;/p&gt;
</description>
</item>

<item>
<title>Починили random() в bc</title>
<guid isPermaLink="false">136003</guid>
<link>https://bolknote.ru/all/pochinili-random-v-bc/</link>
<pubDate>Thu, 29 May 2025 15:54:54 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/pochinili-random-v-bc/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Вышла версия утилиты &lt;tt&gt;bc&lt;/tt&gt;, в которую я присылал патч для исправления &lt;a href="https://bolknote.ru/all/gnu-bc-i-random/"&gt;проблемы&lt;/a&gt; с функцией для получения случайных значений. Исправление попало в версию 1.08.2.&lt;/p&gt;
&lt;p&gt;Интересно, что в авторы исправления меня не записали, зато поблагодарили, записав имя и фамилию русскими буквами, хотя в конце письма я подписался латиницей:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Thu Apr 10 12:59:31 PDT 2025 Ken Pizzini &amp;lt;ken@gnu.org&amp;gt;&lt;br /&gt;
bc/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.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
</item>

<item>
<title>«Курсор»</title>
<guid isPermaLink="false">135778</guid>
<link>https://bolknote.ru/all/ide-cursor/</link>
<pubDate>Fri, 09 May 2025 11:35:04 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/ide-cursor/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Что-то я опять по кривой Гартнера свалился на дно разочарования в «Курсоре» — это редактор, где можно программировать с помощью нейросетей. Из семи последних задач «Курсор» запорол все семь, да ещё как эпично! Задачи, на мой взгляд, я описывал понятно — так, как описал бы живому программисту.&lt;/p&gt;
&lt;p&gt;Чтобы отойти от разочарования, решил как-то реабилитировать технологию в своих глазах, тем более, что некоторые мои задачи нейросети всё-таки выполняют. Взял &lt;a href="https://github.com/gavinhoward/bc/blob/master/gen/lib2.bc"&gt;библиотеку функций&lt;/a&gt; из продвинутой реализации &lt;tt&gt;bc&lt;/tt&gt;, чтобы попробовать портировать её на версию &lt;i&gt;GNU&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;Попросил три понятных изменения сделать, любой дурак справится:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a@b заменить на вызов функции &lt;tt&gt;floor(a, b)&lt;/tt&gt;, которую я написал;&lt;/li&gt;
&lt;li&gt;a$ заменить на вызов &lt;tt&gt;floor(a, 0)&lt;/tt&gt;;&lt;/li&gt;
&lt;li&gt;там, где оператор &lt;tt&gt;else&lt;/tt&gt; перенесен на другую строку от конструкции &lt;tt&gt;if&lt;/tt&gt;, надо либо заэкранировать перенос через обратный слеш, либо вернуть &lt;tt&gt;else&lt;/tt&gt; на одну строку с &lt;tt&gt;if&lt;/tt&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Задача простая, но даже тут «Курсор» накосячил, не справившись с подсчётом скобок. В итоге, тщательно проверял все замены и считал скобки я сам. К чёрту такую автоматизацию, по сумме, я бы сам быстрее сделал.&lt;/p&gt;
&lt;p&gt;Раньше я бы к этому спокойно отнёсся, но в последнее время раздражительность повысилась — мёрзну и всё время на грани простуды. Отопление давно отключили, а на улице резко похолодало — снег уже несколько раз шёл. Но, видимо, недостаточно холодно, чтобы включать отопление обратно.&lt;/p&gt;
&lt;p&gt;Вокруг очень многие болеют пневмонией, это ещё что такое, откуда? Я уверен, что слово «пневмония» я слышал за прошедшие два года больше, чем за всю прошлую жизнь. Сам я всё время кашляю, хотя не чувствуется, что болею, временами только какая-то слабость накатывает.&lt;/p&gt;
</description>
</item>

<item>
<title>Кроссплатформенность и bc</title>
<guid isPermaLink="false">135632</guid>
<link>https://bolknote.ru/all/krossplatformennost-i-bc/</link>
<pubDate>Mon, 21 Apr 2025 21:04:35 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/krossplatformennost-i-bc/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Как мы все знаем, в мире существует две версии &lt;tt&gt;bc&lt;/tt&gt; — более скромная по возможностям версия &lt;i&gt;GNU&lt;/i&gt;, которая используется в Линуксе, и более развитая, которая, например, используется в командной строке МакОСи.&lt;/p&gt;
&lt;p&gt;Они довольно серьёзно различаются — когда я писал игру «&lt;a href="https://github.com/bolknote/bc-hangman"&gt;Виселица&lt;/a&gt;» на этом языке, мне пришлось сделать две версии для разных синтаксисов.&lt;/p&gt;
&lt;p&gt;В принципе, можно писать кроссплатформенно, если использовать подмножество, которое поддерживают обе версии, но есть одна неприятность — функция получения случайного числа в гну-версии называется &lt;tt&gt;random()&lt;/tt&gt;, а в более продвинутой — &lt;tt&gt;rand()&lt;/tt&gt; (точнее там их целое семейство, но функции &lt;tt&gt;random()&lt;/tt&gt; там нет).&lt;/p&gt;
&lt;p&gt;Поскольку в языке нет способа узнать определена функция или нет, нужно каким-то образом отличать одну версию от другой и вызывать, в зависимости от результата, ту или другую функцию.&lt;/p&gt;
&lt;p&gt;Каким же образом мы можем это сделать?&lt;/p&gt;
&lt;p&gt;Вначале я возлагал надежду на переменную &lt;tt&gt;seed&lt;/tt&gt;. В &lt;i&gt;GNU&lt;/i&gt; её нету, то есть она содержит ноль, а в продвинутой версии она содержит инициализирующее значение. Как будто этого вполне достаточно, но, во-первых, никто не обещает, что она по какой-то случайности не получит нулевое значение, а во-вторых, её вполне могут реализовать в версии &lt;i&gt;GNU&lt;/i&gt;. Нужно что-то принципиально другое, что в будущем не будет работать иначе, правка или реализация которого сломала бы обратную совместимость.&lt;/p&gt;
&lt;p&gt;Такую особенность я нашёл — она заключается в приоритете обработки операции отрицания, которая записывается как восклицательный знак.&lt;/p&gt;
&lt;p&gt;Из-за этой разницы две версии по-разному вычисляют конструкцию &lt;tt&gt;!1+1&lt;/tt&gt;. В продвинутой версии порядок выполнения следующий: &lt;tt&gt;(!1)+1&lt;/tt&gt;, что даёт нам единицу, а в гнушной приоритет другой и конструкция выполнится так: &lt;tt&gt;!(1+1)&lt;/tt&gt;, что даёт нам ноль.&lt;/p&gt;
&lt;p&gt;Основываясь на этом, мы можем написать универсальную функцию для получения случайного числа:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;define rnd() {
    /* Checking the bc version */
    if (!1+1) {
        return rand()
    } else {
        return random() * random()
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;P. S. Надо помнить, что в гну-версии функция получения случайного числа сломана, но &lt;a href="https://bolknote.ru/all/gnu-bc-i-random/"&gt;есть надежда&lt;/a&gt;, что скоро её починят и ей можно будет пользоваться.&lt;/p&gt;
&lt;p&gt;P. P. S. Я умножаю &lt;tt&gt;random()&lt;/tt&gt; на &lt;tt&gt;random()&lt;/tt&gt;, чтобы хоть немного выровнять по диапазону значений &lt;tt&gt;rand()&lt;/tt&gt; и &lt;tt&gt;random()&lt;/tt&gt;.&lt;/p&gt;
</description>
</item>

<item>
<title>GNU bc и random()</title>
<guid isPermaLink="false">135565</guid>
<link>https://bolknote.ru/all/gnu-bc-i-random/</link>
<pubDate>Mon, 14 Apr 2025 21:23:55 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/gnu-bc-i-random/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Я не задумывался об этом раньше, но это здорово сбивает с толку, что в мире есть две различающиеся версии &lt;i&gt;bc&lt;/i&gt; — одна является частью проекта &lt;i&gt;GNU&lt;/i&gt; и поставляется в дистрибутивах Линукса, а вторая развивается другим коллективом авторов и входит, например, в состав МакОСи.&lt;/p&gt;
&lt;p&gt;Я уже поучаствовал в разработке последней — предложил &lt;a href="https://bolknote.ru/all/uskorenie-operaciy-v-bc/"&gt;изменение&lt;/a&gt; ускоряющее некоторые операции и &lt;a href="https://bolknote.ru/all/popravil-oshibku-v-bc/"&gt;исправил одну ошибку&lt;/a&gt;, а теперь, пока был отпуске, внёс вклад и в версию проекта &lt;i&gt;GNU&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;Как я &lt;a href="https://bolknote.ru/all/igra-viselica-na-bc-pod-linuks/"&gt;как-то писал&lt;/a&gt; в этой версии есть недокументированная и бесполезная функция &lt;tt&gt;random()&lt;/tt&gt;, которая возвращает всегда одно и то же число, так как автор забыл проинициализировать генератор случайных чисел.&lt;/p&gt;
&lt;p&gt;Я подумал — чем чёрт не шутит? Если предложить своё исправление и в этот проект, то, может, его тоже примут? Так как открытого репозитория кода у &lt;i&gt;bc&lt;/i&gt; проекта &lt;i&gt;GNU&lt;/i&gt; нет, свой патч я отправил на почту мантейнеру.&lt;/p&gt;
&lt;p&gt;Он ответил почти сразу, поблагодарил за исправление бага и написал, что сейчас же внесёт исправление в код. Так что, вероятно, следующая версия &lt;i&gt;bc&lt;/i&gt; выйдет уже с нормально работающей функцией &lt;tt&gt;random()&lt;/tt&gt;!&lt;/p&gt;
</description>
</item>

<item>
<title>Странности bc</title>
<guid isPermaLink="false">135334</guid>
<link>https://bolknote.ru/all/strannosti-bc/</link>
<pubDate>Wed, 26 Mar 2025 01:15:37 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/strannosti-bc/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Чем больше узнаёшь &lt;tt&gt;bc&lt;/tt&gt;, тем больше в нём находишь странностей. Особенно меня поражают массивы.&lt;/p&gt;
&lt;p&gt;Например, как вы думаете, чему равна длина массива, в который мы ещё ни разу не инициализировали? Правильно, единице. Почему? Да чёрт его знает, так в коде написано:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;void
bc_array_init(BcVec* a, bool nums)
{
    BC_SIG_ASSERT_LOCKED;

    // Set the proper vector.
    if (nums) bc_vec_init(a, sizeof(BcNum), BC_DTOR_NUM);
    else bc_vec_init(a, sizeof(BcVec), BC_DTOR_VEC);

    // We always want at least one item in the array.
    bc_array_expand(a, 1);
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Или вот такой код:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;define void f(*a[]) {
    . = a[99]
}

f(b[]); length(b[])&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Чему будет равна длина массива &lt;tt&gt;b[]&lt;/tt&gt;?&lt;/p&gt;
&lt;p&gt;Правильный ответ — она будет равна ста. Потому что в функции, куда мы передали этот массив по ссылке, происходит чтение из 99-го (массивы начинаются с нуля) элемента. В коде &lt;tt&gt;bc&lt;/tt&gt; ясно сказано:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;// The bc spec says that if an element is accessed that does not
// exist, it should be preinitialized to 0. Well, if we access
// an element *way* out there, we have to preinitialize all
// elements between the current last element and the actual
// accessed element.
if (v-&amp;gt;len &amp;lt;= idx)
{
    BC_SIG_LOCK;
    bc_array_expand(v, bc_vm_growSize(idx, 1));
    BC_SIG_UNLOCK;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Как только идёт обращение к несуществующему элементу массива, неважно, для чтения или записи, он получается значение «ноль».&lt;/p&gt;
&lt;p&gt;В этих случаях я даже уже и не понимаю — баги это или нет. Вроде нет, но выглядит контринтуитивно.&lt;/p&gt;
</description>
</item>

<item>
<title>Поправил ошибку в bc</title>
<guid isPermaLink="false">135321</guid>
<link>https://bolknote.ru/all/popravil-oshibku-v-bc/</link>
<pubDate>Tue, 25 Mar 2025 10:55:32 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/popravil-oshibku-v-bc/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Вчера часа проснулся около часа ночи, сна ни в одном глазу. Ворочался-ворочался, думаю надо бы заняться чем-нибудь, мозг утомить. Решил почитать исходный код &lt;tt&gt;bc&lt;/tt&gt;. Он остался у меня с того раза, когда я &lt;a href="https://bolknote.ru/all/uskorenie-operaciy-v-bc/"&gt;коммитил туда&lt;/a&gt; своё предложение по ускорению функции &lt;tt&gt;band()&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Бродил по коду туда-сюда, читал случайные куски, пока не дошёл до кусочка, проверяющего дублирующиеся параметры у функции. Вот это место:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;for (i = 0; i &amp;lt; f-&amp;gt;autos.len; ++i)
{
	// Get the auto.
	BcAuto* aptr = bc_vec_item(&amp;amp;f-&amp;gt;autos, i);

	// If they match, barf.
	if (BC_ERR(idx == aptr-&amp;gt;idx &amp;amp;&amp;amp; type == aptr-&amp;gt;type))
	{
		const char* array = type == BC_TYPE_ARRAY ? &amp;quot;[]&amp;quot; : &amp;quot;&amp;quot;;

		bc_error(BC_ERR_PARSE_DUP_LOCAL, line, name, array);
	}
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Посмотрел что тут происходит и заметил, что в перечислении, описывающем виды параметров, вообще-то три значения — скаляр, массив и массив, передающийся по ссылке. При этом код выше написан так, как будто их только два. Небольшой тест показал, что так и есть. Следующий код должен порождать ошибку, между тем, он выполняется как ни в чём не бывало:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;define a(*t[], t[]) {}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Подумал, что уже достаточно утомился, чтобы лечь спать, но не тут-то было! Стоило закрыть глаза, как мозг начал продумывать как поизящнее исправить этот баг. Пришлось снова открыть ноутбук и &lt;a href="https://github.com/gavinhoward/bc/pull/89"&gt;править&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Уже утром я прочитал сообщение по моему коммиту — автор &lt;tt&gt;bc&lt;/tt&gt; попросил отформатировать код и написать небольшой тест. Я всё исправил и теперь ещё немного моего кода есть в этой прекрасной утилите!&lt;/p&gt;
</description>
</item>

<item>
<title>Приняли коммит в bc</title>
<guid isPermaLink="false">134969</guid>
<link>https://bolknote.ru/all/prinyali-kommit-v-bc/</link>
<pubDate>Sat, 01 Mar 2025 14:11:29 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/prinyali-kommit-v-bc/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Как-то быстро и неожиданно мой коммит, &lt;a href="https://bolknote.ru/all/uskorenie-operaciy-v-bc/"&gt;ускоряющий&lt;/a&gt; функцию &lt;tt&gt;band()&lt;/tt&gt;, &lt;a href="https://github.com/gavinhoward/bc/pull/88"&gt;приняли&lt;/a&gt; в репозиторий &lt;tt&gt;bc&lt;/tt&gt;. Что ещё круто, основываясь на той же идее, автор ускорил функции &lt;tt&gt;bnotn()&lt;/tt&gt;, &lt;tt&gt;bor()&lt;/tt&gt; и &lt;tt&gt;bxor()&lt;/tt&gt;. Я тоже думал ими заняться, если мой коммит примут, а он уже сам всё сделал. Отлично!&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2025.03.01@2x.webp" width="1000" height="240" alt="" /&gt;
&lt;/div&gt;
</description>
</item>

<item>
<title>Ускорение операций в bc</title>
<guid isPermaLink="false">134889</guid>
<link>https://bolknote.ru/all/uskorenie-operaciy-v-bc/</link>
<pubDate>Wed, 26 Feb 2025 23:11:19 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/uskorenie-operaciy-v-bc/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Как вы помните, я недавно устроил себе суточный хакатон, писал «&lt;a href="https://bolknote.ru/all/doom-na-bc/"&gt;Дум&lt;/a&gt;» на &lt;tt&gt;bc&lt;/tt&gt;. Получился он тогда довольно медленным, особенно когда на экране было много объектов. Сейчас я его потихоньку оптимизирую, но так как профилирования в &lt;tt&gt;bc&lt;/tt&gt; не существует, двигаюсь наугад.&lt;/p&gt;
&lt;p&gt;По сути я до сих пор не знаю, на что там уходит больше всего времени, но иногда выбираю час-другой посмотреть какие операции ещё можно ускорить. Что, в целом, обычно, положительно сказывается на производительности.&lt;/p&gt;
&lt;p&gt;В стандартной библиотеке &lt;tt&gt;bc&lt;/tt&gt; есть много функций, написанных нативно. Их, как правило, удаётся так или иначе ускорить, поэтому я решил посмотреть что у меня из такого ещё используется. Взор пал на функцию &lt;tt&gt;band()&lt;/tt&gt;, особенно в форме &lt;tt&gt;(band(a, b) &amp;&amp; 1)&lt;/tt&gt;, то есть там, где всё, что меня интересует — установлен бит или нет. У меня в коде было несколько таких мест.&lt;/p&gt;
&lt;p&gt;Написал свой вариант по мотивам того кода, который используется в стандартной библиотеке:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;define check_bit(x, y) {
    auto result, m[]
    result = 0
    scale = 0

    while (x &amp;amp;&amp;amp; y) {
        x = divmod(x, 2, m[])
        if (m[0]) {
            y = divmod(y, 2, m[])
            result += m[0]
        } else {
            y /= 2
        }
    }
    return result
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Получилось быстрее почти в два с половиной раза. Саму операцию &lt;tt&gt;band()&lt;/tt&gt; тоже удалось ускорить в 1,7 раза, в «чистом» виде она у меня в коде тоже есть. Думаю, может сделать коммит в код &lt;tt&gt;bc&lt;/tt&gt;?&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Добавлено:&lt;/i&gt; &lt;a href="https://github.com/gavinhoward/bc/pull/88"&gt;коммит сделал&lt;/a&gt;. Но беда — автор &lt;tt&gt;bc&lt;/tt&gt; в примечании к репозиторию на «Гитхабе» написал, что с «Гитхаба» он ушёл. К сожалению, то место, куда он ушёл не работает. Так что коммит пришлось залить на «Гитхаб», больше-то некуда.&lt;/p&gt;
</description>
</item>

<item>
<title>Улучшение в словаре на bc</title>
<guid isPermaLink="false">134747</guid>
<link>https://bolknote.ru/all/uluchshenie-v-slovare-na-bc/</link>
<pubDate>Thu, 20 Feb 2025 21:51:09 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/uluchshenie-v-slovare-na-bc/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;За последние недели мой уровень в &lt;tt&gt;bc&lt;/tt&gt; очень сильно вырос. Я стал видеть вещи в своих прежних проектах, которые можно сделать проще и изящнее. Но, кажется, мой рост остановился. Интересно, достиг ли я потолка? Или, может, стал ли я сеньором в этом? Не пора ли мне учить других? Открыть курсы, поднимать сообщество? Вопросы без ответов!&lt;/p&gt;
&lt;p&gt;В общем, открыл сегодня, пока ехал в такси, исходник своего &lt;a href="https://bolknote.ru/all/anglo-russkiy-slovar-na-bc/"&gt;англо-русского словаря&lt;/a&gt;, написанного на &lt;tt&gt;bc&lt;/tt&gt;, и пришло мне в голову очевидное — не нужно хранить слова в десятичных числах, они длинные и непонятные, надо хранить их как они есть — в виде слов, ведь у нас в &lt;tt&gt;bc&lt;/tt&gt; есть 36-ричная система счисления, то есть десять цифр и 26 букв.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2025.02.20@2x.webp" width="1000" height="300" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Почему же я раньше-то до такой простой штуки не додумался? Всё приходит с опытом.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Добавлено&lt;/i&gt;: грустно — на скриншоте обнаружил ошибки в словаре, который я использую.&lt;/p&gt;
</description>
</item>

<item>
<title>Быстрый корень из суммы квадратов</title>
<guid isPermaLink="false">134710</guid>
<link>https://bolknote.ru/all/bystry-koren-iz-summy-kvadratov/</link>
<pubDate>Wed, 19 Feb 2025 15:55:21 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/bystry-koren-iz-summy-kvadratov/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Я недавно писал как ускорял свой «&lt;a href="https://bolknote.ru/all/doom-na-bc/"&gt;Дум&lt;/a&gt;» для &lt;tt&gt;bc&lt;/tt&gt;. В частности я заменял тригонометрические функции их менее точными, но более быстрыми, аналогами.&lt;/p&gt;
&lt;p&gt;Роман Парпалак &lt;a href="https://bolknote.ru/all/uskorenie-trigonometricheskih-funkciy-v-bc/#:~:text=Роман%20Парпалак"&gt;посоветовал способ&lt;/a&gt; ускорения вычисления квадратного корня из суммы квадратов. Аппроксимация там через формулу &lt;tt&gt;0,96 × x + 0,4 × y&lt;/tt&gt; при &lt;tt&gt;x&lt;/tt&gt; ≥ &lt;tt&gt;y&lt;/tt&gt;. Погрешность должна быть не более 4%.&lt;/p&gt;
&lt;p&gt;Выглядит здорово, я замерил — производительность вырастает в восемь раз, заманчиво, но если посмотреть абсолютную погрешность там она почти 5,5 единиц. Это как будто бы очень много. Я даже нарисовал график разницы между корнем и аппроксимацией в «Днунипере».&lt;/p&gt;
&lt;p&gt;&lt;video src="/pictures/2025.02.19@2x.mp4" autoplay playsinline width=500 height=400 loop muted&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Заменять я не буду, но знать о такой возможности полезно, спасибо, Роман!&lt;/p&gt;
</description>
</item>

<item>
<title>Doom на bc</title>
<guid isPermaLink="false">134355</guid>
<link>https://bolknote.ru/all/doom-na-bc/</link>
<pubDate>Thu, 13 Feb 2025 23:30:24 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/doom-na-bc/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Давно хотел повысить градус безумия своих приложений и изобразить что-нибудь трёхмерное в терминале. Изначально я планировал использовать для этого &lt;i&gt;ASCII&lt;/i&gt;-графику, но вспомнил, что немного &lt;a href="https://bolknote.ru/all/4432/"&gt;экспериментировал с выводом&lt;/a&gt; растра в консоли и решил замахнуться на пиксельное изображение.&lt;/p&gt;
&lt;p&gt;Писать начал, разумеется, на одном из самых далёких от вывода графики на экран языков — &lt;tt&gt;bc&lt;/tt&gt;, я ведь теперь всё на нём пишу (ха-ха). Для работы с  графикой в нём нет буквально ни-че-го! Попутно решить считать это хакатоном — дал себе сутки на реализацию. В итоге, писать начал утром, а закончил в три ночи.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2025.02.13.1@2x.webp" width="350" height="210" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Что получилось в конечном счёте: экранчик игры, внизу набранные очки, количество оставшихся врагов, полоска здоровья, выше головы поверженных противников&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Как вообще устроен вывод графики в текстовый терминал? Надо сказать, что как правило, терминал у нас текстовый число номинально. Да, там выводятся какие-то символы, но в конечном счёте терминал выводит их готовыми картинками на графический экран, а не алфавитно-цифровой, как встарь.&lt;/p&gt;
&lt;p&gt;Обычно мы отсылаем в терминал какие-то символы и он их отображает, а как же передать ему графику? Для этого придумали несколько несовместимых способов. Моя любимая программа для работы в терминале &lt;i&gt;iTerm2&lt;/i&gt; придумала собственный. Графику в этом формате можно передать в терминал специальной текстовой командой:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="nginx"&gt;ESC ] 1337 ; File = [необязательные параметры] : изображение в формате base64 ^G&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Хорошо, с этим разобрались. Но как нарисовать картинку именно из &lt;tt&gt;bc&lt;/tt&gt;? Тут надо решить несколько очевидных проблем.&lt;/p&gt;
&lt;p&gt;Во-первых, графику надо как-то хранить внутри программы. Тут выбора особо нет, со структурами данных в &lt;tt&gt;bc&lt;/tt&gt; негусто, — картинка будет храниться в одномерном массиве, где строки изображения будут последовательно записываться одна за другой.&lt;/p&gt;
&lt;p&gt;Во-вторых, нужно написать свою реализацию кодирования &lt;tt&gt;base64&lt;/tt&gt;. Это, конечно, дело техники, но требует усилий. Тут, кстати, очень помогла обнаруженная в описании языка функция &lt;tt&gt;asciify()&lt;/tt&gt;, которая переводит код символа в сам символ.&lt;/p&gt;
&lt;p&gt;В-третьих, и самое интересное, — нужно выбрать какой-то простой бинарный формат, в котором будет формироваться графика. Тут я сразу подумал о &lt;i&gt;BMP&lt;/i&gt;, так как  в 2005-м году делал &lt;a href="https://bolknote.ru/all/278/"&gt;библиотеку для работы&lt;/a&gt; с ним на &lt;i&gt;PHP&lt;/i&gt;.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2025.02.13.2@2x.webp" width="1000" height="315" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Сохранившийся скриншот, где я пытаюсь аккуратно расписать для себя формат &lt;i&gt;BMP Core&lt;/i&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;i&gt;BMP&lt;/i&gt; — это, как водится во многих старых форматах, внутренне не один формат хранения графики, а несколько. В данном случае я взял самый простой и примитивный — &lt;i&gt;BMP Core&lt;/i&gt; с индексированной палитрой из двух цветов.&lt;/p&gt;
&lt;p&gt;Его плюс — у него очень простой заголовок и его относительно дёшево формировать. Тем более, что мне не хотелось возиться со сжатием, количество вычислений для этого могло превысить все разумные пределы.&lt;/p&gt;
&lt;p&gt;Теперь надо было решить что же я буду писать. На самом деле к этому моменту я уже внутренне определился. В начале двухтысячных локальный фурор произвела игрушка «&lt;a href="https://web.archive.org/web/20031205101316/http://www.wolf5k.com/"&gt;&lt;i&gt;Wolf5k&lt;/i&gt;&lt;/a&gt;», написанная на ДжаваСкрипте. Чтобы понять, чем она крута, надо знать, что ДжаваСкрипт тогда графику выводить не умел — не существовало ни тега &lt;tt&gt;CANVAS&lt;/tt&gt;, ни, тем более, &lt;i&gt;WebGL&lt;/i&gt; или &lt;i&gt;WebGPU&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;Изображение формировалось в текстовом формате &lt;i&gt;XBM&lt;/i&gt;, которое, через весьма остроумный хак, показывалось в браузере. На настоящий момент поддержки этого формата давно уже нет ни в одном современном браузере.&lt;/p&gt;
&lt;p&gt;Это как будто могло быть очень символично — сделать порт игрушки, которая выводила свою графику на языке, для этого в те годы непригодном, на язык, который так же непригоден для этого сейчас.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2025.02.13.3@2x.webp" width="1000" height="292" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Вот и весь исходный код «&lt;i&gt;Wolf5k&lt;/i&gt;»&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;К несчастью, исходный код игры обфусцирован и, когда я в самом начале сел за его чтение, был в отчаянии — мне казалось, что за отведённый самому себе суточный срок разобраться не получится. К счастью, раскопки в веб-архиве принесли в сетях &lt;a href="https://web.archive.org/web/20041208223205/http://www.icarusindie.com/DoItYourSelf/javascript3D/deobfwolk5k.php"&gt;частично деобфусцированный&lt;/a&gt; исходник. С ним я и начал работать.&lt;/p&gt;
&lt;p&gt;Не буду описывать все сложности, с которыми пришлось столкнуться, но примерно к полуночи у меня получился код, который умел рендерить картинку покадрово — к тому времени я ещё не решил проблему опроса клавиатуры и мой «игрок» просто крутился на одном месте. В рендере я увидел несколько проблем, но не критичных.&lt;/p&gt;
&lt;p&gt;Самой большой проблемой была производительность. Но это я отложил на следующий день — решил, что работающая, но немного глючащая и сильно подтормаживающая игра, написанная за сутки — удовлетворительный результат. До окончания хакатона мне предстояло решить ещё одну проблему — проблему опроса клавиатуры.&lt;/p&gt;
&lt;p&gt;«&lt;i&gt;Wolf5k&lt;/i&gt;» — динамичная игра, а во всём языке &lt;tt&gt;bc&lt;/tt&gt; единственная функция ввода — &lt;tt&gt;read()&lt;/tt&gt;, которая требует нажатия на «Энтер» после каждого ввода. Такой себе интерактив.&lt;/p&gt;
&lt;p&gt;В самом языке это никак не решить, так что, признаюсь, тут я немного смухлевал — написал на &lt;tt&gt;zsh&lt;/tt&gt; запускающую часть, которая сама читает клавиатуру и пересылает нажатия в &lt;tt&gt;bc&lt;/tt&gt;, «нажимая» на «Энтер»:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="bash"&gt;#!/bin/zsh
x=/*
while {}; do
    v=
    read -rs -k1 -t0.4 v

    case &amp;quot;${v:l}&amp;quot; in
        [wasdljkm\ ]) printf &amp;quot;%d\n&amp;quot; &amp;quot;&amp;#039;${v:l}&amp;quot;;;
        *)    echo 0;;
    esac
done | bc -g -Ll -f &amp;quot;$0&amp;quot;
exit; */1
/* тут программа на bc */&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Да, не очень честно, но какой выбор?&lt;/p&gt;
&lt;p&gt;К трём ночи у меня была игрушка, в которой всё работало на три с плюсом, особенно, если на экране было не так много объектов. Правда, при поворотах враги иногда пропадали, а иногда взлетали и улетали за пределы экрана. Но в &lt;i&gt;это&lt;/i&gt; уже можно было играть.&lt;/p&gt;
&lt;p&gt;У меня был соблазн опубликовать её на следующий же день, но хорошо, что я дал коду «отлежаться». Во-первых, успел пофиксить все баги, во-вторых, придумал несколько трюков для ускорения, &lt;a href="https://bolknote.ru/all/uskorenie-trigonometricheskih-funkciy-v-bc/"&gt;один из которых&lt;/a&gt; описал вчера.&lt;/p&gt;
&lt;p&gt;Результат &lt;a href="https://github.com/bolknote/bc-doom"&gt;выложил в свой репозиторий&lt;/a&gt;. Несмотря на то, что это порт «&lt;i&gt;Wolf5k&lt;/i&gt;», игра называется &lt;i&gt;BC-Doom&lt;/i&gt;, а не &lt;i&gt;BC-Wolf&lt;/i&gt;, потому что как-то так повелось, — называть все подобные трёхмерные игрушки «Думом», а про «Вульф» уже никто и не помнит, как мне кажется.&lt;/p&gt;
</description>
</item>

<item>
<title>Ускорение тригонометрических и прочих функций в bc</title>
<guid isPermaLink="false">134267</guid>
<link>https://bolknote.ru/all/uskorenie-trigonometricheskih-funkciy-v-bc/</link>
<pubDate>Wed, 12 Feb 2025 21:56:02 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/uskorenie-trigonometricheskih-funkciy-v-bc/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Интересно, что вся стандартная библиотека (подключаемая через ключ &lt;tt&gt;-l&lt;/tt&gt;) для &lt;tt&gt;bc&lt;/tt&gt; написана нативно. С одной стороны, это не очень-то здорово, так как не использует всю мощь современных процессоров для вычисления различных функций, с другой стороны, эти функции можно свободно переопределить, если мы готовы пожертвовать точностью.&lt;/p&gt;
&lt;p&gt;Я тут потихоньку ускоряю одну из своих программ на &lt;tt&gt;bc&lt;/tt&gt;, но все «низко висящие фрукты» я уже подобрал. Добрался до тригонометрических функций. Во внутренней библиотеке косинус &lt;a href="https://github.com/gavinhoward/bc/blob/master/gen/lib.bc#L120"&gt;выражается через синус&lt;/a&gt;, так что, если ускорить синус, то ускорится сразу и косинус.&lt;/p&gt;
&lt;p&gt;Посмотрел разные реализации, в итоге портировал функцию, которую взял из одной из &lt;a href="https://habr.com/ru/companies/ruvds/articles/584460/"&gt;статей на «Хабре»&lt;/a&gt;, получилось так (используется многочлен Чебышёва):&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;define mod(a, b) {
    auto s, m
    s = scale; scale = 0; m = a$ % b$; scale = s; return m
}

define s(x) {
    auto sign, xf, per, xx, y

    x *= 0.63661977236758134308
    if (sign = (x &amp;lt; 0)) x = -x

    xf = x$
    x -= xf

    if (mod(xf, 2)) x = 1 - x

    per = mod(xf / 2, 2)
    xx = x * x
    y = x * (1.5707903005870776 + xx * (-0.6458858977085938 + \
    xx*(0.07941798513358536 - 0.0043223880120647346 * xx)))

    if (sign != per) return -y
    return y
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Расхождение со встроенной в &lt;tt&gt;bc&lt;/tt&gt; реализацией начинается в седьмом знаке, это более чем достаточно для меня, зато вычисление синуса ускорилось больше, чем в четыре раза.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Добавлено позднее&lt;/i&gt;: ещё я заменил функцию нахождения логарифма по основанию десять. Логарифмом я находил количество разрядов числа, чтобы потом вывести его на экран, так что его легко было заменить на цикл с подсчётом порядка делением. Разница в производительности — больше, чем в 60 раз.  Код теперь выглядит так:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;define cnt_digits(x) {
    auto i, s
    s = scale; scale = 0

    for (i = 0; x /= 10; i++){}
    scale = s; return i
}&lt;/code&gt;&lt;/pre&gt;</description>
</item>

<item>
<title>Необычная система счисления в bc</title>
<guid isPermaLink="false">134183</guid>
<link>https://bolknote.ru/all/neobychnaya-sistema-schisleniya-v-bc/</link>
<pubDate>Tue, 11 Feb 2025 22:05:21 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/neobychnaya-sistema-schisleniya-v-bc/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;В моём временно любимом &lt;tt&gt;bc&lt;/tt&gt; есть интересная, но не сразу понятная особенность работы с числами. Даже в режиме ввода десятичных чисел принимаются буквы в верхнем регистре, то есть число может состоять из цифр в диапазонах 0…9 и &lt;i&gt;A&lt;/i&gt;…&lt;i&gt;Z&lt;/i&gt;. Буквы при этом обозначают цифры от десяти до тридцати пяти.&lt;/p&gt;
&lt;p&gt;Но так как режим десятичный, результирующее значение числа, содержащего буквы, вычисляется необычно. Я специально не описываю словами, ниже скажу почему. Принцип на картинке, думаю, понятно как всё получается.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2025.02.11@2x.webp" width="1000" height="377" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Мне стало интересно решить задачу конвертации десятичных чисел в такую необычную систему. Из самого принципа следует, что десятичное число может быть представлено несколькими способами, так что придумать можно куда больше одного алгоритма.&lt;/p&gt;
&lt;p&gt;Сегодня на работе, пока обедали с братишкой, пытались в режиме обсуждения решить задачу в уме. Потратили на это почти весь обед, в конце я перенёс то, что придумалось, в код программы:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="python"&gt;def convert(num):
    if num == 0: return 0
    out, orig_num = &amp;quot;&amp;quot;, num

    while num:
        num, r = divmod(num, 10)
        v = min(2 if r &amp;gt; 5 else 3, num)
        if (digit := v * 10 + r) &amp;gt; 9:
            out = chr(digit - 10 + ord(&amp;#039;A&amp;#039;)) + out
        else:
            out = str(digit) + out

        num -= v

    return out if len(out) &amp;lt; len(str(orig_num)) else orig_num&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;А потом мы решили развлечься ещё одним способом — аккуратно сформулировать эту задачу в тексте и решить её искусственным интеллектом. Взяли топовые сети — ЧатГПТ, ДипСик и так далее.&lt;/p&gt;
&lt;p&gt;Я намеренно не показываю получившийся промпт, вдруг вы захотите тоже попробовать, но скажу сразу — с первого или даже пятого раза сформулировать задачу так, чтобы хоть какая-нибудь нейросеть решила её правильно у нас не получилось. Я, в итоге, сдался, а братишка добился-таки код, который её решает, от ДипСика. Листинг, правда, получился вдвое длиннее, чем у меня.&lt;/p&gt;
&lt;p&gt;Из этого можно сделать важный и почему-то не всем очевидный вывод: иногда задачу проще решить самому, потому что сформулировать её нейросети — очень сложное занятие.&lt;/p&gt;
&lt;p&gt;А если посмотреть чуть глубже, то можно додуматься вот до чего. В ближайшее время искусственный интеллект не убьёт профессию программиста, а просто её модифицирует. Сейчас программисты описывают задачу, переведённую ими в алгоритм, на языке программирования, а в будущем буду описывать её на натуральных языках.&lt;/p&gt;
</description>
</item>

<item>
<title>Ещё немного про random() в bc</title>
<guid isPermaLink="false">134018</guid>
<link>https://bolknote.ru/all/eschyo-nemnogo-pro-random-v-bc/</link>
<pubDate>Thu, 06 Feb 2025 22:07:29 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/eschyo-nemnogo-pro-random-v-bc/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Как я уже рассказывал, &lt;tt&gt;bc&lt;/tt&gt; под «Линуксом» очень старый, — на всех машинах, куда у меня есть доступ, установлена версия 1.07.1 2017-го года. Непонятно с чем связан такой консерватизм, но чем богаты. В этой версии отсутствует до печального много удобных вещей, например, функция для получения случайного числа.&lt;/p&gt;
&lt;p&gt;Ранее я &lt;a href="https://bolknote.ru/all/igra-viselica-na-bc-pod-linuks/"&gt;обнаружил&lt;/a&gt; недокументированную функцию &lt;tt&gt;random()&lt;/tt&gt;, но генератор случайных чисел в линуксовом &lt;tt&gt;bc&lt;/tt&gt; не инициализируется и функция выдаёт на старте всегда одно и тоже число. Её можно покрутить снаружи случайное число раз и это исправляет ситуацию, но способ, который я тогда придумал для этого, так себе.&lt;/p&gt;
&lt;p&gt;Сегодня, пока ехал в такси, придумывал ещё более так себе способы это сделать.&lt;/p&gt;
&lt;p&gt;Мысль моя крутилась вокруг запуска через утилиту &lt;tt&gt;env&lt;/tt&gt;. В мире командной строки так частенько делают, так что этот способ как будто бы чуть более честный, так шелл тут не используется:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="bash"&gt;#!/usr/bin/env -S -i seed_=&amp;quot;0${XDG_SESSION_ID};while(seed_--).=random()#&amp;quot; bc /proc/self/environ
print random()
quit()&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Здорово, правда?&lt;/p&gt;
&lt;p&gt;Вся чёрная магия сосредоточена в первой строке. Файл &lt;tt&gt;/proc/self/environ&lt;/tt&gt; формируется в «Линуксе» для каждого запущенного процесса и содержит унаследованные переменные окружения. Так как там много ненужного нам мусора, очищаем его целиком при помощи ключа &lt;tt&gt;-i&lt;/tt&gt; утилиты &lt;tt&gt;env&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Далее мы создаём переменную окружения &lt;tt&gt;seed_&lt;/tt&gt;, а внутри её формируем небольшую программу, которая запустится до нашего кода. Для &lt;tt&gt;bc&lt;/tt&gt; результат будет выглядеть так:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;seed_=0123456
while(seed_--).=random()
#^@
print random()
quit()&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Я развернул односрочную программу в многострочную для удобства.&lt;/p&gt;
&lt;p&gt;Вместо &lt;tt&gt;123456&lt;/tt&gt;, конечно, будет подставлено число из переменной окружения &lt;tt&gt;$XDG_SESSION_ID&lt;/tt&gt;, которая содержит число. Ноль там впереди, чтобы не случилось ничего страшного, если эта переменная в вашем дистрибутиве «Линукс» отсутствует.&lt;/p&gt;
&lt;p&gt;Мне кажется, это неплохой способ, жаль только что содержимое &lt;tt&gt;$XDG_SESSION_ID&lt;/tt&gt; остаётся одинаковым на всём протяжении жизни сессии. То есть, если запустить программу несколько раз в одном и том же окне терминала, случайные числа будут генерироваться всегда в одной и той же последовательности.&lt;/p&gt;
&lt;p&gt;В конце файла &lt;tt&gt;/proc/self/environ&lt;/tt&gt; всегда есть символ с кодом ноль, который мог бы нам всё испортить, но мы спрятали его за символом комментария — &lt;tt&gt;#&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Как видно, функция &lt;tt&gt;random()&lt;/tt&gt; вызывается &lt;tt&gt;seed_&lt;/tt&gt; раз, что позволяет остановиться на каком-то случайном значении. Точка (&lt;tt&gt;.&lt;/tt&gt;), которой я присваиваю &lt;tt&gt;random()&lt;/tt&gt;, — специальная переменная &lt;tt&gt;bc&lt;/tt&gt;. У неё есть значение, но, фактически, её частенько используют, чтобы присвоить куда-нибудь ненужные возвращаемые значения; иначе они попадут на экран.&lt;/p&gt;
&lt;p&gt;Несложно додуматься до похожего способа, который позволяет читать число из какого-нибудь файла в системе. Нужно только, чтобы оно было там одно. Надо создать файл с содержимым &lt;tt&gt;seed_=\&lt;/tt&gt; и подключить его до файла с числом. Файлы подключаются через перевод строки, действие которого отменяет слеш, так что число, опять же, попадёт в переменную &lt;tt&gt;seed_&lt;/tt&gt;. Дальше всё как в предыдущем примере.&lt;/p&gt;
</description>
</item>

<item>
<title>Англо-русский словарь на bc</title>
<guid isPermaLink="false">133982</guid>
<link>https://bolknote.ru/all/anglo-russkiy-slovar-na-bc/</link>
<pubDate>Wed, 05 Feb 2025 22:15:07 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/anglo-russkiy-slovar-na-bc/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Пока писал «Виселицу» на &lt;tt&gt;bc&lt;/tt&gt;, в процессе немало с ним экспериментировал. Обратил внимание на то, какой он шустрый. Я не делал прямых сравнений, но сложилось такое впечатление. Подмывало как-то потестировать скорость поплотнее, но забил.&lt;/p&gt;
&lt;p&gt;Позже, не справившись с исследовательским зудом, решил попробовать сделать на нём что-то нарочито многострочное, чтобы проверить насколько быстро он работает. Так как набивать несколько тысяч строк — руки отвалятся, придумал сделать англо-русский словарь, тем более, что обрабатывать ввод одиночных английских слов я &lt;a href="https://bolknote.ru/all/igra-viselica-na-bc-pod-linuks/"&gt;уже научился&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Сделал так же, как в версии под «Линукс» — &lt;tt&gt;bc&lt;/tt&gt; переводится на ввод 36-ричных чисел. В таком режиме слова у нас становятся числами.&lt;/p&gt;
&lt;p&gt;Правда есть проблема — под «Мак» слова надо вводить исключительно в верхнем регистре, иначе они трактуются как имена переменных. Можно было бы создать, конечно, кучу переменных, но это работает не очень — некоторые английские слова совпадают с ключевыми словами языка.&lt;/p&gt;
&lt;p&gt;Так что я поступил иначе — проверяю версию &lt;tt&gt;bc&lt;/tt&gt; и, если она достаточной новая (как под «Маком»), запускаю &lt;tt&gt;bc&lt;/tt&gt; через &lt;tt&gt;tr&lt;/tt&gt;, который заменяет буквы в нижнем регистре на буквы в верхнем. В этом случае, начало программы выглядит так:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="bash"&gt;#!/bin/sh
c=/*
tr -u a-z A-Z | bc -R &amp;quot;$0&amp;quot;
exit; */1&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Похожий пролог я уже использовал в прошлый раз, когда надо было «накрутить» рандомизирующую функцию.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2025.02.05@2x.webp" width="1000" height="331" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Сам словарь нашёлся в интернете. Чтобы не заливать в свой репозиторий чужую интеллектуальную собственность, я сделал &lt;tt&gt;make&lt;/tt&gt;-файл, генерирующий мне программу на &lt;tt&gt;bc&lt;/tt&gt; — словарь скачивается, распаковывается и обрабатывается специально написанной программой на Пайтоне. В итоге получается программа на пятьдесят тысяч с гаком строк.&lt;/p&gt;
&lt;p&gt;В результате всё работает шустро, несмотря на линейный поиск. Я вообще не замечаю проблем с производительностью у &lt;tt&gt;bc&lt;/tt&gt;, любопытно. Умели же делать!&lt;/p&gt;
&lt;p&gt;Чтобы минимизировать программу по объёму, я сделал два цикла, а останов поиска делаю через &lt;tt&gt;break&lt;/tt&gt; — он позволяет выйти из внутреннего цикла к началу внешнего:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;while(c) while (c) {
ibase=36;c=read();ibase=A

if(c==19976){&amp;quot;Несколько&amp;quot;;break}
/* тут очень много строк */
if(c==2813515210532){&amp;quot;Сухарь&amp;quot;;break}
if(c==2174201762){&amp;quot;Зигота&amp;quot;;break}
&amp;quot;Неизвестное слово&amp;quot;;}
quit()&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ноль используется для выхода — у меня в &lt;tt&gt;Makefile&lt;/tt&gt; есть небольшой тест, вот он и использует ноль, чтобы прекратить выполнение получившейся программы.&lt;/p&gt;
&lt;p&gt;Результат, как обычно, можно увидеть в &lt;a href="https://github.com/bolknote/bc-enru-dictionary"&gt;моём репозитории&lt;/a&gt;.&lt;/p&gt;
</description>
</item>

<item>
<title>Игра «Виселица» на bc под «Линукс»</title>
<guid isPermaLink="false">133947</guid>
<link>https://bolknote.ru/all/igra-viselica-na-bc-pod-linuks/</link>
<pubDate>Tue, 04 Feb 2025 14:25:00 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/igra-viselica-na-bc-pod-linuks/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Я планировал заняться адаптацией «&lt;a href="https://bolknote.ru/all/igra-viselica-na-bc/"&gt;Виселицы&lt;/a&gt;» на &lt;tt&gt;bc&lt;/tt&gt; под «Линукс» на следующий день, то есть сегодня, но не выдержал и вчера просидел над этим почти до полуночи. Линуксовый &lt;tt&gt;bc&lt;/tt&gt;, конечно, гораздо скромнее по возножностям, было где поломать мозг, но больше всего времени я, кажется, потратил на рандомизацию.&lt;/p&gt;
&lt;p&gt;Я вчера писал уже, что в документации для линуксового &lt;tt&gt;bc&lt;/tt&gt; нет упоминаний функций для генерации случайных чисел, но чтение исходников показало, что документации не всегда можно верить. Функция есть, называется она &lt;tt&gt;random()&lt;/tt&gt;, но не работает так как хочется — при вызове генерирует всегда одну и ту же последовательность.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2025.02.04.1@2x.webp" width="600" height="122" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Видимо, её забыли правильно проинициализировать. Непонятно почему за столько лет это нельзя исправить, ведь новые версии &lt;a href="https://www.gnu.org/software/bc/"&gt;иногда выходят&lt;/a&gt;, правда в списке изменений последних версий сплошь какая-то косметика.&lt;/p&gt;
&lt;p&gt;Так как никаких способов исправить ситуацию, не меняя исходный код &lt;tt&gt;bc&lt;/tt&gt;, я не обнаружил, решил обойтись хаком — при запуске вызвать &lt;tt&gt;random()&lt;/tt&gt; случайное количество раз, чтобы в коде моей программу его внутреннее состояние тоже стало случайным.&lt;/p&gt;
&lt;p&gt;Для этого я изменил способ запуска программы — сделал его шелл-скриптом, который передаёт в &lt;tt&gt;bc&lt;/tt&gt; на инициализации цикл, генерирующий случайное количество вызовов &lt;tt&gt;random()&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="bash"&gt;#!/bin/bash
x=/*
BC_LINE_LENGTH=0 bc -l -q &amp;lt;(/usr/bin/seq -f &amp;quot;x=random()+%g&amp;quot; $RANDOM) &amp;quot;$0&amp;quot;
exit; */1&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Обвязка с комментарием сделана так, чтобы и шелл, и &lt;tt&gt;bc&lt;/tt&gt; не увидели в коде ничего странно и не выдали ошибку синтаксиса, а вся мякотка происходит в строке &lt;tt&gt;/usr/bin/seq -f &amp;quot;x=random()+%g&amp;quot; $RANDOM&lt;/tt&gt;. Команда &lt;tt&gt;seq&lt;/tt&gt; генерирует последовательность &lt;tt&gt;x=random()+число&lt;/tt&gt; столько раз, сколько указано в переменной &lt;tt&gt;$RANDOM&lt;/tt&gt;. &lt;tt&gt;$RANDOM&lt;/tt&gt; — это специальная переменная шелла, которая содержит случайное значение.&lt;/p&gt;
&lt;p&gt;Подстановка &lt;tt&gt;%g&lt;/tt&gt; необходима, чтобы заработал шаблон в параметре команды &lt;tt&gt;seq&lt;/tt&gt;, без этого она ругается на неправильный аргумент.&lt;/p&gt;
&lt;p&gt;Ещё одной крупной проблемой стали строки — в этой версии &lt;tt&gt;bc&lt;/tt&gt; не поддерживается присваивание их переменным. Из-за этого код пришлось сильно переделать.&lt;/p&gt;
&lt;p&gt;Для вывода, вместо кучи переменных, пришлось сделать функцию, которая выводит букву по её коду через горку условий. Код получился похожим на то место, где я выбираю слово по номеру:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;define void print_letter(c) {
    if(!--c){&amp;quot;a&amp;quot;}
    if(!--c){&amp;quot;b&amp;quot;}
    if(!--c){&amp;quot;c&amp;quot;}
    /* …тут все 26 букв */
    if(!--c){&amp;quot;y&amp;quot;}
    if(!--c){&amp;quot;z&amp;quot;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Я не стал ставить &lt;tt&gt;return&lt;/tt&gt;, чтобы сделать функцию более визуально компактной, тем более, что на производительность мне, по большому счёту, наплевать.&lt;/p&gt;
&lt;p&gt;Кстати, ввод удалось сильно упростить, перейдя на тридцатишестиричную систему исчисления, где все английские буквы соответствую числам:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;define read_letter() {
    auto z, b
    b = ibase
    ibase = 36

    z = read()
    ibase = b
    return z - 9
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Переменная &lt;tt&gt;ibase&lt;/tt&gt; отвечает за систему исчисления при вводе чисел.&lt;/p&gt;
&lt;p&gt;Таким образом, численное исчисление получили не только все одиночные буквы, но и все слова. В теории, это можно использовать для ввода одиночных команд на английском языке. Я использую это свойство, чтобы распознать команду &lt;tt&gt;exit&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Остальные проблемы решались попроще. Ещё я немного поломал голову чем заменить &lt;tt&gt;ceil&lt;/tt&gt; (округление вверх), потом догадался прибавить единицу и, выставив через специальную переменную &lt;tt&gt;scale&lt;/tt&gt; нулевую точность для цифр после запятой, разделил получившееся значение на один, чтобы отбросить дробную часть:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;define word_len(c) {
    auto r
    scale=10
    r = l(c) / l(256) + 1
    scale=0
    return r/1
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Функцию логарифма &lt;tt&gt;log()&lt;/tt&gt; тут пришлось заменить на натуральный логарифм &lt;tt&gt;l()&lt;/tt&gt; — это одна из немногих математических функций, которые поддерживаются в этой версии &lt;tt&gt;bc&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Остальные замены довольно тривиальны, я писал о них ещё &lt;a href="https://bolknote.ru/all/igra-viselica-na-bc/"&gt;в прошлый раз&lt;/a&gt;. Результат положил отдельным файлом &lt;a href="https://github.com/bolknote/bc-hangman"&gt;в моём репозитории&lt;/a&gt;.&lt;/p&gt;
</description>
</item>

<item>
<title>Игра «Виселица» на bc</title>
<guid isPermaLink="false">133926</guid>
<link>https://bolknote.ru/all/igra-viselica-na-bc/</link>
<pubDate>Mon, 03 Feb 2025 21:43:04 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/igra-viselica-na-bc/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;После того как я &lt;a href="https://bolknote.ru/all/99-butylok-kalkulyator-bc/"&gt;написал&lt;/a&gt; «бутылки пива» на &lt;tt&gt;bc&lt;/tt&gt;, стало интересно попробовать написать на этом языке какую-нибудь игру. На этом попроще я не первый, есть, например, очень годный &lt;a href="https://habr.com/ru/articles/132840/"&gt;пасьянс&lt;/a&gt;, но попробовать сделать что-то своё тоже хочется.&lt;/p&gt;
&lt;p&gt;В силу специфики обработки ввода &lt;tt&gt;bc&lt;/tt&gt;, писать нужно что-то пошаговое — фоновое выполнение не поддерживается, программа может работать только от ввода до ввода. Долго не размышляя, я как-то сразу решил написать игру «Виселица». Я её уже &lt;a href="https://bolknote.ru/tags/hangman-game/"&gt;писал&lt;/a&gt; под «Флиппер», если помните.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2025.02.03@2x.webp" width="1000" height="275" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Игровой процесс игры «Веселица», написанной на &lt;tt&gt;bc&lt;/tt&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;На пути к успеху сразу начались трудности. Несмотря на то, что в &lt;tt&gt;bc&lt;/tt&gt; есть многообещающая функция &lt;tt&gt;read()&lt;/tt&gt;, оказалось, что с её помощью можно вводить только выражения языка и числа. В вышеупомянутом «пасьянсе» автор обошёлся числами, а мне нужны буквы, иначе играть будет невозможно.&lt;/p&gt;
&lt;p&gt;К счастью, «выражения» — это ещё и переменные. Если задать значения всем однобуквенным переменным, мы сможем определить какую именно букву нажал пользователь.&lt;/p&gt;
&lt;p&gt;К тому же можно ещё сразу сделать таблицу, которая позволит нам рисовать клавиатуру, так как других способов вывести последовательно буквы в языке нет.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;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
u=21;v=22;w=23;x=24;y=25;z=26

co[a]=&amp;quot;a&amp;quot;;co[b]=&amp;quot;b&amp;quot;;co[c]=&amp;quot;c&amp;quot;;co[d]=&amp;quot;d&amp;quot;;co[e]=&amp;quot;e&amp;quot;;co[f]=&amp;quot;f&amp;quot;;co[g]=&amp;quot;g&amp;quot;;co[h]=&amp;quot;h&amp;quot;;co[i]=&amp;quot;i&amp;quot;;co[j]=&amp;quot;j&amp;quot;
co[k]=&amp;quot;k&amp;quot;;co[l]=&amp;quot;l&amp;quot;;co[m]=&amp;quot;m&amp;quot;;co[n]=&amp;quot;n&amp;quot;;co[o]=&amp;quot;o&amp;quot;;co[p]=&amp;quot;p&amp;quot;;co[q]=&amp;quot;q&amp;quot;;co[r]=&amp;quot;r&amp;quot;;co[s]=&amp;quot;s&amp;quot;;co[t]=&amp;quot;t&amp;quot;
co[u]=&amp;quot;u&amp;quot;;co[v]=&amp;quot;v&amp;quot;;co[w]=&amp;quot;w&amp;quot;;co[x]=&amp;quot;x&amp;quot;;co[y]=&amp;quot;y&amp;quot;;co[z]=&amp;quot;z&amp;quot;

exit = -1&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Заодно я задал значение переменной &lt;tt&gt;exit&lt;/tt&gt;, это слово пользователь может ввести, чтобы выйти.&lt;/p&gt;
&lt;p&gt;Весь интерфейс рисуется при помощи управляющих последовательностей, благо хоть тут проблем нет — указываешь коды прямо в строке и всё работает.&lt;/p&gt;
&lt;p&gt;Кстати о строках. В языке они присутствуют, но, по большому счёту, сделать с ними ничего нельзя. Например, в игре нужна функция поиска буквы в строке или хотя бы получения символа по индексу. Ничего такого нет даже в помине. Как тогда быть?&lt;/p&gt;
&lt;p&gt;Единственное решение, которое приходит в голову — кодировать слова, как числа. 26 букв легко умещаются в один байт, поэтому можно кодировать по байту на цифру. Я написал функцию на несколько тысяч строк, которая содержит закодированные слова и возвращает одно из них, в зависимости от аргумента:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;define get_word(c) {
    if(!--c) return 4328588043
    if(!--c) return 4328588820
    /* и так далее */
    if(!--c) return 437194509

    return -c
}

word = get_word(irand(get_word(0)) + 1)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Как видно, если передать в функцию ноль, она вернёт количество элементов, это полезно для того, чтобы знать до какого предела генерировать случайное число.&lt;/p&gt;
&lt;p&gt;Функция &lt;tt&gt;irand&lt;/tt&gt;, используемая тут, является расширением &lt;tt&gt;bc&lt;/tt&gt;, у меня на «Маке» она поддерживается, но под «Линуксом» её нет, так же как и вообще любой другой функции для работы со случайными числами.&lt;/p&gt;
&lt;p&gt;С такими «строками» можно уже как-то работать, например, считать длину, чтобы вывести подходящее количество «окошек», в которых будут появляться буквы:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;define word_len(c) {
    scale=10
    return ceil(log(c, 256), 0)
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Или вывести на печать:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;define void print_word(c) {
    auto word, i, mod

    scale=0
    for (i = 0; c; i++) {
        c = divmod(c, 256, mod[])
        word[i] = mod[0]
    }

    while (i--) {
        print co[word[i]]
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;В общем, всё как с обычными строками, только чуть-чуть очень сильно неудобно.&lt;/p&gt;
&lt;p&gt;Остальное, в общем-то, писать было просто — логика игры очень простая, пишется за несколько минут. На результат можно посмотреть в &lt;a href="https://github.com/bolknote/bc-hangman"&gt;моём репозитории&lt;/a&gt; на «Гитхабе».&lt;/p&gt;
&lt;p&gt;В теории, игру можно портировать и на «Линукс», надо только избавиться от хранения строк в переменных, заменить генерацию случайных чисел на внешний генератор, заменить &lt;tt&gt;log()&lt;/tt&gt; на &lt;tt&gt;l()&lt;/tt&gt;, а &lt;tt&gt;divmod()&lt;/tt&gt; на деление и взятие модуля и избавиться от &lt;tt&gt;length()&lt;/tt&gt; — массив в качестве аргумента в «Линуксе» не поддерживается.&lt;/p&gt;
</description>
</item>

<item>
<title>99 бутылок: калькулятор bc</title>
<guid isPermaLink="false">133908</guid>
<link>https://bolknote.ru/all/99-butylok-kalkulyator-bc/</link>
<pubDate>Sun, 02 Feb 2025 19:42:38 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/99-butylok-kalkulyator-bc/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Разбирал одну старенькую научную статью с некоторым количеством математики, а внутри увидел вычисления на &lt;tt&gt;bc&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Не особо с ним знаком, но несколько раз пользовался, даже не вникая что он умеет. Честно говоря, не помню зачем он мне тогда понадобился, наверное надо было что-то вычислить в консоли. Из статей в интернете, где он иногда вскользь упоминался, я знал, что это навороченный калькулятор, но не знал насколько.&lt;/p&gt;
&lt;p&gt;В общем, оказалось, там внутри целый язык программирования, с циклами, ветвлениями, локальными переменными, строками, массивами и числам. Поддерживаются даже пользовательские функции. Решил попробовать написать на нём очередную «песню о пиве».&lt;/p&gt;
&lt;p&gt;&lt;b&gt;82. bc&lt;/b&gt; — интерактивный интерпретатор Си-подобного языка, появившийся ещё в 1975 году как интерфейс для утилиты &lt;tt&gt;dc&lt;/tt&gt;, на котором «песню о пиве» я &lt;a href="https://bolknote.ru/all/99-bottles-dc/"&gt;уже писал&lt;/a&gt;. Утилита &lt;tt&gt;dc&lt;/tt&gt; выполняла вычисления с произвольной точностью, используя обратную польскую запись, а &lt;tt&gt;bc&lt;/tt&gt; предоставила более привычный Си-подобный синтаксис, транслируя его в команды &lt;tt&gt;dc&lt;/tt&gt;. В 1991 году утилита &lt;tt&gt;bc&lt;/tt&gt; была стандартизирована &lt;i&gt;POSIX&lt;/i&gt;, и сегодня существует несколько её реализаций.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;/* Beer song. Evgeny Stepanischev, Jan 2025 */

define void bottles(b) {
    if (b) print b else print &amp;quot;No&amp;quot;
    &amp;quot; bottle&amp;quot;
    if (b-1) print &amp;quot;s&amp;quot;
    &amp;quot; of beer&amp;quot;
}

for(beer = 99; beer;) {
    bottles(beer); &amp;quot; on the wall, &amp;quot;
    bottles(beer); print &amp;quot;!\n&amp;quot;

    print &amp;quot;Take one down, pass it around,\n&amp;quot;
    bottles(--beer); print &amp;quot; on the wall!\n\n&amp;quot;
}

print &amp;quot;No more bottles of beer on the wall,\n&amp;quot;
print &amp;quot;No more bottles of beer!\n&amp;quot;
print &amp;quot;Go to the store and buy some more,\n&amp;quot;
bottles(99); &amp;quot; on the wall!&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Единственное, что вызвало у меня затруднение — это как сделать так, чтобы функция ничего не возвращала. Дело в том, что функции в &lt;tt&gt;bc&lt;/tt&gt; по-умолчанию возвращают число. Если не указано какое, вернётся ноль. А в глобальном контексте то, что возвращается из функции будет напечатано на экране. Поэтому у меня выводился лишний ноль. Чтобы это исправить, нужно в определение функции добавить ключевое слово &lt;tt&gt;void&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Никаких других сложностей с этой программой у меня не возникло, язык простой, хорошо продуманный, лёгок в освоении.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Добавлено позднее&lt;/i&gt;: как оказалось, у языка есть свои особенности о которых нелишне знать. Например, подключение математической библиотеки меняет точность, определяемую переменной &lt;tt&gt;scale&lt;/tt&gt;, что влияет, например, на операцию вычисления модуля, она начинает работать иначе.&lt;/p&gt;
&lt;p&gt;Другая странность — операции сдвига работают в десятичной системе. Не понимаю какой от этого толк. Например, &lt;tt&gt;1&amp;lt;&amp;lt;2&lt;/tt&gt; даст &lt;tt&gt;100&lt;/tt&gt;.&lt;/p&gt;
</description>
</item>


</channel>
</rss>