Подтвердить что ты не робот

Расширенная (80-разрядная) двойная с плавающей запятой в x87, а не SSE2 - мы ее не пропустили?

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

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

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

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

4b9b3361

Ответ 1

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

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

Кстати, если у вас возникли проблемы с неточностями, вам нужно взглянуть на статью " Что каждый программист должен знать о арифметике с плавающей запятой", а затем, возможно, вместо этого использовать произвольную математическую библиотеку точности (например, GMP).

Ответ 2

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

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 botched.

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

  • Распакуйте мантиссу, экспоненту и, возможно, знак x в отдельные регистры (показатель экспоненты и знак часто могут быть "двухъярусными" ).
  • Распакуйте также.
  • Сдвиньте мантиссой значение с нижним индексом, если оно есть, а затем добавьте или вычтите значения.
  • В случае, если x и y имеют разные знаки, сдвиньте влево мантису до тех пор, пока крайний левый бит не станет равным 1 и соответствующим образом отрегулируйте экспоненту.
  • Добавьте экспонента и мантиссу обратно в двойной формат.
  • Распакуйте этот временный результат.
  • Распаковать z.
  • Сдвиньте мантиссой значение с нижним индексом, если оно есть, а затем добавьте или вычтите значения.
  • В случае, если предыдущий результат и z имели разные знаки, сдвиньте левую мантиссу до тех пор, пока крайний левый бит не станет равным 1 и соответствующим образом настройте экспоненту.
  • Добавьте экспонента и мантиссу обратно в двойной формат.

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

Ответ 3

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

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

Ответ 4

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

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

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

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

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

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