Расширенная (80-битная) двойная плавающая точка в x87, а не SSE2 - мы не пропустили это? - PullRequest
33 голосов
/ 08 июля 2010

Сегодня я читал о исследователях, которые обнаружили, что библиотеки NVidia Phys-X используют x87 FP вместо SSE2 .Очевидно, что это будет неоптимальным для параллельных наборов данных, где скорость превосходит точность.Тем не менее, автор статьи продолжает цитировать:

Intel начала препятствовать использованию x87 с введением P4 в конце 2000 года. AMD устарела с x87 с K8 в 2003 году, так как x86-64 являетсяопределяется с поддержкой SSE2;VIA C7 поддерживает SSE2 с 2005 года. В 64-битных версиях Windows x87 не рекомендуется использовать в пользовательском режиме и полностью запрещать в режиме ядра.Практически все в отрасли рекомендуют SSE вместо x87 с 2005 года, и нет причин использовать x87, если только программное обеспечение не должно работать на встроенном Pentium или 486.

Я задавался вопросом об этом.Я знаю, что x87 использует 80-битные расширенные двойные значения для вычисления значений, а SSE2 - нет.Разве это ни для кого не имеет значения?Это кажется мне удивительным.Я знаю, что когда я делаю вычисления на точках, линиях и многоугольниках на плоскости, значения могут быть удивительно неправильными при выполнении вычитаний, а области могут сжиматься и выравнивать псевдонимы друг друга из-за отсутствия точности.Я мог бы предположить, что использование 80-битных и 64-битных значений может помочь.

Это неверно?Если нет, то что мы можем использовать для выполнения расширенных операций двойного FP, если x87 будет прекращен?

Ответы [ 4 ]

24 голосов
/ 10 июля 2010

Самая большая проблема с x87 в основном состоит в том, что все операции с регистрами выполняются в 80 битах, тогда как в большинстве случаев люди используют только 64-битные числа с плавающей запятой (то есть числа с двойной точностью).Что происходит, вы загружаете 64-битный float в стек x87, и он преобразуется в 80 бит.Вы выполняете некоторые операции над ним в 80 битах, затем сохраняете его обратно в память, преобразовывая его в 64 бит.Вы получите другой результат, чем если бы вы выполнили все операции всего с 64 битами, а с оптимизирующим компилятором может быть очень непредсказуемо, сколько преобразований может пройти значение, поэтому трудно проверить, что вы получаете "правильный ответ при проведении регрессионных тестов.

Другая проблема, которая имеет значение только с точки зрения того, кто пишет сборку (или косвенно пишет сборку, в случае, когда кто-то пишет генератор кода для компилятора),в том, что x87 использует стек регистров, тогда как SSE использует индивидуально доступные регистры.В x87 у вас есть куча дополнительных инструкций для манипулирования стеком, и я полагаю, что Intel и AMD скорее заставят свои процессоры работать с кодом SSE быстрее, чем пытаться заставить эти дополнительные инструкции x87 манипулировать стеком работать быстро.Кстати, если у вас возникли проблемы с неточностью, вам нужно взглянуть на статью " Что должен знать каждый программист об арифметике с плавающей точкой ", а затем, возможно, использовать математическую библиотеку произвольной точности (например, GMP).) вместо.

5 голосов
/ 22 сентября 2015

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

void print_dist_squared(double x1, double y1, double x2, double y2)
{
  printf("%12.6f", (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
}

должен быть какой-то тип, который можно использовать для захвата и замены общих подвыражений x2-x1 и y2-y1, позволяя переписать код как:

void print_dist_squared(double x1, double y1, double x2, double y2)
{
  some_type dx = x2-x1;
  some_type dy = y2-y1;
  printf("%12.6f", dx*dx + dy*dy);
}

без изменения семантики программы.К сожалению, ANSI C не смог указать какой-либо тип, который мог бы использоваться для some_type на платформах, которые выполняют вычисления с повышенной точностью, и стало гораздо более распространенным обвинять Intel в существовании типов с расширенной точностью, чем обвинять в неудачной поддержке ANSI.

Фактически, типы с расширенной точностью имеют такое же значение на платформах без модулей с плавающей запятой, как и на процессорах x87, поскольку на таких процессорах вычисления, подобные x + y + z, влекут за собой следующие шаги:

  1. Распакуйте мантиссу, экспоненту и, возможно, знак x в отдельные регистры (экспонента и знак часто могут "двухъярусными")
  2. Аналогично распакуйте y.
  3. Сдвиньте вправо мантиссу значения с меньшим показателем степени, если он есть, а затем сложите или вычтите значения.
  4. В случае, если x и y имели разные знаки, сдвигайте мантиссу влево до тех пор, пока самый левый бит не станет1 и отрегулируйте показатель степени соответствующим образом.
  5. Упакуйте показатель степени и мантиссу обратно в двойной формат.
  6. Распаковать этот временный результат.
  7. Распаковать z.
  8. Сместить вправо мантиссу значения с меньшим показателем степени, если он есть, а затем сложить или вычесть значения.
  9. В случае, если предыдущий результат и z имели разные знаки, сдвиньте мантиссу влево до крайнего левого бита, равного 1, и соответствующим образом скорректируйте показатель степени.
  10. Упакуйте показатель степени и мантиссу обратно в двойной формат.

Использование типа с повышенной точностью позволит исключить шаги 4, 5 и 6.Поскольку 53-битная мантисса слишком велика, чтобы поместиться менее чем в четыре 16-битных регистра или в два 32-битных регистра, выполнение сложения с помощью 64-битной мантиссы не медленнее, чем при использовании 53-битной мантиссы, поэтому использованиематематика с расширенной точностью предлагает более быстрые вычисления без недостатков в языке, который поддерживает правильный тип для хранения временных результатов .Нет оснований обвинять Intel в предоставлении FPU, который мог бы выполнять математические вычисления с плавающей запятой таким способом, который был и самым эффективным методом на чипах без FPU.

2 голосов
/ 21 сентября 2015

Другой ответ предполагает, что использование 80-битной точности - плохая идея, но это не так. Он играет иногда жизненно важную роль в сохранении неточности, см., Например, труды В. Кахана.

Всегда используйте 80-битную промежуточную арифметику, если вы можете справиться с ней по скорости. Если это означает, что вы должны использовать математику x87, хорошо, сделайте это. Его поддержка повсеместна, и пока люди продолжают поступать правильно, она будет вездесущей.

0 голосов
/ 09 сентября 2016

Двойная точность - на 11 бит меньше, чем f80 (примерно 2,5 куска / цифры), для многих приложений (в основном игр) это не повредит.Но вам понадобится вся точность, доступная, скажем, для космической программы или медицинского приложения.

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

Большим преимуществом SSE на самом деле является операция сериализации, 2, 4, 8 значений одновременно, с множеством операций типа varian.Да, вы можете напрямую перенести в регистр, но вы все равно перенесете эти значения в память в конце.

Большой недостаток f80 в том, что его нечетные 10 байт длиной нарушают выравнивание.вам нужно выровнять их 16 для более быстрого доступа.но не очень практично для массива.

Вы все равно должны использовать fpu для тригонометрических и других трансдентальных математических операций.Для asm есть много трюков f80, которые действительно забавны и полезны.

Для игр и обычного простого приложения (почти все), вы можете просто использовать double, чтобы никто не умер.Но для нескольких серьезных, математических или научных приложений вы просто не можете отказаться от f80.

...