09 апреля 2025

🧮 Округление в Power BI: как не попасть в ловушку

Data Analyst / BI Dev / SQL Dev Senior developer at USETECH Telegram: @aleksandripatov
Твой отчет показывает разные цифры при одинаковой логике? Не спеши винить систему – это классический кейс с округлением в Power BI. Разбираемся, как типы данных влияют на точность и почему Currency может стать твоим врагом.
🧮 Округление в Power BI: как не попасть в ловушку

Всем привет! Я – Ипатов Александр, старший разработчик компании USETECH. Сегодня рассмотрим вопрос округления в Power BI, которое может привести к неочевидной разнице результатов при различной реализации в DAX.

В мире бизнес-аналитики точность расчетов имеет критическое значение. Однако даже в такой мощной системе, как Power BI, пользователи могут столкнуться с неожиданными расхождениями в цифрах. Эти различия часто обусловлены особенностями округления при работе с разными типами данных. Проблема становится особенно заметной при работе с финансовыми показателями, где каждая копейка на счету.

Округление – это не просто техническая особенность системы, а фундаментальный аспект компьютерной арифметики. В Power BI и DAX оно проявляется особенно ярко из-за:

  1. Разных типов данных (Currency, Decimal, Integer).
  2. Особенностей вычислений в столбцах и мерах.
  3. Различий в агрегации данных.

Хотя разницы в округлении в Power BI встречаются нечасто, но когда они возникают, пользователи обычно удивляются и разочаровываются.

Рассмотрим такой пример: расчет премий в зависимости от результатов.

Рассмотрим две реализации одной и той же бизнес–логики: мера [Премия] вычисляет 0,1% от продаж в рабочие дни и 0,2% от продаж в нерабочие. [Сумма продаж] для каждой транзакции рассчитывается как произведение ‘Продажи’[Количество] на ‘Продажи’[Стоимость].

Две меры [Премия] и [Премия v2] – реализуют одну логику, но разными способами:

Премия :=

SUMX (

‘Продажи’,

VAR Amt = ‘Продажи’[Количество] * ‘Продажи’[Стоимость]

VAR Pct = IF ( RELATED ( 'Календарь'[Рабочий день] ) = 1, 0.001, 0.002 )

RETURN

Amt * Pct

)

[Премия] применяет округление на уровне каждой транзакции.

Сумма продаж :=

SUMX ( ‘Продажи’, ‘Продажи’[Количество] * ‘Продажи’[Стоимость] )

Премия v2 :=

CALCULATE ( [Сумма продаж], 'Календарь'[Рабочий день] = 1 ) * .001

+

CALCULATE ( [Сумма продаж], 'Календарь'[Рабочий день] = 0 ) * .002

[Премия v2] сначала суммирует продажи, а затем применяет процент.

Результаты немного различаются:

разница в результатах между мерами
разница в результатах между мерами

[Премия] : 544 035,41

[Премия v2] : 544 035,62

Разница: 0,21 (0,00004%).

Честный разбор подводных камней при построении DWH и практические советы по их преодолению. История о том, как превратить хаос данных в работающую бизнес-аналитику.

Почему так происходит? Причина кроется в типах данных

Столбец ‘Продажи’[Стоимость] имеет тип Десятичное число с фиксированной запятойDAXCurrency). Этот тип хранит числа с фиксированной точностью до 4 знаков после запятой (0,0001). При умножении 0,01 (минимальный шаг цены) на 0,001 (ставка бонуса) получаем 0,00001 – значение, которое не может быть точно представлено в этом формате

Умножение ‘Продажи’[Количество] (Целое число) на ‘Продажи’[Стоимость] (Currency) дает результат типа Currency.

Затем это значение умножается на 0,001 или 0,002 (тип Decimal).

По правилам DAX, умножение Currency на Decimal возвращает Currency, что приводит к округлению до 4 знаков после запятой. Поскольку ‘Продажи’[Стоимость] имеет точность 0,01, умножение на 0,001 дает 0,00001, что выходит за пределы точности Currency. В результате округление происходит на уровне каждой транзакции (в таблице более 100 тысяч записей), и накопленная погрешность становится заметной.

Какой результат правильный?

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

Другими словами: если нужно округлять каждую транзакцию – то верен [Премия], если требуется точный расчет без промежуточного округления, то [Премия v2] ближе к истине.

Как избежать различий?

1. Преобразование в Decimal перед умножением

Можно явно преобразовать промежуточный результат в Decimal, чтобы избежать округления:

Премия :=

SUMX (

‘Продажи’,

VAR Amt = ‘Продажи’[Количество] * ‘Продажи’[Стоимость]

VAR Pct = IF ( RELATED ( 'Календарь'[Рабочий день] ) = 1, 0.001, 0.002 )

RETURN

CONVERT ( Amt, DOUBLE ) * Pct

)

одинаковые результаты между мерами
одинаковые результаты между мерами

Тогда обе меры будут иметь один и тот же результат вычисления.

2. Использование для цен / стоимости типа «Десятичное число (с плавающей запятой)»

Если изменить тип ‘Продажи’[Стоимость] на Десятичное число, умножение сохранит плавающую точность, и результаты обеих мер, опять же, совпадут.

Практические рекомендации

Когда использовать Currency / Fixed Decimal (Десятичное число с фиксированной запятой):

  • Финансовые отчеты, где важно соответствие бухгалтерским документам.
  • Системы, работающие с валютами (деньги всегда имеют фиксированный формат).
  • Большие объемы данных, где важна производительность.

Когда предпочесть Decimal (Десятичное число):

  • Научные и инженерные расчеты.
  • Cложные математические операции (особенно умножение/деление).
  • Когда нужна максимальная точность без промежуточного округления.

Абсолютная точность vs практическая необходимость:

В реальном бизнесе часто приходится балансировать между:

  • Математической точностью
  • Требованиями нормативных документов
  • Производительностью системы
  • Ожиданиями пользователей

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

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека программиста»

Выводы

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

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

2. Типы данных в DAX критичны – Currency округляет промежуточные результаты, Decimal сохраняет точность.

3. Выбор подхода зависит от требований:

3.1. Если нужна точность до копеек на уровне транзакций – используйте Currency.

3.2. Если важна математическая точность – переходите на Decimal.

4. Проверяйте логику расчетов, особенно если сравниваете разные реализации одной формулы.

В большинстве случаев разница незначительна, но в финансовых моделях даже 0,001% может иметь значение. Всегда учитывайте возможные побочные эффекты округления при работе с DAX!

Комментарии

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ