Точность вычисления чисел с плавающей запятой: деление против умножения

Я наткнулся на эту реализацию векторного / скалярного деления:

public static Vector2 operator /(Vector2 value1, float divider)
{
    float factor = 1 / divider;
    value1.X *= factor;
    value1.Y *= factor;
    return value1;
}

Я пробовал реализовать это с помощью простого деления:

public static Vector2 operator /(Vector2 value1, float divider)
{
    return new Vector2(value1.X / divider, value1.Y / divider);
}

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

Это какой-то трюк для повышения точности вычислений?


person Den    schedule 26.06.2014    source источник
comment
Какие бывают разные результаты?   -  person Liam McInroy    schedule 27.06.2014
comment
Результат не будет правильно округлен, но часто ускорение от сохранения деления имеет большее значение, чем потеря точности результата. (И результат будет хуже, если вы воспользуетесь этим трюком, а не лучше.)   -  person tmyklebu    schedule 27.06.2014
comment
Не могли бы вы опубликовать конкретный пример? Я ожидаю, что простое деление даст наиболее точный ответ, а версия умножения будет иметь немного большую ошибку округления, но рассмотрение конкретного случая позволит это проверить.   -  person Patricia Shanahan    schedule 27.06.2014


Ответы (3)


Нет, это просто попытка сделать это быстрее, поскольку умножение часто выполняется быстрее, чем деление.

Что делать: умножение или деление?

1 деление и 2 умножения против 2 делений не всегда могут быть быстрее, но почти наверняка причина в этом.

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

Ошибки округления в дополнительных операциях приводят к разным результатам.

person weston    schedule 26.06.2014
comment
Основываясь на таблицах инструкций Агнера Фога, по крайней мере, для Haswell, два идеально спланированных div'а займут 14 тактов, а div и два mul'а займут 8. - person Cory Nelson; 27.06.2014
comment
Я сомневаюсь в том, чтобы называть это точными цифрами. У разных процессоров разные значения. Так о какой таблице вы имеете в виду? Плюс какие именно операции? - person weston; 27.06.2014
comment
@weston: очевидно, таблица для Haswell (en.wikipedia.org/wiki/Haswell_%28microarchitecture % 29). - person Rudy Velthuis; 27.06.2014
comment
См. Руководство по таблицам инструкций на сайте Agner Fog. Я смотрю DIVSS и MULSS для архитектуры Haswell. - person Cory Nelson; 27.06.2014
comment
Интересный материал. Не знаю, как интерпретировать эти таблицы сам! Почему вы выбрали операции SS, а не другие миллионы мультиплееров и дивизионов? - person weston; 27.06.2014
comment
SS = Скалярная одинарная точность, т.е. float. В отличие от, например, PD = Упакованный (вектор) Двойная точность. - person Stephen Canon; 27.06.2014

Помните, что плавающая запятая имеет форму (мантисса * основание ^ экспонента), где основание чаще всего равно 2, а мантисса имеет ограниченное количество цифр в основании и находится в интервале [1,2) или [0,1). для субнормальных.

Согласно стандарту IEEE 754 каждая операция с плавающей запятой (как минимум + - * / fmod остаток sqrt) работает так, как если бы она была произведена этим алгоритмом:

  1. выполнить точную операцию (значение1 * 2 ^ exp1) op (значение2 * 2 ^ exp2)
  2. округлить этот точный результат до ближайшего представимого числа с плавающей запятой согласно действующему направлению округления.

Я немного упростил, потому что есть еще обработка исключительных значений, программируемая генерация исключений FPU и т. Д.

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

Поскольку * быстрее, чем / (попробуйте подражать им самостоятельно), первый из них, который учитывает обратное, предназначен для увеличения скорости выполнения, но, конечно, не для повышения точности.

person aka.nice    schedule 26.06.2014

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

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

person jcaron    schedule 26.06.2014
comment
«Если бы вычисление факторов было более сложным», это деление. - person Pascal Cuoq; 27.06.2014