ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Четверг
21 ноября
910300 Топик полностью
Ксения (14.03.2019 15:03, просмотров: 613) ответил Evgeny_CD на Интересно, за счет чего все же разница образуется? fma и обычный FPU в проце по-разному считают дабловую плавучку, у них не все разряды достоверные?
В разрядами у FPU87 всё отлично, т.к. он всегда считает в разрядной сетке float80, а при чтении и записи в память делает конверсию в float80 и обратно. Я до сих пор им пользуюсь, когда нужна повышенная точность. Исключение поддержки float80 этому помешать не может, т.к. вместо "long double" можно создать свой класс со строкой в 5 байт и пользоваться этим ... из своей арифметики :), переопределив арифметические операции под float80. Однако подчеркну, что всё это имеет смысл при работе с плохо определенными матрицами или матрицами большой размерности, когда длины мантиссы не хватает для сложения больших и малых чисел. Причины образования разницы в скорости между FPU87 и SSE/AVX: 1. FPU87 работает с числами на своем стеке (8 внутренних регистров float80), снаружи недоступных. А потому загрузка и выгрузка чисел сопровождается "растяжкой" коротких операндов при чтении из памяти и округлением при выгрузке в память. И эти операции тоже расходуют время, т.к. здесь не простая операция память - регистр, но и преобразование числа из одной формы в другую. Именно здесь интересен формат данных float80, т.к. при его использовании такого преобразования нет, хотя повышается расход времени на операции с памятью, т.к. становится на 2 байта больше. 2. FPU87 имеет стековую архитектуру, что мешает компиляторам использовать его регистры для загрузки всех параметров функции, поскольку позиция числа в стеке постоянно прыгает при выполнении операций. Из-за этого компилятор использует FPU87 по-дурацки - только два внешних регистра: затолкал пару чисел, вызвал команду выполнения операции между ними, а затем результат тут же вытолкал назад в память. Именно поэтому float-параметры для вызываемой функции (тем паче, когда их больше одного) закладываются не на стек FPU87, а на системный стек возвратов. Тогда как при работе с SSE/AVX параметры можно сразу закладывать в арифметические регистры (с №0 по №3) перед вызовом функции, используя их, как flоat-переменные, напрямую. Например, при суммировании элементов массива: Sum += Array[i] при работе с FPU87 компилятору пришлось бы завести в ПАМЯТИ переменную Sum, а самому FPU87 в каждом цикле грузить Sum из памяти в свой регистр (с расширением разрядной сетки), а после приращения записывать обратно в переменную Sum (с округлением float80 до float64 или float32). Тогда как на SSE/AVX компилятор может ассоциировать переменную Sum с одним из арифметических регистров (проще с №0, т.к. в нем положено оставлять результат) и накапливать сумму прямо в нем, без перезагрузки в память и без растяжек и округлений на каждом шаге. Конечно, если пишешь на ассемблере, то такого рода проблемы преодолеваются, однако абсолютное большинство пользуется услугами компилятора, который полные возможности FPU87 не использует. 3. В инструкциях SSE/AVX есть операции, которых у FPU87 нет. Скажем, пресловутая fma(a,b,c) на AVX2 в среднем выполняется за один такт, т.к. современные процессоры имеют раздельные блоки умножения и сложения, которые могут работать одновременно - пока второй складывает a*b+c, первый умножает следующую пару a*b. 4. Лично у меня есть еще опасение, что скорость FPU87 специально тормозится против SSE/AVX. Например, при переходе с "Pentium 4" на "Core 2 Duo" SSE2 ускорились сильнее, чем FPU87. У новых процессоров, если верить таблицам, вроде бы соблюдается паритет в скорости выполнения сложения и умножения, но на практике FPU87 продолжил отставание. Сильно похоже на то, что выполнение AVX-инструкций стараются оптимизироваться (на уровне микрокода и железа), тогда как на FPU87 и SSE махнули рукой.