Зиновьев Василий

автор библиотеки paradox

Добрый день, друзья! Сегодня вы познакомитесь с «новой» парадигмой в математике и получите реальный инструмент для смелых экспериментов. В конце статьи вы найдёте ссылку на работающую библиотеку C++ (Paradox libraries), для использования в ваших проектах.

Ноль это отражение бесконечности, но что есть зеркало?
Ноль это отражение бесконечности, но что есть зеркало?

Постановка задачи:

Большинство людей уже не воспринимают эти проблемы как проблемы, а профессиональные разработчики искусно обходят все подводные камни работы с нулями и бесконечностями, но давайте нарушим привычный ход вещей и объявим следующие проблемы:

  1. Деление на 0! Да многие из вас воскликнут, это не проблема, мы с лёгкостью можем ловить и обрабатывать такое исключение. Да всё верно, само деление на ноль мы обработаем, но результат операции будет потерян для дальнейших расчётов...

  2. Умножение на 0! Тут справедливо вы заметите, что это вообще не проблема и никогда таковой не была! В целом вы правы, классика нам говорит, что результатом будет 0! Но как дальше использовать это? Снова безвозвратная потеря информации.

  3. Если мы попытаемся разделить результат умножения числа на ноль, на тот же самый ноль, что мы получим в классике? NAN. Какой никакой результат, но теперь мы вообще не понимаем как это использовать..

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

Мы не будем углубляться в историю проблем "деления на ноль" и разбирать "концепции работы с бесконечностями", за историю человечества их накопилось целое множество, о выше упомянутых проблемах и способах их решения вы найдёте много материала в интернете, особенно подробно описал их уважаемый Ivan Galavachov @habit в этих статьях: Часть 1. Вообще-то уже все поделили до нас! Часть 2. Истина где-то рядом, за что ему отдельное спасибо и глубокое уважение.

Итак давайте создадим такой инструмент(метод), который не нарушая общепринятые законы классической математики, решит все перечисленные выше проблемы и сделает это в нашей обычной числовой системе которую использует каждый из наших компьютеров, а именно позволит делить и умножать на 0 и/или бесконечность без потери данных*, решит проблему NAN при 0/0 или бесконечность/бесконечность. Добавим математически строгую и корректную работу с бесконечностями и конечно же устраним проблему переполнения чисел в расчётах.

*(потерей данных в данном случае назовём невозможность обратного восстановления числа при умножении или делении его с нолём и/или бесконечностью), забегу немного вперёд, в итоге мы получим ещё кое-какие фичи, возможно важные, а возможно нет, а их использование возможно станет темой следующих статей других авторов.

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

Общий концепт:

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

Для того, чтобы оперировать бесконечно большими сущностями, теми что находятся за пределами линейки нужен некий ориентир на который мы будем опираться, назовём его Абсолют (А), и дадим определение:

Абсолют (А) — это условно выбранная, мысленно фиксированная "точка" или "состояние" в бесконечности. Она не является числом, не имеет конкретной "величины" в привычном смысле и не может быть выражена в числовой форме. Это методологический прием: поскольку работать с "бесконечностью" вообще абстрактно и сложно, мы вводим A как воображаемый, но фиксированный ориентир в бесконечности. Его "значение" неизвестно (или принципиально неопределимо как число), но мы принимаем его существование и фиксированность по соглашению для нужд нашей модели.

Абсолют служит фундаментальной опорой (репером, базисом), точкой отсчета, относительно которой определяются направления ("порядок Абсолюта," "степень Абсолюта") сравниваются другие бесконечности или конечные величины, строятся и вводится понятие "Ноля", вводится понятия Уровня бесконечности(абсолюта).

Не надо путать Абсолют с классическими понятиями:

Это не мощность/ординал в чистом виде: А не характеризует размер множества (ℵ₀, ℵ₁), а служит внешним ориентиром для сравнения таких размеров.

Это не предел: А — это не число, к которому что-то стремится (как lim x->∞ 1/x = 0). Он — сама условная цель стремления (x -> ?).

Это не "бесконечность" вообще: А — конкретно выбранный (пусть условно) экземпляр бесконечности в данной модели.

Имея такую абстракцию как А, зададим правила для расширенного числового пространства:
пусть Х - регулярное число, зададим что А0 = 1, тогда X = X * А0;

Тогда X = X * А1- это X в бесконечности или если по классике это бесконечность, но в нашем случае конкретная бесконечность, тогда любое регулярное число умноженное на абсолют в степени больше чем 0 это число в бесконечности или по классике это бесконечность. в то же время любое регулярное число умноженное на А-1, А-2 и т.д. это 0.

ноль

регулярные числа

бесконечность

X * А-1, А-2 ,...., А-n

X * А0

X * А1, А2 ,...., Аn

Дадим определение ноля в нашей модели:

Ноль - это любое число умноженное на абсолют в отрицательной степени.

Итак, мы получили индексированную или многоуровневую модель арифметики, и в связи с особенностями её архитектуры, появилась необходимость ввести ещё кое какие правила:

  1. Регулярное число X не может быть равным 0, так как Ноль для нашей системы это множество, то есть запись типа: 0 * А0 некорректна.

  2. Бесконечность не равна бесконечности, если только это не таже самая бесконечность.

  3. Ноль не равен нулю, если только это не тот же самый ноль.

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

Как устроено многомерное число: под капотом Paradox libraries

Когда вы создаёте объект dspirit из обычного числа, происходит не просто копирование значения. Давайте разберёмся, почему и как.

Конструкторы: мост между классической и многомерной математикой

// Основные конструкторы dspirit:

// Из double
dspirit a(3.14);       // Обычное число -> уровень 0
dspirit b(0.0);        // Классический ноль -> особый случай!

// Из float и int
dspirit c(2.5f);       // Float автоматически приводится
dspirit d(42);         // Целое число -> уровень 0

// Специальный конструктор из уровня
dspirit e = dspirit::fromLevel(1.0, -1.0); // Число 1 на уровне -1

Почему ноль — это особый случай?

// Внутри конструктора dspirit::Impl(double value):
void init(double value, double level = 0.0) {
    if (isApproxZero(value)) {
        // Для нуля используем единицу в первом отрицательном слое
        r_ = 1.0;    // Храним 1.0, а не 0.0!
        i_ = 0.0;
        j_ = 0.0;
        level_ = level - 1.0;  // Уровень на 1 ниже
    } else {
        // Обычное число
        r_ = value;
        i_ = 0.0;
        j_ = 0.0;
        level_ = level;
    }
}

Почему так? Потому что в нашей системе:

  • 0 (классический ноль) представляется как 1 * ∞⁻¹

  • 1 (единица) представляется как 1 * ∞⁰

  •  (бесконечность) представляется как 1 * ∞¹

Таким образом, ноль — это не отсутствие значения, а значение на уровне -1!

Математические операторы: как работает магия

Давайте посмотрим на реализацию ключевых операций.

1. Сложение: работа с разными уровнями

Impl add(const Impl& other) const {
    // Быстрый путь для одинаковых уровней
    if (isApproxEqualLevel(level_, other.level_)) {
        Impl result;
        result.r_ = r_ + other.r_;
        result.i_ = i_ + other.i_;
        result.j_ = j_ + other.j_;
        result.level_ = level_;
        result.normalize();  // Важно: нормализуем результат!
        return result;
    }
    
    // Находим максимальный уровень
    const double max_level = std::max(level_, other.level_);
    
    // Если разница в уровнях больше 2, меньшими уровнями можно пренебречь
    if (max_level - std::min(level_, other.level_) > 2.5) {
        return (level_ > other.level_) ? *this : other;
    }
    
    // Суммируем значения на каждом уровне
    const double sum_r = atLevel(max_level) + other.atLevel(max_level);
    const double sum_i = atLevel(max_level - 1.0) + other.atLevel(max_level - 1.0);
    const double sum_j = atLevel(max_level - 2.0) + other.atLevel(max_level - 2.0);
    
    Impl result(sum_r, sum_i, sum_j, max_level);
    result.normalize();
    return result;
}

Пример работы сложения:

// 10 (уровень 0) + 1*∞ (уровень 1)
dspirit a(10.0);           // 10 * ∞⁰
dspirit b = dspirit::INF;  // 1 * ∞¹

dspirit c = a + b;
// Результат: 1 * ∞¹ (бесконечность "поглощает" конечное число)
// Но информация о 10 сохраняется в младших уровнях!

2. Умножение: складываем уровни

Impl multiply(const Impl& other) const {
    // Умножение: уровни складываются!
    const double result_level = level_ + other.level_;
    
    // Умножаем значения (как в полиномах)
    const double result_r = r_ * other.r_;
    const double result_i = r_ * other.i_ + i_ * other.r_;
    const double result_j = r_ * other.j_ + i_ * other.i_ + j_ * other.r_;
    
    Impl result(result_r, result_i, result_j, result_level);
    result.normalize();
    return result;
}

Математическая основа:
Если A = a ∞ᴸ и B = b ∞ᴹ, то: A B = (a b) * ∞ᴸ⁺ᴹ

3. Деление: вычитаем уровни

Impl divide(const Impl& divisor) const {
    // Деление: уровни вычитаются!
    const double result_level = level_ - divisor.level_;
    
    // Алгоритм аналогичен делению полиномов
    const double result_r = r_ / divisor.r_;
    const double result_i = (i_ - result_r * divisor.i_) / divisor.r_;
    const double result_j = ((j_ - result_r * divisor.j_) - result_i * divisor.i_) / divisor.r_;
    
    Impl result(result_r, result_i, result_j, result_level);
    result.normalize();
    return result;
}

Почему это работает для деления на ноль?

// Делим число на ноль:
dspirit x(42.0);      // 42 * ∞⁰
dspirit zero(0.0);    // 1 * ∞⁻¹

dspirit result = x / zero;
// Уровень результата: 0 - (-1) = 1
// Значение: 42 / 1 = 42
// Итог: 42 * ∞¹  (бесконечность, содержащая информацию о 42)

Нормализация: поддержание канонической формы

void normalize() {
    if (isApproxZero(r_)) {
        if (!isApproxZero(i_)) {
            // Сдвигаем значения вверх
            r_ = i_;
            i_ = j_;
            j_ = 0.0;
            level_ -= 1.0;  // Понижаем уровень
        } else if (!isApproxZero(j_)) {
            r_ = j_;
            i_ = 0.0;
            j_ = 0.0;
            level_ -= 2.0;
        } else {
            // Все нули - особый случай
            r_ = 1.0;
            i_ = 0.0;
            j_ = 0.0;
            level_ -= 1.0;
        }
        return;
    }
    resetLowerLevels();
}

Зачем нужна нормализация? Чтобы всегда иметь каноническое представление:

  • Старший уровень r_ никогда не равен нулю

  • Нули в младших уровнях явно обнуляются

  • Число всегда в наиболее компактной форме

Операторы сравнения: как сравнивать бесконечности

bool lessThan(const Impl& other) const {
    // Оба нуля
    if (isZero() && other.isZero()) return false;
    
    // Текущее - ноль, другое - нет
    if (isZero()) return other.isPositive();
    
    // Другое - ноль, текущее - нет
    if (other.isZero()) return isNegative();
    
    // Оба не нули - сравниваем уровни
    if (!isApproxEqualLevel(level_, other.level_)) {
        if (isPositive() && other.isPositive()) {
            return level_ < other.level_;  // Меньший уровень < большего
        }
        if (isNegative() && other.isNegative()) {
            return level_ > other.level_;  // Для отрицательных наоборот
        }
        return isNegative() && other.isPositive();
    }
    
    // Одинаковые уровни - сравниваем значения
    return r_ < other.r_;
}

Пример сравнения бесконечностей:

dspirit inf1 = dspirit::INF;           // 1 * ∞¹
dspirit inf2 = inf1 * inf1;            // 1 * ∞²

cout << (inf2 > inf1) << endl;         // true!
cout << (inf1 > 1000.0) << endl;       // true
cout << (0.0 > -inf1) << endl;         // true

Полный пример: цепочка операций

#include <iostream>
#include "paradox/spirit_double.h"

using namespace paradox;

void demonstrate_chain() {
    std::cout << "=== Цепочка операций с сохранением информации ===" << std::endl;
    
    // Исходное число
    dspirit x = 7.5;
    std::cout << "1. Исходное число: " << x.debugString() << std::endl;
    
    // Умножаем на ноль
    dspirit y = x * 0.0;
    std::cout << "2. После умножения на 0: " << y.debugString() << std::endl;
    std::cout << "   В классике: 0, у нас: " << y << std::endl;
    
    // Умножаем на бесконечность
    dspirit z = y * dspirit::INF;
    std::cout << "3. После умножения на INF: " << z.debugString() << std::endl;
    
    // Делим на бесконечность
    dspirit w = z / dspirit::INF;
    std::cout << "4. После деления на INF: " << w.debugString() << std::endl;
    
    // Делим на ноль
    dspirit v = w / 0.0;
    std::cout << "5. После деления на 0: " << v.debugString() << std::endl;
    
    // И восстанавливаем исходное!
    dspirit restored = v * 0.0 * dspirit::INF / dspirit::INF * 0.0;
    std::cout << "6. Восстановленное: " << restored.debugString() << std::endl;
    std::cout << "   Значение: " << restored << " (ожидалось 7.5)" << std::endl;
    
    if (std::abs(static_cast<double>(restored) - 7.5) < 1e-10) {
        std::cout << "✓ Информация полностью сохранена!" << std::endl;
    }
}

int main() {
    demonstrate_chain();
    return 0;
}

Интеграция с STL и алгоритмами

// dspirit можно использовать в контейнерах STL
#include <vector>
#include <algorithm>
#include <numeric>

void stl_integration() {
    std::vector<dspirit> numbers = {5.0, 0.0, -3.0, dspirit::INF, 2.5};
    
    // Сортировка работает!
    std::sort(numbers.begin(), numbers.end());
    
    std::cout << "Отсортированные числа:" << std::endl;
    for (const auto& n : numbers) {
        std::cout << n.debugString() << std::endl;
    }
    
    // Суммирование с аккумуляцией
    dspirit sum = std::accumulate(
        numbers.begin(), 
        numbers.end(), 
        dspirit::ZERO
    );
    
    std::cout << "\nСумма: " << sum.debugString() << std::endl;
    
    // Поиск максимального (учитывая бесконечности!)
    auto max_it = std::max_element(numbers.begin(), numbers.end());
    std::cout << "Максимум: " << max_it->debugString() << std::endl;
}

Производительность: под капотом

// dspirit использует идиому Pimpl (Pointer to implementation)
// Это даёт несколько преимуществ:

class dspirit {
private:
    class Impl;  // Объявление внутреннего класса
    Impl* pimpl; // Указатель на реализацию
    
public:
    // Небольшой размер (размер указателя)
    // Быстрое копирование (можно добавить copy-on-write)
    // Стабильный ABI (можно менять Impl без перекомпиляции клиентов)
    
    // Размеры:
    static_assert(sizeof(dspirit) == sizeof(void*), 
        "dspirit должен быть размером с указатель");
};

// При этом все данные хранятся в куче:
class dspirit::Impl {
    double r_, i_, j_;  // Три уровня
    double level_;      // Текущий уровень
    // Итого: 4 * double = 32 байта
};

Заключение технической части

Мы рассмотрели, как Paradox libraries реализует многомерные числа:

  1. Конструкторы создают мост между классическими и многомерными числами

  2. Ноль представляется как число на уровне -1, а не как отсутствие значения

  3. Арифметические операторы работают с учётом уровней бесконечности

  4. Нормализация поддерживает каноническую форму чисел

  5. Сравнения учитывают и уровни, и значения внутри уровней

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

Попробуйте в действии:

// Самый впечатляющий пример:
dspirit create_singularity(double value) {
    return value / 0.0 * 0.0 / 0.0 * 0.0 * dspirit::INF / dspirit::INF;
}

// Несмотря на все "опасные" операции,
// информация о value не теряется!

Где это можно применять?

  1. Научные расчёты — физика, инженерия, там где встречаются сингулярности

  2. Машинное обучение — обработка выбросов, работа с разреженными данными

  3. Финансовое моделирование — расчёты с нулевыми ставками, бесконечными горизонтами планирования

  4. Компьютерная графика — обработка перспективы, камеры, работа с бесконечно удалёнными объектами

  5. Игровые движки — физика, коллизии, генерация бесконечных миров

Попробуйте сами!

Библиотека доступна на GitHub: https://github.com/Dydya-Vasya/paradox.

В репозитории вы найдёте:

  • Полную документацию API

  • Примеры использования

  • Юнит-тесты для проверки корректности

  • CMake-файлы для лёгкой интеграции

Что дальше?

Эта реализация — только начало. В планах:

  • Поддержка комплексных многомерных чисел

  • Векторизованные операции (SIMD)

  • Интеграция с библиотеками линейной алгебры

  • Реализация на других языках (Python, Rust, JavaScript)

Присоединяйтесь к разработке! Если идея вас заинтересовала:

  • Ставьте звёзды на GitHub

  • Пробуйте в своих проектах

  • Сообщайте об ошибках и предлагайте улучшения

  • Пишите свои статьи и исследования на основе библиотеки

Вопрос к читателям: В какой области вы бы попробовали применить эту технологию? Делитесь идеями в комментариях!

P.S. Помнитетот пример с линейкой в начале статьи? Теперь у вас есть не просто линейка, а телескоп, который позволяет заглянуть за её край, и микроскоп, чтобы рассмотреть, что происходит в самой точке «ноль». И всё это — в привычном мире double‑чисел вашего процессора.

Комментарии (44)


  1. cpud47
    05.01.2026 16:25

    Подход типичный, но он не работает.

    Вы говорите, что у Вас обычный 0 представляется как 1/A. Но тогда возникает вопрос: чему равно 1 - 1, или A - A. Предположу, что A^-1 и A^0 соответственно.

    Но тогда:

    \frac{42A^{-2} + 1 - 1}{A^{-2}} = A

    Что очевидно глупость. И я уже не говорю про2-2...

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

    \frac{\sqrt{1 + xA^{-10}} - 1}{A^{-10}}

    Я ожидаю увидеть в ответе\frac12 x, но Ваша библиотека выдаст что-то другое.

    Ну и в целом, в любой адекватной числовой системе0необратим — иначе мы потеряем дистрибутивность/ассоциативность. А без дистрибутивности/ассоциативность никакие числа не нужны... (Ну ладно флоаты как-то живут — но разве это жизнь)


    1. Dyadya_Vasya0 Автор
      05.01.2026 16:25

      Да, точно, спасибо за внимательность! Надо исправить и первое и второе замечание совершенно верны.


      1. cpud47
        05.01.2026 16:25

        Как уже сказал, это нельзя исправить


        1. Dyadya_Vasya0 Автор
          05.01.2026 16:25

          1 можно попробовать ввести абсолютный ноль(как я этого не хотел), видимо без него не обойтись.
          2) для второго можно не отсекать уровни, хранить как полином до n-уровня, правда это замедлит всё..
          Как думаете?


          1. cpud47
            05.01.2026 16:25

            Чему равен\log \mathbb A?

            Edit: или даже проще:\sqrt{x + y \mathbb A}?


            1. Dyadya_Vasya0 Автор
              05.01.2026 16:25

              1) Отличный вопрос! "A" это не число, даже не очень большое число, это что-то где-то в бесконечности, поэтому в этой системе log(A) подразумевается таким же как log(∞) в классической системе , но какой ∞ точнее A будет, логарифмирование и извлечение корней пока не реализовывал.
              2) Но вот по корням второй степени из А первой степени, как частного случая появления дробного корня, у меня было два варианта развития развития ситуации, введение степеней с плавающей точкой, но сейчас склоняюсь к тому что через static переменную фиксировать то в какую степень возводили и какую извлекали числа, ведь по логике А это общий ориентир для всей модели.. а корень любой(конечной) степени из бесконечности это бесконечность, тут надо ещё подумать и поэкспериментировать..


              1. cpud47
                05.01.2026 16:25

                Так не выйдет. Например для любогоnверно

                1 + \frac{A \log^n A}{A^2} = 1 + \epsilon

                Где\epsilonкакая-то величина меньшая по порядку чемA^0.

                То есть, если\log A = A^\delta, то достаточно взятьn \ge \frac2\deltaи "нормальная" логика сломается.

                Ну и Вы не ответили на вопрос с корнем. Ну или даже ещё проще: чему равно

                \frac1{1 + A}

                ?


                1. Dyadya_Vasya0 Автор
                  05.01.2026 16:25

                  Да вы абсолютно правы, пока в текущей системе нельзя корректно определить log(A)я думаю реальный и честный вариант пока, это ограничить его использование в пределах регулярных чисел, с корнем ответил выше


                1. Dyadya_Vasya0 Автор
                  05.01.2026 16:25

                  \frac1{1 + A}

                  в этой реализации это будет 1/(A + 1) = 1×A⁻¹ - 1×A⁻² + 1×A⁻³ или 0 в обычной системе.


                  1. cpud47
                    05.01.2026 16:25

                    Забыли +1.

                    Такой результат начнёт врать если к этому выражению прибавить полином 3-го порядка — так называемое "катастрофическое сокращение"


                    1. Dyadya_Vasya0 Автор
                      05.01.2026 16:25

                      Не понял про +1 и про "катастрофическое сокращение" тоже не понял, можно пояснить?


                      1. cpud47
                        05.01.2026 16:25

                        Если мы из

                        \frac1{1+A}

                        Вычтем

                         1 - A + A^{-2} - A^{-3} - 42A^{-4}

                        То хотелось бы получить

                        43A^{-4}

                        А не 0.


                      1. Dyadya_Vasya0 Автор
                        05.01.2026 16:25

                        если правильно, то получим -42A(-4) а хотелось бы 43) эмулировать бесконечный ряды тоже можно но нужно ли.. если и то и другое для конечного пользователя это 0 например..


                      1. cpud47
                        05.01.2026 16:25

                        Ну, можно потом результат разделить наA^{-4}и уже будет не 0. В работе с бесконечностями всегда можно прощупать скольугодно малые колебания.


                    1. Dyadya_Vasya0 Автор
                      05.01.2026 16:25

                      В данной системе катастрофического сокращения не может быть, тут "A" - не число, числа на разных уровнях не могут суммироваться но про +1 всё равно не понял)


                      1. cpud47
                        05.01.2026 16:25

                        Так я их и не вычитаю. Вопрос в том, что у Вас не хранится информация о коэффициенте приA^{-4}. Поэтому при вычитании разных чисел может получится 0 — это и называется "катастрофическое сокращение" (не в смысле IEEE 754, а в обобщённом смысле, если хотите).

                        Перечитайте ещё раз чему равна дробь. У Вас получается, что 1/1 = 0. Там член прогрессии пропустили


                      1. Dyadya_Vasya0 Автор
                        05.01.2026 16:25

                        нет я ничего не пропустил, 1/(A + 1)  это 1/(1 + ∞ ) это 1×A⁻¹ - 1×A⁻² + 1×A⁻³ в предложенной системе 0 в обычной..


                      1. cpud47
                        05.01.2026 16:25

                        А, действительно. Это я перепутал. Ну тогда в выкладках выше нужно немного поправить вычитаемый многочлен.

                        P.S. обычно определяют не "бесконечность", а "бесконечномалую" — впрочем это двойственные понятия.


              1. cpud47
                05.01.2026 16:25

                Так корень же может быть как снаружи так и внутри. Например, чему равно:

                \sqrt{\sqrt{1 - xA} - 1 - \frac12 x A}

                Я Вам могу ещё долго таких "каверзных" примеров накидывать.

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

                Ввиду своих ограничений данные подходы тяжело сделать общеприменимыми. Поэтому живут либо на флоатах, либо вообще избегают вещественных чисел.

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


                1. Dyadya_Vasya0 Автор
                  05.01.2026 16:25

                  Я понял, за "каверзными" примерами буду к Вам бежать, за это отдельное спасибо. В конце концов на нерешаемые вопросы всегда можно выкинуть исключение, но попробовать решить тоже можно)


                  1. cpud47
                    05.01.2026 16:25

                    Вернуть NaN всегда можно, да. Но тогда зачем всё это? Чем обычные флоаты не угодили :)

                    Попробуйте сформулировать задачу, которую Ваша библиотека пытается решить. Я пока не очень понимаю её скоуп/применимость.


                    1. Dyadya_Vasya0 Автор
                      05.01.2026 16:25

                      А ну вот) конкретно мне понравилась идея чтобы в расчётах сложнозамкнутых произвольно коммутируемых сетей не перестраивать при каждой коммутации граф, а просто заменит 0 на ∞  и наоборот... конечно у меня там нет необходимости в логарифмах и вложенных корней произвольной размерности, поэтому всё работает даже на одном слое..


                      1. cpud47
                        05.01.2026 16:25

                        А, ну тогда Вы придумали (гипер)дуальные числа.

                        Впрочем идея может и красивая, но перестраивать граф, скорее всего, гораздо эффективнее. Хотя зависит от деталей задачи.


                      1. Dyadya_Vasya0 Автор
                        05.01.2026 16:25

                        я находил, что это альтернативный анализ с манадами и тп


                      1. cpud47
                        05.01.2026 16:25

                        Не совсем. Это чисто вычислительный трюк, чтобы работать с бесконечномалыми на компьютере.

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

                        Гипердуальные числа есть просто обобщение на другие степени. Например, можете рассматривать числа вида:

                        x_1 + x_2 d + x_3 A

                        Где d — означает бесконечномалую, а A — плюс бесконечность. Дальше осталось ввести только таблицу умножения, например:

                        A^2 = A \quad d^2 = 0 \quad Ad = 1

                        Тогда в определённых пределах такие числа будут давать корректные результаты. А если заменитьA^2на NaN/исключение, то она даже будет предсказуемой.

                        Подразумевается, разумеется, что данные числа определены с точностью доo(d). Можно также хранить признак, является ли число "точным", или же там есть o-малое. Тогда можно будет отличать ситуации деления на 0.

                        Tl;Dr; Если не замахиваться на универсальность, можно достичь хороших результатов с гораздо более простым представлением чисел (и для него будет проще определить границы применимости)


                  1. rukhi7
                    05.01.2026 16:25

                    вот здесь есть не только каверзный пример (из моей статьи маленько на другую тему), но и имеющий большое практическое значение, потому как LDPC коды много где применяются. Я как раз не проанализировал до конца +-бесконечности в LLR-ах, потому как заработало и без этого.

                    Я к тому что вряд ли выражение бесконечности и нуля будет казаться вам большой проблемой когда вы столкнетесь с алгоритмом уровня LDPC декодера.


                    1. Dyadya_Vasya0 Автор
                      05.01.2026 16:25

                      Возможно Вы правы, но изобретать велосипед нам никто не может запретить))


    1. funca
      05.01.2026 16:25

      Подход типичный, но он не работает

      Какие-то пустяки на самом деле. Весь современный www держится на технологии, где в теории все сломано. Но он работает.

      Скрытый текст

      Не знаю зачем автор выбрал C++. Многомерную математику нужно сразу писать на JavaScript. /s


      1. cpud47
        05.01.2026 16:25

        Так на практике и флоаты работают. Зачем тогда подход автора?/s


      1. Dyadya_Vasya0 Автор
        05.01.2026 16:25

        Спасибо)


  1. black_warlock_iv
    05.01.2026 16:25

    Проблема, которая решается, неясна. Какой бы результат ни приписать операции деления на ноль, это не сделает это деление осмысленным.


    1. Dyadya_Vasya0 Автор
      05.01.2026 16:25

      Проблему которую решал я, связана с эмулированием поведения коммутируемых сложнозамкнутых сетей, мне показалось занятным имитировать коммутации путём замены нуля на бесконечность и обратно, а не перестройки всего графа. По поводу бессмысленности деления на ноль, тоже иногда так думаю, но Эйлер, Коши, Ньютон и другие уважаемые люди с нами бы не согласились.


  1. kajdarov
    05.01.2026 16:25

    Пишите "о" в слове "ноль", там где ударение на первый слог и "у" там, где нет ударения: "нулём", "нулевой", и никогда не ошибётесь. Исключение: выражение "подстричь под нуль"


    1. Dyadya_Vasya0 Автор
      05.01.2026 16:25

      Благодарю!


  1. Jijiki
    05.01.2026 16:25

    мне кажется лучше не делить на 0 всё таки, это безопасно, я последнее время думаю 0 это начало координат для единичных отрезков


  1. Dyadya_Vasya0 Автор
    05.01.2026 16:25

    Ну я всё таки пока склоняюсь к тому что можно делить, хотя под руководством чётких правил, поэтому и появилась попытка родить в опенсорсе библиотеку для этого..


  1. frostsumonner
    05.01.2026 16:25

    Решили 1 проблему - создали миллион. Ваши числа даже сложить нельзя... не говоря о log и exp


    1. Dyadya_Vasya0 Автор
      05.01.2026 16:25

      Приведите пожалуйста пример, что не получилось сложить? В области регулярных чисел всё должно работать и с log и exp. если есть примеры приведите их пожалуйста


      1. cpud47
        05.01.2026 16:25

        В области регулярных чисел всё должно работать и с log и exp

        Кстати об этом. Чему равно\exp(10000)? Это уже из области реализации, но вопрос в том, как Ваши числа взаимодействуют с флоатами


        1. Dyadya_Vasya0 Автор
          05.01.2026 16:25

          Преобразование многоуровневых чисел в стандартный флоат: если число находится на нулевом уровне, то возвращается флоат(double) старшего члена, если уровень выше ноля, то STL-евский INF или -INF в зависимости от знака старшего члена, если же, уровень ниже ноля, то double 0. Математические функции: log, exp и другие, используют STL реализацию с предварительным приведением к флоату, для тригонометрических функций выкидывается исключение для бесконечного аргумента.


          1. cpud47
            05.01.2026 16:25

            Тут опять же нарушается логика. Например,

            \exp(2x) - \exp(x) = 0

            Для достаточно большихx- например дляx = 10000.

            Вообще, Вы сейчас пытаетесь на скорую руку залатать концепцию. Так ничего хорошего не выйдет.

            По хорошему, Вам нужно сначала сформулировать какими свойствами должны обладать Ваши операции. В идеале, хочется что-то типа аксиом поля. Но честного поля у Вас не получится, т.к. флоаты уже им не удовлетворяют. Но можно строить более слабые аналоги: например можно затребовать чтобыd((x + y) + z, x + (y + z)) < \epsilon(x, y, z)для какого-то разумного выбора функции\epsilonи для любыхx, y, zиз какого-то достаточно большого множества. И так с остальными аксимомами.

            Дальше нужно посмотреть а следует ли из заданных аксиом ожидаемое поведение. Посмотреть на практические задачи и как в них себя ведут эти аксиомы.

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

            И вот эти вот аксиомы/теоремы - это неотъемлимая часть документации. Именно их нужно выписывать в статье. Без них пользоваться библиотекой/подходом невозможно. Просто потому что никогда не знаешь, когда он начнёт врать =/


    1. Dyadya_Vasya0 Автор
      05.01.2026 16:25

      Поймите меня правильно, без конкретных примеров трудно решать проблему, это всё таки Opensource библиотека, и пока, я один в неё вовлечён, для того чтоб найти "Ваши числа даже сложить нельзя... " уйдут годы. Конкретно мои числа все складываются без ошибок. Многоуважаемый @cpud47, дал хоть и спорные, но развёрнутые и чёткие замечания, настолько чёткие, что ему можно смело присвоить соавтора, у Вас пока не понятное замечание, больше похожее на плевок..


      1. cpud47
        05.01.2026 16:25

        Ваши числа даже сложить нельзя

        Да вроде всё тот же пример:1 + (-1). У Вас в статье всё ещё не отражено наличие нуля.


        1. Dyadya_Vasya0 Автор
          05.01.2026 16:25

          Добрый день, в репозитории я разместил код с супер нулём, статью пока не исправлял, потому что есть некоторые сомнения и предположения. Хочу отметить, что в пределах регулярных чисел, в том числе и в приведённом вами примере: 1 + (-1) работает и работало так как ожидается, раньше это был бы 1*А^(-1), то есть 0. Не работало, как вы правильно заметили ранее, на уровнях 1 и выше, появлялся артефакт на нулевом уровне в этом примере: 1/0 - 1/0 = 1