zz.h(3)
💖 NAME 💖
okay so bestie, welcome to zz.h(3) — straight out of the Library Functions Manual, section 3. This is the header for Большие неотрицательные целые числа — aka big non-negative integers. bignum math, but make it cute. 🫶✨
🦋 SYNOPSIS 🦋
#include 'bee2/defs.h'
#include 'bee2/core/safe.h'
🌸 Функции (the functions, the whole roster) 🌸
bool_t zzIsEven (const word a[], size_t n)— is this number even? like, even-even? 👀bool_t zzIsOdd (const word a[], size_t n)— is this number odd?word zzAdd (word c[], const word a[], const word b[], size_t n)— adding numbers together 🧮word zzAdd2 (word b[], const word a[], size_t n)— adding a number into another oneword zzAdd3 (word c[], const word a[], size_t n, const word b[], size_t m)— adding numbers of arbitrary lengthword zzAddW (word b[], const word a[], size_t n, register word w)— adding a number and a wordword zzAddW2 (word a[], size_t n, register word w)— adding a word inbool_t zzIsSumEq (const word c[], const word a[], const word b[], size_t n)— does the sum of the numbers equal the number?bool_t zzIsSumWEq (const word b[], const word a[], size_t n, register word w)— does a number plus a word equal the number?word zzSub (word c[], const word a[], const word b[], size_t n)— subtracting numbersword zzSub2 (word b[], const word a[], size_t n)— decrementing a numberword zzSubW (word b[], const word a[], size_t n, register word w)— subtracting a word from a numberword zzSubW2 (word a[], size_t n, register word w)— decrementing a number by a wordvoid zzNeg (word b[], const word a[], size_t n)— minus. negation. the ✨negative✨ vibeword zzMulW (word b[], const word a[], size_t n, register word w)— multiplying a number by a wordword zzAddMulW (word b[], const word a[], size_t n, register word w)— adding the product of a number and a wordword zzSubMulW (word b[], const word a[], size_t n, register word w)— subtracting the product of a number and a wordvoid zzMul (word c[], const word a[], size_t n, const word b[], size_t m, void *stack)— multiplying numbersvoid zzSqr (word b[], const word a[], size_t n, void *stack)— squaring a numberbool_t zzSqrt (word b[], const word a[], size_t n, void *stack)— square root extractionword zzDivW (word q[], const word a[], size_t n, register word w)— dividing a number by a machine wordword zzModW (const word a[], size_t n, register word w)— remainder from dividing a number by a machine wordword zzModW2 (const word a[], size_t n, register word w)— remainder from dividing a number by a small machine wordvoid zzDiv (word q[], word r[], const word a[], size_t n, const word b[], size_t m, void *stack)— dividing numbersvoid zzMod (word r[], const word a[], size_t n, const word b[], size_t m, void *stack)— remainder from dividing numbersvoid zzGCD (word d[], const word a[], size_t n, const word b[], size_t m, void *stack)— greatest common divisorbool_t zzIsCoprime (const word a[], size_t n, const word b[], size_t m, void *stack)— are they coprime?void zzLCM (word d[], const word a[], size_t n, const word b[], size_t m, void *stack)— least common multiplevoid zzExGCD (word d[], word da[], word db[], const word a[], size_t n, const word b[], size_t m, void *stack)— the extended Euclidean algorithmint zzJacobi (const word a[], size_t n, const word b[], size_t m, void *stack)— the Jacobi symbolvoid zzAddMod (word c[], const word a[], const word b[], const word mod[], size_t n)— modular addition of numbersvoid zzAddWMod (word b[], const word a[], register word w, const word mod[], size_t n)— modular addition of a number and a wordvoid zzSubMod (word c[], const word a[], const word b[], const word mod[], size_t n)— modular subtraction of numbersvoid zzSubWMod (word b[], const word a[], register word w, const word mod[], size_t n)— modular subtraction of a word from a numbervoid zzNegMod (word b[], const word a[], const word mod[], size_t n)— additive inversion of numbers modulovoid zzMulMod (word c[], const word a[], const word b[], const word mod[], size_t n, void *stack)— modular multiplication of numbersvoid zzMulWMod (word b[], const word a[], register word w, const word mod[], size_t n, void *stack)— modular multiplication of a number by a wordvoid zzSqrMod (word b[], const word a[], const word mod[], size_t n, void *stack)— modular squaring of numbersvoid zzInvMod (word b[], const word a[], const word mod[], size_t n, void *stack)— modular inversionvoid zzDivMod (word b[], const word divident[], const word a[], const word mod[], size_t n, void *stack)— modular divisionvoid zzDoubleMod (word b[], const word a[], const word mod[], size_t n)— doubling a number modulovoid zzHalfMod (word b[], const word a[], const word mod[], size_t n)— halving a number modulosize_t zzAlmostInvMod (word b[], const word a[], const word mod[], size_t n, void *stack)— almost-inversion modulobool_t zzRandMod (word a[], const word mod[], size_t n, gen_i rng, void *rng_state)— random residue modulobool_t zzRandNZMod (word a[], const word mod[], size_t n, gen_i rng, void *rng_state)— random non-zero residue modulovoid zzRed (word a[], const word mod[], size_t n, void *stack)— standard reductionvoid zzRedCrand (word a[], const word mod[], size_t n, void *stack)— Crandall reductionvoid zzRedBarrStart (word barr_param[], const word mod[], size_t n, void *stack)— Barrett reduction initvoid zzRedBarr (word a[], const word mod[], size_t n, const word barr_param[], void *stack)— Barrett reductionvoid zzRedMont (word a[], const word mod[], size_t n, register word mont_param, void *stack)— Montgomery reductionvoid zzRedCrandMont (word a[], const word mod[], size_t n, register word mont_param, void *stack)— Montgomery reduction modulo a Crandall modulusvoid zzPowerMod (word c[], const word a[], size_t n, const word b[], size_t m, const word mod[], void *stack)— modular exponentiationword zzPowerModW (register word a, register word b, register word mod, void *stack)— modular exponentiation of a machine word
🧚 ПОДРОБНОЕ ОПИСАНИЕ 🧚 (the detailed description, aka the lore)
💜 ОБЩИЕ ПОЛОЖЕНИЯ 💜 (general setup)
okay so the tea is: this whole thing implements operations on big non-negative integers. no negatives unless you zzNeg them, periodt.
A number is given as an array of machine words: word w[n]. Machine word w[0] is the least significant, machine word w[n - 1] is the most significant. big-endian girlies stay mad, this is little-endian energy. 💅
The empty number (n = 0) counts as zero. yes, a whole zero. iconic.
In the function descriptions, B = 2^{B_PER_W} is the base of the numeral system. 🧮
The function zzDoubleMod(), together with zzAddMod() and zzSubMod(), lets you set up fast modular multiplication of a number by a small constant. for example, computing b <- 7 a \mod mod can be arranged like this:
zzDoubleMod(b, a, mod, n);
zzDoubleMod(b, b, mod, n);
zzDoubleMod(b, b, mod, n);
zzSubMod(b, a, mod, n);
Similarly, zzHalfMod() lets you set up fast modular division by certain constants. 🎀
Предусловие (precondition) — read it, bestie, it's not optional:
- All input pointers are valid. fr.
- In the functions that work with numbers, at the memory addresses for the numbers, a number of machine words is reserved that is either clear from context or spelled out in the function descriptions.
- The auxiliary
stackbuffer does not overlap with any other buffers.
🌈 РЕДУКЦИЯ 🌈 (reduction)
A reduction consists of determining the residue of the number [2n]a modulo [n]mod. The number being processed always consists of 2n machine words, and the result is always returned in place of a (compare with zzMod()). To make these conventions loud and clear, instead of Mod (remainder of division) we write Red (reduction). different word, different rules, iykyk. 👑
Besides the ordinary reduction, fast reductions over special moduli are also implemented. slay.
🔥 ФУНКЦИИ 🔥 (the functions themselves)
✨ word zzAdd (word c[], const word a[], const word b[], size_t n)
The sum [n]c of the numbers [n]a and [n]b is determined:
c <- (a + b) \mod B^n, carry <- (a + b) \div B^n,
c + B^n * carry == a + b.
Предусловие — the buffer c either does not overlap, or coincides with each of the buffers a, b.
Возвращает — the carry word carry.
Аргументы:
c— the suma— the first addendb— the second addendn— the length ofa,bin machine words
✨ word zzAdd2 (word b[], const word a[], size_t n)
The number [n]a is added to the number [n]b:
b <- (a + b) \mod B^n, carry <- (a + b) \div B^n.
Предусловие — the buffer b either does not overlap, or coincides with the buffer a.
Возвращает — the carry word carry.
Аргументы
b— первое слагаемое / суммаa— второе слагаемоеn— длинаa,bв машинных словах
word zzAdd3 (word c[], const word a[], size_t n, const word b[], size_t m)
okay so эта штука складывает два числа, которые могут быть разной длины, и результат по длине = max(n, m). Считается сумма [max(n, m)]с чисел [n]a и [m]b:
c <- (a + b) \mod B^{max(n,m)}, carry <- (a + b) \div B^{max(n,m)}.
Предусловие
Буфер c либо не пересекается, либо совпадает с каждым из буферов a, b.
Возвращает
Слово переноса carry.
Аргументы
c— суммаa— первое слагаемоеn— длинаaв машинных словахb— второе слагаемоеm— длинаbв машинных словах
void FAST zzAddMod (word c[], const word a[], const word b[], const word mod[], size_t n)
Считается сумма [n]c чисел [n]a и [n]b по модулю [n]mod:
с <- (b + a) \mod mod.
🫶 заметь: тут модуль держит всё в узде, так что сумма не разлетается, periodt.
Предусловие
a < mod && b < mod.- Буфер
cлибо не пересекается, либо совпадает с каждым из буферовa,b. - Буфер
сне пересекается с буферомmod.
Регулярность
Имеется ускоренная нерегулярная редакция.
Аргументы
c— суммаa— первое слагаемоеb— второе слагаемоеmod— модульn— длина чисел в машинных словах
Перекрестные ссылки
zzAddMod().
Используется в
zzAddMod().
word zzAddMulW (word b[], const word a[], size_t n, register word w)
К числу [n]b добавляется произведение числа [n]a на машинное слово w:
b <- (b + a * w) \mod B^n, carry <- (b + a * w) \div B^n.
Предусловие
Буфер b либо не пересекается, либо совпадает с буфером a.
Возвращает
Слово переноса carry.
Аргументы
b— слагаемое / суммаa— первый множительn— длинаa,bв машинных словахw— второй множитель
word zzAddW (word b[], const word a[], size_t n, register word w)
Считается сумма [n]b числа [n]a и слова w:
b <- (a + w) \mod B^n, carry <- (a + w) \div B^n.
Предусловие
Буфер b либо не пересекается, либо совпадает с буфером a.
Возвращает
Слово переноса carry.
Аргументы
b— суммаa— первое слагаемоеn— длинаaв машинных словахw— второе слагаемое
word zzAddW2 (word a[], size_t n, register word w)
К числу [n]a добавляется слово w:
a <- (a + w) \mod B^n, carry <- (a + w) \div B^n.
in-place moment — прибавляем прям в тот же буфер, slay ✨
Возвращает
Слово переноса carry.
Аргументы
a— слагаемое / суммаn— длинаaв машинных словахw— второе слагаемое
void FAST zzAddWMod (word b[], const word a[], register word w, const word mod[], size_t n)
Считается сумма [n]b числа [n]a и слова w по модулю [n]mod:
b <- (a + w) \mod mod.
Предусловие
a < mod && w < mod.- Буфер
bлибо не пересекается, либо совпадает с буферомa. - Буфер
bне пересекается с буферомmod.
Регулярность
Имеется ускоренная нерегулярная редакция.
Аргументы
b— суммаa— первое слагаемоеw— второе слагаемоеmod— модульn— длина чисел в машинных словах
Перекрестные ссылки
zzAddWMod().
Используется в
zzAddWMod().
size_t zzAlmostInvMod (word b[], const word a[], const word mod[], size_t n, void * stack)
Считается число [n]b, почти-мультипликативно обратное к [n]a по модулю [n]mod:
b <- a^{-1} * 2^k \mod mod,
где wwBitSize(mod) <= k <= 2 * wwBitSize(mod).
Предусловие
mod— нечетное &&mod[n - 1] != 0.0 < a < mod.- Буфер
bне пересекается с буферомmod.
Ожидается
\gcd (a, mod) == 1.
Возвращает
Параметр k.
Прим.
- Если
\gcd (a, mod) != 1, тоb <- 0. - Применяя
kразzzHalfMod(), можно определить поbобычный обратный элемент. Применяяn * B_PER_W - kразzzDoubleMod(), можно определить поbобратный элемент относительно умножения Монтгомери.
Схема расчета глубины stack
zzAlmostInvMod_deep(n).
Регулярность
Функция нерегулярна.
Аргументы
b— обратное числоa— обращаемое числоmod— модульn— длина чисел в машинных словахstack— вспомогательная память
void zzDiv (word q[], word r[], const word a[], size_t n, const word b[], size_t m, void * stack)
Определяются частное [n - m + 1]q и остаток [m]r от деления числа [n]a на число [m]b:
q <- a \div b, r <- r \mod b,
a == q * b + r, r < b.
Предусловие
n >= m.m > 0 && b[m - 1] != 0.- Буферы
qиrне пересекаются. - Буфер
rлибо не пересекается с буферомa, либоr == a.
Схема расчета глубины stack
zzDiv_deep(n, m).
Регулярность
Функция нерегулярна.
Аргументы
q— частноеr— остатокa— делимоеn— длинаaв машинных словахb— делительm— длинаbв машинных словахstack— вспомогательная память
void zzDivMod (word b[], const word divident[], const word a[], const word mod[], size_t n, void * stack)
Определяется частное [n]b от деления числа [n]divident на число [n]a по модулю [n]mod:
b <- divident * a^{-1} \mod mod.
Предусловие
mod— нечетное &&mod[n - 1] != 0.a,divident < mod.- Буфер
bне пересекается с буферомmod.
Ожидается
\gcd (a, mod) = 1.
Прим.
Если \gcd (a, mod) != 1, то b <- 0.
Схема расчета глубины stack
zzDivMod_deep(n).
Регулярность
Функция нерегулярна.
Аргументы
b— частноеdivident— делимоеa— делительmod— модульn— длина чисел в машинных словахstack— вспомогательная память
word zzDivW (word q[], const word a[], size_t n, register word w)
Определяется частное [n]q от деления числа [n]a на машинное слово w:
q <- a \div w.
Предусловие
w != 0.- Буфер
qлибо не пересекается, либо совпадает с буферомa.
Возвращает
Остаток от деления.
Аргументы
q— частноеa— делимоеn— длинаaв машинных словахw— делитель
void FAST zzDoubleMod (word b[], const word a[], const word mod[], size_t n)
Определяется произведение [n]b числа [n]a на число 2 по модулю [n]mod:
b <- 2 * a \mod mod.
умножить на двойку, но по модулю — iconic behavior 💅
Предусловие
a < mod.- Буфер
bлибо не пересекается, либо совпадает с буферомa. - Буфер
bне пересекается с буферомmod.
Регулярность
Имеется ускоренная нерегулярная реализация.
Аргументы
b— произведениеa— множительmod— модульn— длина чисел в машинных словах
Перекрестные ссылки
zzDoubleMod().
Используется в
zzDoubleMod().
void zzExGCD (word d[], word da[], word db[], const word a[], size_t n, const word b[], size_t m, void * stack)
Определяется наибольший общий делитель [min(n, m)]d чисел [n]a и [m]b:
d <- \gcd(a, b),
а также положительные числа [m]da и [n]db (коэффициенты Безу) такие, что
da * a - db * b == d
Предусловие
a != 0 && b != 0.- Буферы
d,da,dbне пересекаются между собой и с буферамиa,b.
Схема расчета глубины stack
zzExGCD_deep(n, m).
Регулярность
Функция нерегулярна.
Аргументы
d— н.о.д.da— первый коэффициент Безуdb— второй коэффициент Безуa— первое числоn— длинаaв машинных словахb— второе числоm— длинаbв машинных словахstack— вспомогательная память
void zzGCD (word d[], const word a[], size_t n, const word b[], size_t m, void * stack)
Определяется наибольший общий делитель [min(n, m)]d чисел [n]a и [m]b:
d <- \gcd(a, b).
Предусловие
a != 0 && b != 0.- Буфер
dне пересекается с буферамиaиb.
Прим.
- Использование нулевых
aиbзапрещается для того, чтобы наибольший общий делительdукладывался в [min(n, m)] слов. - Считается, что
\gcd (0, b) = b, в частности,\gcd (0, 0) = 0.
Схема расчета глубины stack
zzGCD_deep(n, m).
Регулярность
Функция нерегулярна.
🎀 Аргументы 🎀
d— н.о.д.a— первое числоn— длинаaв машинных словахb— второе числоm— длинаbв машинных словахstack— вспомогательная память
✨ void FAST zzHalfMod (word b[], const word a[], const word mod[], size_t n) ✨
Окей так вот, эта функция находит частное [n]b от деления числа [n]a на число 2 по модулю [n]mod, типа:
b <- a * 2^{-1} \mod mod.
Предусловие 💅
mod— нечетное&& mod[n - 1] != 0.a < mod.- Буфер
bлибо не пересекается, либо совпадает с буферомa. - Буфер
bне пересекается с буферомmod.
Регулярность
Имеется ускоренная нерегулярная реализация. no cap ✨
Аргументы
b— частноеa— делимоеmod— модульn— длина чисел в машинных словах
Перекрестные ссылки — zzHalfMod().
Используется в — zzHalfMod().
🌸 void zzInvMod (word b[], const word a[], const word mod[], size_t n, void * stack) 🌸
Тут определяется число [n]b, мультипликативно обратное к [n]a по модулю [n]mod, вот так:
b <- a^{-1} \mod mod.
Предусловие 🫶
mod— нечетное&& mod[n - 1] != 0.a < mod.- Буфер
bне пересекается с буферомmod.
Ожидается
\gcd (a, mod) == 1.
Прим.
Если \gcd (a, mod) != 1, то b <- 0. ngl это важно, bestie 🫠
Схема расчета глубины stack
zzInvMod_deep(n).
Регулярность
Функция нерегулярна. periodt 💀
Аргументы
b— обратное числоa— обращаемое числоmod— модульn— длина чисел в машинных словахstack— вспомогательная память
🦋 bool_t zzIsCoprime (const word a[], size_t n, const word b[], size_t m, void * stack) 🦋
Проверяется, что числа [n]a и [m]b взаимно просты, а именно:
\gcd(a, b) == 1?
Возвращает
Признак взаимной простоты a и b. ✨
Схема расчета глубины stack
zzIsCoprime_deep(n, m).
Регулярность
Функция нерегулярна.
Аргументы
a— первое числоn— длинаaв машинных словахb— второе числоm— длинаbв машинных словахstack— вспомогательная память
💖 bool_t zzIsEven (const word a[], size_t n) 💖
Проверяется, что число [n]a является четным. Просто чек, чет или нет.
Возвращает
Признак четности.
Аргументы
a— числоn— длинаaв машинных словах
💜 bool_t zzIsOdd (const word a[], size_t n) 💜
Проверяется, что число [n]a является нечетным. Обратный вайб от zzIsEven(), iykyk ✨
Возвращает
Признак нечетности.
Аргументы
a— числоn— длинаaв машинных словах
🔥 bool_t FAST zzIsSumEq (const word c[], const word a[], const word b[], size_t n) 🔥
Проверяется, что сумма чисел [n]a и [n]b равняется числу [n]c:
a + b == c?
Прим.
Переставляя операнды, можно проверять не только суммы, но и разности. chef's kiss, fr fr 👑
Возвращает
Признак равенства.
Регулярность
Имеется ускоренная нерегулярная редакция.
Аргументы
c— суммаa— первое слагаемоеb— второе слагаемоеn— длинаa,b,cв машинных словах
Перекрестные ссылки — zzIsSumEq().
Используется в — zzIsSumEq().
⭐ bool_t FAST zzIsSumWEq (const word b[], const word a[], size_t n, register word w) ⭐
Проверяется, что сумма числа [n]a и слова w равняется числу [n]b:
a + w == b?
Возвращает
Признак равенства.
Регулярность
Имеется ускоренная нерегулярная редакция.
Аргументы
b— суммаa— первое слагаемоеn— длинаa,bв машинных словахw— второе слагаемое
Перекрестные ссылки — zzIsSumWEq().
Используется в — zzIsSumWEq().
🌈 int zzJacobi (const word a[], size_t n, const word b[], size_t m, void * stack) 🌈
Определяется символ Якоби (a / b) чисел [n]a и [m]b. Это математика, но мы справляемся 💅
Предусловие
b — нечетное.
Прим.
Если b является произведением простых p_1, p_2,.., p_k, то (a / b) = (a / p_1) * (a / p_2) *... * (a / p_k). Здесь (a / p_i) — символ Лежандра: (a / p) равняется 0, если a делится на p, равняется 1, если a — квадратичный вычет \mod p, и равняется -1 в остальных случаях.
Возвращает
Символ Якоби (a / b): 0, 1 или -1.
Схема расчета глубины stack
zzJacobi_deep(n, m).
Регулярность
Функция нерегулярна.
Аргументы
a— первое числоn— длинаaв машинных словахb— второе числоm— длинаbв машинных словахstack— вспомогательная память
🍓 void zzLCM (word d[], const word a[], size_t n, const word b[], size_t m, void * stack) 🍓
Определяется наименьшее общее кратное [n + m]d чисел [n]a и [m]b:
d <- \lcm[a, b].
Предусловие
a != 0 && b != 0.- Буфер
dне пересекается с буферамиaиb.
Прим.
Использование нулевых a и b запрещается для согласованости с zzGCD() и избежания разбора редких, неиспользуемых на практике случаев. lowkey справедливо 🤷♀️
Схема расчета глубины stack
zzLCM_deep(n, m).
Регулярность
Функция нерегулярна.
Аргументы
d— н.о.к.a— первое числоn— длинаaв машинных словахb— второе числоm— длинаbв машинных словахstack— вспомогательная память
🧚 void zzMod (word r[], const word a[], size_t n, const word b[], size_t m, void * stack) 🧚
Определяется остаток [m]r от деления числа [n]a на число [m]b:
a <- a \mod b.
Предусловие
m > 0 && b[m - 1] != 0.- Буфер
rлибо не пересекается с буферомa, либоr == a.
Схема расчета глубины stack
zzMod_deep(n, m).
Регулярность
Функция нерегулярна.
Аргументы
r— остатокa— делимоеn— длинаaв машинных словахb— делительm— длинаbв машинных словахstack— вспомогательная память
🌸 word zzModW (const word a[], size_t n, register word w) 🌸
Определяется остаток от деления числа [n]a на машинное слово w:
r <- a \mod w.
Предусловие
w != 0.
Возвращает
Остаток от деления r.
Аргументы
a— делимоеn— длинаaв машинных словахw— делитель
🎀 word zzModW2 (const word a[], size_t n, register word w) 🎀
Определяется остаток от деления числа [n]a на малое машинное слово w:
r <- a \mod w.
Предусловие
w != 0 && w^2 <= B.
Возвращает
Остаток от деления r.
Прим.
Функция zzModW2() работает быстрее zzModW() на тех платформах, где деление не менее чем в 2 раза медленнее умножения. obsessed с этой оптимизацией ✨
Аргументы
a— делимоеn— длинаaв машинных словахw— делитель
💅 void zzMul (word c[], const word a[], size_t n, const word b[], size_t m, void * stack) 💅
Определяется произведение [n + m]c чисел [n]a на [m]b:
c <- a * b.
Предусловие
Буфер c не пересекается с буферами a и b.
Схема расчета глубины stack
zzMul_deep(n, m).
Аргументы
c— произведениеa— первый множительn— длинаaв машинных словахb— второй множительm— длинаbв машинных словахstack— вспомогательная память
🌈 void zzMulMod (word c[], const word a[], const word b[], const word mod[], size_t n, void * stack) 🌈
Определяется произведение [n]c чисел [n]a и [n]b по модулю [n]mod:
c <- a * b \mod mod.
Предусловие
n > 0 && mod[n - 1] != 0.a < mod && b < mod.
Схема расчета глубины stack
zzMulMod_deep(n).
Аргументы
c— произведениеa— первый множительb— второй множительmod— модульn— длина чисел в машинных словахstack— вспомогательная память
🦋 word zzMulW (word b[], const word a[], size_t n, register word w) 🦋
Определяется произведение [n]b числа [n]a на слово w:
b <- (a * w) \mod B^n, carry <- (a * w) \div B^n.
Предусловие
Буфер b либо не пересекается, либо совпадает с буфером a.
Возвращает
Слово переноса carry.
Аргументы
b— произведениеa— первый множительn— длинаa,bв машинных словахw— второй множитель
🌸 zzMulWMod — умножение на слово по модулю 🌸
void zzMulWMod (word b[], const word a[], register word w, const word mod[],
size_t n, void * stack)
Окей, bestie, вот эта функция вычисляет произведение [n]b числа [n]a на слово w по модулю [n]mod. Звучит как матан? Не, это просто:
b <- a * w \mod mod.
Предусловие (да, проверь, а то будет больно):
<yellow>n > 0 && mod[n - 1] != 0.</yellow><yellow>a < mod.</yellow>
Схема расчета глубины stack:
zzMulWMod_deep(n).
Аргументы:
b— произведение 💖a— первый множитель ✨w— второй множитель 🎀mod— модуль 🦋n— длина чисел в машинных словах 🌸stack— вспомогательная память 💅
💜 zzNeg — отрицательное число по модулю B^n 💜
void zzNeg (word b[], const word a[], size_t n)
Тут мы получаем число [n]b, отрицательное к [n]a по модулю B^n. Это как «отрицательный вайб», но математический:
b <- B^n - a.
Предусловие:
- Буфер
bлибо не пересекается, либо совпадает с буферомa. (Да, можно и так, и так, но не иначе!)
Аргументы:
b— отрицательное число 🙈a— число ✨n— длинаaв машинных словах 🌸
🔥 zzNegMod — аддитивно обратное по модулю 🔥
void FAST zzNegMod (word b[], const word a[], const word mod[], size_t n)
А вот это уже аддитивно обратное число [n]b к [n]a по модулю [n]mod. То есть:
b <- -a \mod mod.
Предусловие:
<yellow>n > 0 && mod[n - 1] != 0.</yellow><yellow>a < mod.</yellow>- Буфер
bлибо не пересекается, либо совпадает с буферомa. - Буфер
bне пересекается с буферомmod.
Регулярность:
Имеется ускоренная нерегулярная редакция. (Типа есть быстрый вариант, но он нерегулярный, iykyk.)
Аргументы:
b— обратное число 💖a— число ✨mod— модуль 🦋n— длина чисел в машинных словах 🌸
Перекрестные ссылки zzNegMod().
Используется в zzNegMod().
(Да, это выглядит как рекурсия, но так в оригинале. Мы просто копируем факты.)
👑 zzPowerMod — возведение в степень по модулю 👑
void zzPowerMod (word c[], const word a[], size_t n, const word b[], size_t
m, const word mod[], void * stack)
Определяется число [n]c, которое является [m]b-ой степенью числа [n]a по модулю [n]mod. Это как pow(), но с модулем:
c <- a^b \mod mod.
Предусловие:
<yellow>n > 0 && mod[n - 1] != 0.</yellow><yellow>a < mod.</yellow>
Прим.:
<rainbow>0^0 == 1.</rainbow>(Да, ноль в нулевой — это единица, не спорь.)
Схема расчета глубины stack:
zzPowerMod_deep(n, m).
Регулярность:
todo (пока todo, bestie, не спрашивай.)
Аргументы:
c— степень 💖a— основание ✨n— длинаa,modв машинных словах 🌸b— показатель 🎀m— длинаbв машинных словах 🦋mod— модуль 💅stack— вспомогательная память 💜
⭐ zzPowerModW — степень по модулю машинного слова ⭐
word zzPowerModW (register word a, register word b, register word mod, void
* stack)
Определяется b-ая степень числа a по модулю машинного слова mod. Возвращает степень.
Предусловие:
<yellow>mod != 0.</yellow>
Возвращает:
- Степень.
Схема расчета глубины stack:
zzPowerModW_deep().
Регулярность:
todo (опять todo, ну такое.)
Аргументы:
a— основание 💖b— показатель ✨mod— модуль 🦋stack— вспомогательная память 🌸
🎲 zzRandMod — случайный вычет по модулю 🎲
bool_t zzRandMod (word a[], const word mod[], size_t n, gen_i rng, void *
rng_state)
С помощью генератора rng с состоянием rng_state определяется случайный вычет [n]a по модулю [n]mod. То есть:
a <-R {0, 1,..., mod - 1}.
Предусловие:
<yellow>n > 0 && mod[n - 1] != 0.</yellow>- Буфер
aне пересекается с буферомmod.
Возвращает:
- Признак успеха. (Типа true/false, но у них свой тип.)
Прим.:
- Если
<cyan>2^{l - 1} <= mod < 2^l</cyan>, то для генерацииaпотребуется<cyan>O_OF_B(l) * 2^l / mod <= 2 * O_OF_B(l)</cyan>случайных октетовrngв среднем. - Если
rngвыдает данные низкого статистического качества, то для генерации может потребоваться больше октетов, чем указано выше. Более того, как только количество потребовавшихся октетов превысит определенный порогd, будет возвращен отрицательный результат. Порогdвыбирается так, что вероятность события "для генерации потребуетсяdистинно случайных октетов" не превосходит<red>2^{-B_PER_IMPOSSIBLE}</red>.
Регулярность:
Время выполнения может флуктуировать. По времени выполнения можно судить о выходных данных rng, но не тех, которые используются для формирования a.
Аргументы:
a— случайное число 💖mod— модуль ✨n— длинаaиmodв машинных словах 🌸rng— генератор случайных чисел 🎀rng_state— состояние генератора 🦋
🚫 zzRandNZMod — случайный ненулевой вычет 🚫
bool_t zzRandNZMod (word a[], const word mod[], size_t n, gen_i rng, void *
rng_state)
С помощью генератора rng с состоянием rng_state определяется случайный ненулевой вычет [n]a по модулю [n]mod:
a <-R {1, 2,..., mod - 1}.
Предусловие:
<yellow>n > 0 && mod[n - 1] != 0 && mod != 1.</yellow>- Буфер
aне пересекается с буферомmod.
Возвращает:
- Признак успеха.
Прим.:
- Если
<cyan>2^{l - 1} <= mod < 2^l</cyan>, то для генерацииaпотребуется<cyan>O_OF_B(l) * 2^l / (mod - 1) ≤ 2^l / (2^{l - 1} - 1) O_OF_B(l)</cyan>случайных октетовrngв среднем. - Повторяется последнее замечание по функции
zzRandMod().
Регулярность:
Время выполнения может флуктуировать. По времени выполнения можно судить о выходных данных rng, но не тех, которые используются для формирования a.
Аргументы:
a— случайное число 💖mod— модуль ✨n— длинаaиmodв машинных словах 🌸rng— генератор случайных чисел 🎀rng_state— состояние генератора 🦋
🔄 zzRed — остаток от деления 🔄
void zzRed (word a[], const word mod[], size_t n, void * stack)
Определяется остаток [n]a от деления числа [2n]a на модуль [n]mod.
Предусловие:
<yellow>n >= 1 && mod[n - 1] != 0.</yellow>- Буферы
aиmodне пересекаются.
Схема расчета глубины stack:
zzRed_deep(n).
Регулярность:
Функция нерегулярна. (Типа не жди стабильности, детка.)
Аргументы:
a— делимое / остаток 💖mod— модуль ✨n— длинаmodв машинных словах 🌸stack— вспомогательная память 🎀
🏎️ zzRedBarr — редукция Барретта 🏎️
void FAST zzRedBarr (word a[], const word mod[], size_t n, const word
barr_param[], void * stack)
Определяется остаток [n]a от деления числа [2n]a на модуль [n]mod. При вычислениях используется параметр Барретта [n + 2]barr_param.
Предусловие:
<yellow>n > 0 && mod[n - 1] != 0.</yellow>- Буфер
aне пересекается с буферомmod.
Ожидается:
barr_paramрассчитан с помощью функцииzzRedBarrStart().
Схема расчета глубины stack:
zzRedBarr_deep(n).
Регулярность:
Имеется ускоренная нерегулярная редакция.
Аргументы:
a— делимое / остаток 💖mod— модуль ✨n— длинаmodв машинных словах 🌸barr_param— параметр Барретта 🎀stack— вспомогательная память 🦋
Перекрестные ссылки zzRedBarr().
Используется в zzRedBarr().
🧮 zzRedBarrStart — старт параметра Барретта 🧮
void zzRedBarrStart (word barr_param[], const word mod[], size_t n, void *
stack)
По модулю [n]mod определяется параметр [n + 2]barr_param:
barr_param <- B^{2n} \div mod.
Этот параметр используется в редукции Барретта.
Предусловие:
<yellow>n > 0 && mod[n] != 0.</yellow>- Буферы
barr_paramиmodне пересекаются.
Схема расчета глубины stack:
zzRedBarrStart_deep(n).
Аргументы:
barr_param— параметр Барретта 💖mod— модуль ✨n— длинаmodв машинных словах 🌸stack— вспомогательная память 🎀
🌈 zzRedCrand — редукция Крэндалла 🌈
void FAST zzRedCrand (word a[], const word mod[], size_t n, void * stack)
Определяется остаток [n]a от деления числа [2n]a на модуль [n]mod, который близок снизу к B^n.
Предусловие:
<yellow>n >= 2 && mod[n - 1] != 0.</yellow>- Модуль
modимеет вид<cyan>B^n - c</cyan>, где<cyan>0 < c < B</cyan>. - Буферы
aиmodне пересекаются.
Схема расчета глубины stack:
zzRedCrand_deep(n).
Регулярность:
Имеется ускоренная нерегулярная редакция.
Аргументы:
a— делимое / остаток 💖mod— модуль Крэндалла ✨n— длинаmodв машинных словах 🌸stack— вспомогательная память (не исп.) 🎀
Перекрестные ссылки zzRedCrand().
Используется в zzRedCrand().
💎 zzRedCrandMont — редукция Монтгомери для Крэндалла 💎
void FAST zzRedCrandMont (word a[], const word mod[], size_t n, register
word mont_param, void * stack)
Определяется результат [n]a редукции Монтгомери числа [2n]a по модулю [n]mod, который близок снизу к B^n:
a <- a * R^{-1} \mod mod, R == B^n.
При вычислениях используется параметр Монтгомери mont_param.
Предусловие:
<yellow>n >= 2 && mod -- нечетное && mod имеет вид B^n - c, где 0 < c < B.</yellow><yellow>a < mod * R.</yellow>mont_paramрассчитан с помощью функцииwordNegInv().- Буфер
aне пересекается с буферомmod.
Схема расчета глубины stack:
zzRedCrandMont_deep(n).
✨ Регулярность ✨
Имеется ускоренная нерегулярная редакция.
Это всё, что дока говорит по этому поводу 💅 просто знай: помимо обычной версии есть ещё ускоренная нерегулярная. Не спрашивай меня, как она выглядит внутри — дока молчит, и я тоже молчу 🫶
🎀 Аргументы 🎀
a— входное число / результатmod— модульn— длинаmodв машинных словахmont_param— параметр Монтгомериstack— вспомогательная память
🦋 Перекрестные ссылки 🦋
zzRedCrandMont().
🌸 Используется в 🌸
zzRedCrandMont().
void FAST zzRedMont (word a[], const word mod[], size_t n, register word mont_param, void * stack)
Определяется результат [n]a редукции Монтгомери числа [2n]a по модулю [n]mod:
a <- a * R^{-1} \mod mod, R == B^n.
При вычислениях используется параметр Монтгомери mont_param.
Предусловие
mod— нечетное &&mod[n - 1] != 0.a < mod * R.mont_paramрассчитан с помощью функцииwordNegInv().- Буфер
aне пересекается с буферомmod.
Прим.
Редукция предложена в статье [Montgomery P. L. Modular multiplication without trial division. Mathematics of Computation, 44(170): 519–521, 1985].
То есть у нас тут целая научная родословная, bestie — 1985 год, серьёзная академическая имба 📜✨
Схема расчета глубины stack
zzRedMont_deep(n).
Регулярность
Имеется ускоренная нерегулярная редакция.
Аргументы
a— входное число / результатmod— модульn— длинаmodв машинных словахmont_param— параметр Монтгомериstack— вспомогательная память
Перекрестные ссылки
zzRedMont().
Используется в
zzRedMont().
void zzSqr (word b[], const word a[], size_t n, void * stack)
Определяется квадрат [2n]b числа [n]a:
b <- a * a.
Предусловие
Буфер b не пересекается с буфером a.
Схема расчета глубины stack
zzSqr_deep(n).
Аргументы
b— квадратa— множительn— длинаaв машинных словахstack— вспомогательная память
void zzSqrMod (word b[], const word a[], const word mod[], size_t n, void * stack)
Определяется квадрат [n]b числа [n]a по модулю [n]mod:
b <- a * a \mod mod.
Предусловие
n > 0 && mod[n - 1] != 0.a < mod.
Схема расчета глубины stack
zzSqrMod_deep(n).
Аргументы
b— квадратa— множительmod— модульn— длина чисел в машинных словахstack— вспомогательная память
bool_t zzSqrt (word b[], const word a[], size_t n, void * stack)
Определяется максимальное целое [(n + 1) / 2]b, квадрат которого не превосходит [n]a:
b <- \floor(\sqrt(a)).
Возвращает
Признак того, что a является полным квадратом (a == b * b).
Предусловие
Буфер b не пересекается с буфером a.
Схема расчета глубины stack
zzSqrt_deep(n).
Регулярность
Функция нерегулярна: условные переходы, нерегулярные блоки.
Так и написано — нерегулярна, вот прям буквально. Условные переходы, нерегулярные блоки, вот это всё 😭 Не жди от неё ровного тайминга, она живёт как хочет 🦋
Аргументы
b— квадратный кореньa— числоn— длинаaв машинных словахstack— вспомогательная память
word zzSub (word c[], const word a[], const word b[], size_t n)
Определяется разность [n]c чисел [n]a и [n]b:
c <- (a - b) \mod B^n, borrow <- (a < b),
c - B^n * borrow == a - b.
Предусловие
Буфер c либо не пересекается, либо совпадает с каждым из буферов a, b.
Возвращает
Слово заема borrow.
Аргументы
c— разностьa— уменьшаемоеb— вычитаемоеn— длинаa,bв машинных словах
word zzSub2 (word b[], const word a[], size_t n)
Число [n]b уменьшается на число [n]a:
b <- (b - a) \mod B^n, borrow <- (b < a).
Предусловие
Буфер c либо не пересекается, либо совпадает с каждым из буферов a, b.
Окей, тут реальный момент: в доке буквально написано «Буферc», хотя параметраcу этой функции вообще нет 🙈 Я это не правлю и не «улучшаю» — переношу ровно как в исходнике, а ты просто держи в голове, что там так написано, фр фр.
Возвращает
Слово заема borrow.
Аргументы
b— уменьшаемое / разностьa— вычитаемоеn— длинаa,bв машинных словах
void FAST zzSubMod (word c[], const word a[], const word b[], const word mod[], size_t n)
Определяется разность [n]с чисел [n]a и [n]b по модулю [n]mod:
c <- (a - b) \mod mod.
Предусловие
n > 0 && mod[n - 1] != 0.a < mod && b < mod.- Буфер
cлибо не пересекается, либо совпадает с каждым из буферовa,b. - Буфер
сне пересекается с буферомmod.
Регулярность
Имеется ускоренная нерегулярная редакция.
Аргументы
c— разностьa— уменьшаемоеb— вычитаемоеmod— модульn— длина чисел в машинных словах
Перекрестные ссылки
zzSubMod().
Используется в
zzSubMod().
word zzSubMulW (word b[], const word a[], size_t n, register word w)
Из числа [n]b вычитается произведение числа [n]a на машинное слово w:
b <- (b - a * w) \mod B^n, carry <- (b < a * w).
Предусловие
Буфер b либо не пересекается, либо совпадает с буфером a.
Возвращает
Слово заема borrow.
Аргументы
b— вычитаемое / разностьa— первый множительn— длинаa,bв машинных словахw— второй множитель
word zzSubW (word b[], const word a[], size_t n, register word w)
Определяется разность [n]b числа [n]a и слова w:
b <- (a - w) \mod B^n, borrow <- (a < w).
Предусловие
Буфер b либо не пересекается, либо совпадает с буфером a.
Возвращает
Слово заема borrow.
Аргументы
b— разностьa— уменьшаемоеn— длинаaв машинных словахw— вычитаемое
word zzSubW2 (word a[], size_t n, register word w)
Число [n]a уменьшается на слово w:
a <- (a - w) \mod B^n, borrow <- (a < w).
Возвращает
Слово заема borrow.
Аргументы
a— уменьшаемое / разностьn— длинаaв машинных словахw— вычитаемое
void FAST zzSubWMod (word b[], const word a[], register word w, const word mod[], size_t n)
Определяется разность [n]b числа [n]a и слова w по модулю [n]mod:
b <- (a - w) \mod mod.
Предусловие
a < mod && w < mod.- Буфер
bлибо не пересекается, либо совпадает с буферомa. - Буфер
bне пересекается с буферомmod.
Регулярность
Имеется ускоренная нерегулярная редакция.
Аргументы
b— разностьa— уменьшаемоеw— вычитаемоеmod— модульn— длина чисел в машинных словах
Перекрестные ссылки
zzSubWMod().
Используется в
zzSubWMod().
👑 Автор 👑
Автоматически создано Doxygen для Библиотека Bee2 из исходного текста.
То есть да, bestie, эту доку не человек писал с любовью, а Doxygen нагенерил из исходников — и всё равно получилось читаемо, я считаю это маленьким чудом ✨💖
И вот мы дошли до самого низа страницы, и там подпись: Библиотека Bee2, версия-дата Вс 25 Янв 2026 00:00:00 и имя страницы zz.h(3) — всё, конец, ты дожил(а) до футера, это буквально финальный босс доки 🎀👑 Атте, слэй, периодт, иди пиши код 🫶💅
📦 where this page comes from
- fedora 44: bee2-devel 2.2.0-1.fc44 · GPL-3.0-only and GPL-3.0-or-later
- fedora 44: bee2-devel 2.2.0-1.fc44 · GPL-3.0-only and GPL-3.0-or-later
- 💖 girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms