Если spigot'а перевернуть, то есть внутренним циклом проходить по переносам(от старших к младшим), а внешним по множителям/делителям(в убывающем направлении), то понадобится только массив переносов. При вычислении по 4 цифры переносы будут меньше 10000*2, и хранить потребуется 1000/4*2=500 байт. На каждой итерации внешнего цикла можно сгенерировать оптимальный код для внутреннего, поскольку там требуется только умножение/деление на константу. Вычислений здесь меньше конечно не станет, но не понадобится делать CALL/RET, насиловать стек, да и искать процедуру по таблице. После завершения внешнего цикла, нужно еще раз пройтись по переносам, приводя их к диапазону до 10000, и увеличивая соседний если нужно. Никаких "недействительных" цифр здесь не будет, если двигаться от младших к старшим. Если сделать процедуры умножения/деления 16x24->40, 40/24->16_24, то можно будет вычислять хоть 100К цифр, сейчас это конечно смысла не имеет, но 20 лет назад вычислить 100К цифр при 64К памяти было бы неплохо, пусть даже и за несколько месяцев.

spigot.txt

Сумма вычисляется по формуле s=s*10000+p[i]*a, затем это делится на b. Поскольку a и b во внутреннем цикле можно считать константами, то возможно получится одновременно умножать на 10000 и делить на b, не вылезая за пределы 16 бит. По крайнем мере в той ветви алгоритма где делитель прибавляется, можно сначала добавить множитель, и если результат станет положительным, значит на данном шаге делитель нужно вычитать. Оптимизация здесь возможна за счёт того, что сдвиг суммы станет общим для умножения и деления, и вроде как не потребуется подгружать младшие байты для следующих итераций. А вот про p[i] можно сразу сказать, что частное будет равно 0, поскольку a<b, и вычислять нужно только остаток. Но эти идеи еще нуждаются в проверке.