Как в 1С хранить и обрабатывать числа с высокой точностью и длиной более 32 знаков

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При решении задач количественного учета в специфических сферах (например, учет криптовалют, микродозирование в химическом производстве или расчеты с микровеличинами) разработчики сталкиваются с необходимостью хранить и обрабатывать числа с точностью более 20 знаков после запятой, а также общей длиной, превышающей стандартные возможности платформы. Рассмотрим подробнее, с какими системными ограничениями 1С приходится иметь дело и как правильно организовать архитектуру базы данных для таких расчетов.

Ограничения платформы 1С при работе с числами

Разберем базовые технические рамки типа данных Число в 1С:Предприятии, которые важно учитывать при проектировании структур данных:

  1. Ограничение метаданных: максимальная совокупная длина числового реквизита, ресурса или реквизита табличной части составляет 32 знака (включая как целую, так и дробную часть). Например, можно задать формат длины 30 с точностью 20, однако задать число общей длиной более 32 символов в дереве метаданных платформа не позволит.
  2. Ограничения языка запросов: промежуточные и итоговые вычисления в запросах ограничены разрядностью в 37–38 знаков. При превышении этого лимита происходит автоматическое усечение дробной части (но не менее чем до 5 знаков) или возникает ошибка переполнения.
  3. Ограничения регистров накопления: ресурсом регистра накопления может быть исключительно тип Число. Платформа рассчитывает итоги и обороты на уровне СУБД стандартными числовыми операторами, поэтому использовать строковые данные для автоматического накопления остатков невозможно.

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

Способ 1. Переход на целочисленный учет в минимальных неделимых единицах

Если суммарная разрядность числа укладывается в 32 знака, но дробная часть содержит 15–20 знаков, наиболее надежным решением является переход на целочисленный учет. Посмотрим, как это устроено на практике.

Вместо хранения дробных величин учет ведется в минимальных неделимых квантах (сатоши, миллиграммы, микросекунды и т.п.). Все входящие значения умножаются на фиксированный масштабный коэффициент 10^N:

  1. В метаданных создаем реквизит или ресурс регистра накопления с типом Число(32, 0).
  2. Запись движений в регистры выполняется строго целыми числами без плавающей запятой, что исключает ошибки округления при группировках СУБД.
  3. Используем стандартные виртуальные таблицы остатков и оборотов регистров накопления.
  4. При выводе данных в пользовательский интерфейс или печатные формы выполняем форматирование целого числа обратно в дробное представление.

Посмотрим на пример функции для преобразования масштабированного целого числа в строковое представление с фиксированной точностью:


Функция ПреобразоватьЦелоеВСтрокуСДробью(ЗначениеЦелое, ТочностьДроби)
    СтрокаЧисла = Формат(ЗначениеЦелое, "ЧГ=0");
    Если СтрДлина(СтрокаЧисла) <= ТочностьДроби Тогда
        // Дополняем ведущими нулями дробную часть
        СтрокаЧисла = "0." + СтрЗаменить(Прав(Формат(0, "ЧЦ=" + Формат(ТочностьДроби - СтрДлина(СтрокаЧисла), "ЧГ=0")), ТочностьДроби - СтрДлина(СтрокаЧисла)), " ", "0") + СтрокаЧисла;
    Иначе
        ПозицияТочки = СтрДлина(СтрокаЧисла) - ТочностьДроби;
        СтрокаЧисла = Лев(СтрокаЧисла, ПозицияТочки) + "." + Сред(СтрокаЧисла, ПозицияТочки + 1);
    КонецЕсли;
    Возврат СтрокаЧисла;
КонецФункции

Способ 2. Введение коэффициентов и расчетов с кратностью

Рассмотрим подход, аналогичный учету курсов валют. Если целая или дробная часть числа слишком мала/велика, вводится дополнительный реквизит Кратность (например, 100, 1000, 1000000):

  1. В регистрах и документах хранятся два реквизита: базовое Количество (с точностью до 10–15 знаков) и целочисленная Кратность.
  2. Все математические операции в алгоритмах проводятся с учетом масштабного коэффициента.
  3. Этот способ позволяет оставаться в рамках стандартных числовых типов 1С без риска переполнения разрядной сетки.

Способ 3. Строковое хранение и длинная арифметика для чисел длиннее 32 знаков

Выясним, как действовать, если общая длина числа (целая часть + дробная часть) превышает 32 знака. Встроенных типов произвольной точности в платформе нет, поэтому стандартный числовой тип применить не удастся.

  1. Хранение данных: значения сохраняются в реквизитах с типом Строка неограниченной или фиксированной длины (например, Строка(100)).
  2. Отказ от регистров накопления: так как платформа не может суммировать строки на уровне СУБД, для хранения движений используются Регистры сведений.
  3. Выполнение операций: операции сложения, вычитания и умножения реализуются либо с помощью внешней компоненты (Native API / COM с поддержкой BigNumber/BigDecimal), либо программными алгоритмами поразрядной арифметики на встроенном языке 1С.
  4. Оптимизация остатков: чтобы не пересчитывать всю историю строковых движений с начала времен, создается вспомогательный регистр сведений — таблица срезов/снимков баланса на контрольные даты (например, на начало каждого месяца). Актуальный остаток рассчитывается как снимок на контрольную дату плюс программная сумма движений за последующий период.

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


Функция СложитьДлинныеЧисла(СтрокаА, СтрокаБ)
    ДлинаА = СтрДлина(СтрокаА);
    ДлинаБ = СтрДлина(СтрокаБ);
    МаксДлина = Макс(ДлинаА, ДлинаБ);
    
    Стр1 = Прав("0000000000000000000000000000000000000000" + СтрокаА, МаксДлина);
    Стр2 = Прав("0000000000000000000000000000000000000000" + СтрокаБ, МаксДлина);
    
    Результат = "";
    Перенос = 0;
    
    Для Индекс = 0 По МаксДлина - 1 Цикл
        Поз = МаксДлина - Индекс;
        Цифра1 = Число(Сред(Стр1, Поз, 1));
        Цифра2 = Число(Сред(Стр2, Поз, 1));
        
        Сумма = Цифра1 + Цифра2 + Перенос;
        Перенос = Цел(Сумма / 10);
        Результат = Формат(Сумма % 10, "ЧГ=0") + Результат;
    КонецЦикла;
    
    Если Перенос > 0 Тогда
        Результат = Формат(Перенос, "ЧГ=0") + Результат;
    КонецЕсли;
    
    Возврат Результат;
КонецФункции

Таким образом, выбор метода зависит от предельной разрядности: если число укладывается в 32 разряда, оптимально использовать целочисленный учет через Число(32, 0) в регистрах накопления. Если разрядность превышает 32 знака — следует использовать строковое хранение в регистрах сведений с механизмами длинной арифметики.

← На главную