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

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

При разработке сложных вычислительных систем в среде 1С:Предприятие разработчики часто сталкиваются с ограничением типа Число. Стандартная разрядность в 32 знака кажется достаточной, однако при работе с очень малыми величинами (например, в научных расчетах или специфических финансовых операциях) возникают погрешности. Проблема усугубляется тем, что при промежуточных вычислениях платформа может использовать аппаратную логику чисел с плавающей запятой (стандарт IEEE 754), что порождает «хвосты» вроде 0.0000119999999999999988 вместо ожидаемого точного значения.

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

Причина возникновения проблемы

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

Решение 1: Хранение в виде строки (универсальный метод)

Самый простой и надежный способ сохранить число любой длины без искажений — использовать реквизит с типом Строка (желательно неограниченной длины, если точность заранее неизвестна). Рассмотрим этот подход подробнее.

Преимущества:

  1. Отсутствие автоматического округления платформой.
  2. Возможность хранить любое количество знаков после запятой.
  3. Удобство отображения пользователю на форме.

Для реализации этого метода нам потребуется выполнять преобразования типов перед выполнением арифметических операций. Разберем пример кода для расчета:


// Получаем строковое значение из реквизита
СтрокаЧисла = Объект.ДлинноеЧислоСтрокой; 

// Преобразуем в число для простых вычислений (с учетом лимита 32 знака)
ЗначениеДляРасчета = Число(СтрокаЧисла);

// Выполняем математическую операцию
Результат = ЗначениеДляРасчета * 1.05;

// Записываем результат обратно, предварительно преобразовав в строку
Объект.ДлинноеЧислоСтрокой = Формат(Результат, "ЧГ=0");

Важно помнить: если результат вычисления превышает 32 знака, стандартная функция Число() все равно приведет к потере точности. В таких случаях нужно использовать методы «длинной арифметики».

Решение 2: Масштабирование (целочисленное хранение)

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

Проанализируем ситуацию на примере числа 0.00001199.... Если мы умножим его на 10²⁰, мы получим целое число, которое 1С сохранит без искажений. Перед выводом пользователю или перед использованием в формуле мы будем делить его обратно на тот же коэффициент.

Решение 3: Раздельное хранение мантиссы и порядка

Этот способ заимствован из представления чисел с плавающей запятой в информатике. Мы можем создать два реквизита:

  1. НормализованноеЧисло (тип Число) — мантисса (значимая часть).
  2. СтепеньДесяти (тип Число) — порядок (показатель степени).

Рассмотрим, как это выглядит на практике. Число 0.00001199 можно представить как 1.199, умноженное на 10 в степени -5. При расчетах мы будем оперировать этими двумя составляющими отдельно. Для пользователя на форме можно программно собирать эти данные в одну красивую строку.

Решение 4: Использование ХранилищаЗначения

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


// Упаковка данных
ДанныеДляХранения = Новый Структура;
ДанныеДляХранения.Вставить("Значение", "0.0000119999999999999988");
ДанныеДляХранения.Вставить("Точность", 22);

Объект.ДанныеРасчета = Новый ХранилищеЗначения(ДанныеДляХранения);

// Извлечение данных
ПолученныеДанные = Объект.ДанныеРасчета.Получить();
Если ПолученныеДанные <> Неопределено Тогда
    Сообщить(ПолученныеДанные.Значение);
КонецЕсли;

Особенности работы на форме

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

Рекомендации по настройке интерфейса:

Использование внешних инструментов для сверхточных расчетов

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

  1. COM-объект .NET: Через System.Decimal можно производить расчеты с гораздо более высокой точностью, чем позволяет стандартный тип Double.
  2. Скриптовые движки: Использование MSScriptControl.ScriptControl позволяет передать вычисление в среду VBScript или JScript, где механизмы работы с памятью могут отличаться.
  3. Длинная арифметика на 1С: Можно написать (или найти готовую) функцию, которая складывает и умножает числа «в столбик», работая с ними как со строками. Это медленнее, но исключает любые ошибки округления 1С.

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

← На главную