При разработке сложных вычислительных систем в среде 1С:Предприятие разработчики часто сталкиваются с ограничением типа Число. Стандартная разрядность в 32 знака кажется достаточной, однако при работе с очень малыми величинами (например, в научных расчетах или специфических финансовых операциях) возникают погрешности. Проблема усугубляется тем, что при промежуточных вычислениях платформа может использовать аппаратную логику чисел с плавающей запятой (стандарт IEEE 754), что порождает «хвосты» вроде 0.0000119999999999999988 вместо ожидаемого точного значения.
В этой статье мы подробно разберем, как обойти эти ограничения, рассмотрим различные способы хранения таких данных и выясним, как правильно организовать работу с ними на формах и в программном коде.
Прежде всего, проанализируем ситуацию: почему обычный реквизит типа Число не всегда подходит? В базе данных 1С числовые значения хранятся с фиксированной точностью, которую мы задаем в конфигураторе. Если число знаков после запятой превышает установленный лимит, платформа просто отсечет лишнее. Кроме того, двоичное представление десятичных дробей в оперативной памяти компьютера часто бывает неточным, что и приводит к появлению лишних девяток или восьмерок в конце числа.
Самый простой и надежный способ сохранить число любой длины без искажений — использовать реквизит с типом Строка (желательно неограниченной длины, если точность заранее неизвестна). Рассмотрим этот подход подробнее.
Преимущества:
Для реализации этого метода нам потребуется выполнять преобразования типов перед выполнением арифметических операций. Разберем пример кода для расчета:
// Получаем строковое значение из реквизита
СтрокаЧисла = Объект.ДлинноеЧислоСтрокой;
// Преобразуем в число для простых вычислений (с учетом лимита 32 знака)
ЗначениеДляРасчета = Число(СтрокаЧисла);
// Выполняем математическую операцию
Результат = ЗначениеДляРасчета * 1.05;
// Записываем результат обратно, предварительно преобразовав в строку
Объект.ДлинноеЧислоСтрокой = Формат(Результат, "ЧГ=0");
Важно помнить: если результат вычисления превышает 32 знака, стандартная функция Число() все равно приведет к потере точности. В таких случаях нужно использовать методы «длинной арифметики».
Если точность ваших чисел велика, но ограничена определенным количеством знаков (например, всегда 20 знаков после запятой), мы можем применить метод масштабирования. Суть заключается в том, чтобы умножить число на 10 в нужной степени и хранить его как целое.
Проанализируем ситуацию на примере числа 0.00001199.... Если мы умножим его на 10²⁰, мы получим целое число, которое 1С сохранит без искажений. Перед выводом пользователю или перед использованием в формуле мы будем делить его обратно на тот же коэффициент.
Этот способ заимствован из представления чисел с плавающей запятой в информатике. Мы можем создать два реквизита:
НормализованноеЧисло (тип Число) — мантисса (значимая часть).СтепеньДесяти (тип Число) — порядок (показатель степени).Рассмотрим, как это выглядит на практике. Число 0.00001199 можно представить как 1.199, умноженное на 10 в степени -5. При расчетах мы будем оперировать этими двумя составляющими отдельно. Для пользователя на форме можно программно собирать эти данные в одну красивую строку.
Если требуется хранить не просто число, а сложную структуру данных с расчетами, идеально подойдет тип ХранилищеЗначения. Мы можем упаковать в него структуру, массив или даже таблицу значений.
// Упаковка данных
ДанныеДляХранения = Новый Структура;
ДанныеДляХранения.Вставить("Значение", "0.0000119999999999999988");
ДанныеДляХранения.Вставить("Точность", 22);
Объект.ДанныеРасчета = Новый ХранилищеЗначения(ДанныеДляХранения);
// Извлечение данных
ПолученныеДанные = Объект.ДанныеРасчета.Получить();
Если ПолученныеДанные <> Неопределено Тогда
Сообщить(ПолученныеДанные.Значение);
КонецЕсли;
При работе с такими числами на форме справочника или документа стандартное поле ввода может подвести. Выясним, почему это происходит: у поля ввода есть маски и формат редактирования. Если в конфигураторе для поля не задана огромная точность, визуально число будет округлено, даже если в базе оно лежит правильное.
Рекомендации по настройке интерфейса:
Строка для элемента формы (поля ввода).ПриИзменении реализуйте программную проверку того, что пользователь ввел именно число (используя регулярные выражения или попытку преобразования).Формат() с явным указанием количества знаков после запятой в параметре ЧДЦ.Если стандартных средств 1С (даже при хранении в строках) недостаточно для выполнения математических операций без погрешностей, можно обратиться к внешним библиотекам. Посмотрим на наиболее популярные варианты:
System.Decimal можно производить расчеты с гораздо более высокой точностью, чем позволяет стандартный тип Double.MSScriptControl.ScriptControl позволяет передать вычисление в среду VBScript или JScript, где механизмы работы с памятью могут отличаться.Подводя итог, отметим: выбор метода зависит от того, нужно ли вам просто сохранить число «как есть» для красоты, или же на его основе будут строиться критически важные расчеты. Для большинства бизнес-задач оптимальным является комбинированный метод: хранение в строковом реквизите и использование специализированных функций для вычислений.