Округление вещественных чисел вблизи начала координат приводит к появлению артефактов вращения

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

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

Если центр равен 0,0 и переводится на 0,9 в любом направлении, он все равно равен 0 при округлении

short(+0.9) == 0
short(-0.9) == 0

однако если центр равен 1,0 и переводится на 0,9 в любом направлении, то

short(+0.1) == 0
short(+1.9) == 1

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

Мой вопрос: есть ли способ избежать этой ошибки округления без перевода в положительное пространство?

0

Решение

Кажется, вам просто нужно использовать floor функция:

(short)floor(0.9) = 0
(short)floor(-0.9) = -1
4

Другие решения

Таким образом, очевидный ответ заключается в использовании floor функция. И это хороший ответ, он решит вашу проблему.

Это оставляет вас с проблемой, которая (1.0/3.0)*3.0 != 3.0 в IEEE математика с плавающей точкой. По факту, static_cast<short>(floor((1.0/3.0)*3.0)) == 2,

Вы, вероятно, хотите добавить эпсилон к своим значениям перед вызовом floor, И вы, вероятно, не хотите использовать приведение в стиле C, потому что есть одна законная причина использовать приведение в стиле C (Google "do not use C-style casts" чтобы узнать больше), и этот странный.

Итак, вы хотите что-то вроде этого:

short smart_round( double d, double epsilon=0.00001 ) {
short retval = static_cast<short>(floor( d + epsilon ) );
return retval;
}

который включает в себя epsilonделает static_castи использует floor в противном случае округлить вниз (вместо поведения по умолчанию C / C ++ «округлить до нуля»).

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector