Ответ 1
Код не соответствует.
Приложение G, раздел 5.1, пункт 4, читает
Операторы
*
и/
удовлетворяют следующим бесконечным свойствам для всех действительных, мнимых и комплексных операндов:- если один операнд бесконечен, а другой операнд - ненулевое конечное число или бесконечность, то результат оператора * является бесконечностью;
Итак, если z= a * ib бесконечно и w= c * id бесконечно, число z * w должен быть бесконечным.
В том же приложении, раздел 3, параграф 1, определяется, что означает, что для комплексного числа будет бесконечным:
Комплексное или мнимое значение с по крайней мере одной бесконечной частью рассматривается как бесконечность (даже если ее другая часть является NaN).
So z бесконечно, если либо a, либо b. Это действительно разумный выбор, поскольку он отражает математическую структуру 1.
Однако, если мы допустим z= ∞ + i∞ (бесконечное значение) и w= i∞ (и бесконечное значение), результат для кода Intel z * w= NaN + iNaN из-за промежуточных продуктов ∞ · 0 2.
Это достаточно, чтобы обозначить его как несоответствующее.
Мы можем еще раз подтвердить это, взглянув на сноску первой цитаты (сноска здесь не сообщается), она упоминает директиву CX_LIMITED_RANGE
pragma.
Раздел 7.3.4, пункт 1 гласит
Обычные математические формулы для комплексного умножения, деления и абсолютного значения являются проблематичными из-за их обработки бесконечностей и из-за чрезмерного переполнения и недостаточного потока. Прагма
CX_LIMITED_RANGE
может использоваться для информирования реализации о том, что (там, где состояние "включено" ) приемлемы обычные математические формулы [, которые производят NaN].
Здесь стандартный комитет пытается смягчить огромный моль работы для комплексного умножения (и деления).
Фактически GCC имеет флаг для контроля этого поведения:
-fcx-limited-range
Когда этот параметр включен, этот параметр указывает, что при выполнении сложного деления не требуется этап сокращения диапазона.Также не проверяется, является ли результат комплексного умножения или деления NaN + я * NaN с попыткой спасти ситуацию в этом случае.
Значение по умолчанию
-fno-cx-limited-range
, но включено-ffast-math
.
Эта опция управляет установкой по умолчанию для ISO C99CX_LIMITED_RANGE
прагмы.
Только этот параметр заставляет GCC генерировать медленный код и дополнительные проверки, без него код, который он генерирует, имеет те же недостатки Intel один (я перевел источник на C++)
f(std::complex<float>):
movq QWORD PTR [rsp-8], xmm0
movss xmm0, DWORD PTR [rsp-8]
movss xmm2, DWORD PTR [rsp-4]
movaps xmm1, xmm0
movaps xmm3, xmm2
mulss xmm1, xmm0
mulss xmm3, xmm2
mulss xmm0, xmm2
subss xmm1, xmm3
addss xmm0, xmm0
movss DWORD PTR [rsp-16], xmm1
movss DWORD PTR [rsp-12], xmm0
movq xmm0, QWORD PTR [rsp-16]
ret
Без этого код
f(std::complex<float>):
sub rsp, 40
movq QWORD PTR [rsp+24], xmm0
movss xmm3, DWORD PTR [rsp+28]
movss xmm2, DWORD PTR [rsp+24]
movaps xmm1, xmm3
movaps xmm0, xmm2
call __mulsc3
movq QWORD PTR [rsp+16], xmm0
movss xmm0, DWORD PTR [rsp+16]
movss DWORD PTR [rsp+8], xmm0
movss xmm0, DWORD PTR [rsp+20]
movss DWORD PTR [rsp+12], xmm0
movq xmm0, QWORD PTR [rsp+8]
add rsp, 40
ret
1 Там, где модуль числа продолжается от реального случая | z | на комплексный ‖z‖, сохраняя определение бесконечности в результате неограниченных пределов. Проще говоря, в комплексной плоскости существует целая окружность бесконечных значений, и для получения бесконечного модуля требуется только одна "координата" .
2 Ситуация становится худшей, если мы помним, что z= NaN + i∞ или z= ∞ + iNaN являются допустимыми бесконечными значениями