Почему деление дает совершенно другой результат, чем умножение на дробь с плавающей запятой - PullRequest
4 голосов
/ 02 января 2011

Я понимаю, почему числа с плавающей запятой нельзя сравнивать, и знаю о мантиссе и двоичном представлении экспоненты, но я не эксперт, и сегодня я столкнулся с тем, чего не понимаю:

А именноДопустим, у вас есть что-то вроде:

float denominator, numerator, resultone, resulttwo;

resultone = numerator / denominator;

float buff = 1 / denominator;

resulttwo = numerator * buff;

Насколько мне известно, разные флопы могут давать разные результаты, и это не является необычным.Но в некоторых крайних случаях эти два результата кажутся совершенно разными.Чтобы быть более точным в моем GLSL-коде, вычисляющем распределение наклонов фасета Бекмана для модели Cook-Torrance lighitng:

float a = 1 / (facetSlopeRMS * facetSlopeRMS * pow(clampedCosHalfNormal, 4));
float b = clampedCosHalfNormal * clampedCosHalfNormal - 1.0;
float c = facetSlopeRMS * facetSlopeRMS * clampedCosHalfNormal * clampedCosHalfNormal;

facetSlopeDistribution = a * exp(b/c);

дает очень разные результаты для

float a = (facetSlopeRMS * facetSlopeRMS * pow(clampedCosHalfNormal, 4));
facetDlopeDistribution = exp(b/c) / a;

Почему это так?Вторая форма выражения проблематична.

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

1 Ответ

6 голосов
/ 02 января 2011

Я не подробно изучил вашу математику, но вы должны знать, что мелкие ошибки легко накачиваются всеми этими степенями и показателями.Вы должны попытаться заменить все переменные var на var + e(var) (на бумаге, да) и получить выражение для общей ошибки - без упрощения между этапами, потому что именно отсюда и возникает ошибка!

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

edit: уточнить пример

Скажем, у вас есть некоторая переменная x и выражениеy=exp(x).Ошибка в x обозначается e(x) и является небольшой по сравнению с x (скажем, e(x)/x < 0.0001, но обратите внимание, что это зависит от используемого вами типа).Тогда вы могли бы сказать, что

e(y) = y(x+e(x)) - y(x)
e(y) ~ dy/dx * e(x)   (for small e(x))
e(y) = exp(x) * e(x)

Так что увеличение абсолютной погрешности составляет exp(x), что означает, что около x=0 действительно нет проблем (не удивительно, поскольку в этот момент наклон exp(x) равно значению x), но для больших x вы заметите это.

Относительная ошибка тогда будет

e(y)/y = e(y)/exp(x) = e(x)

, тогда как относительная ошибка в xбыло

e(x)/x

, поэтому вы добавили коэффициент x к относительной ошибке.

...