Код является ошибочной попыткой вычислить величину (абсолютное значение) переданного ему комплексного числа без ненужного переполнения.
Рассмотрим комплексное число a + b i, где a и b - это значения, присвоенные a
и b
в первых нескольких строках функции. Его величина √ ( a 2 + b 2 ). Однако, если a или b велико, вычисление с плавающей запятой a*a
может переполнить конечный диапазон формата с плавающей запятой и привести к бесконечности (∞), даже если величина находится в пределах досягаемости. В качестве простого примера, пусть a будет 2 1000 и b будет 0. Тогда величина √ (2 2000 + 0) = 2 1000 , но вычисление sqrt(a*a + b*b)
дает бесконечность. (Поскольку a*a
переполнено и выдает ∞, а остальные вычисления также производят ∞.)
Код пытается решить эту проблему путем деления меньшего из a и b по большому счету с использованием математически эквивалентного вычисления, но не переполнения. Например, если a < b
имеет значение true, выполняется:
a /= b;
y = b * sqrt(a * a + 1.0);
Тогда a /= b
дает значение меньше 1, поэтому все вычисления до последнего находятся в безопасном пределах в пределах конечного диапазона с плавающей запятой: a * a
меньше 1, a * a + 1.0
меньше 2 и sqrt(a * a + 1.0)
меньше 1,42. Когда мы умножим на b
, конечный результат может переполниться до ∞. Это может произойти по двум причинам: величина a + b i может превысить конечный диапазон с плавающей точкой, поэтому переполнение является правильным. Или же округление в предыдущих расчетах могло привести к тому, что sqrt(a * a + 1.0)
будет немного больше математического результата и достаточным для переполнения b * sqrt(a * a + 1.0)
, когда фактическое значение величины находится в пределах диапазона. Поскольку это не является нашей целью, я не буду более подробно анализировать этот случай в этом ответе.
Помимо этой проблемы округления, первые два случая хороши. Однако этот код неверен:
else if (b == NAN)
Согласно IEEE-754 2008 5.11 и IEEE-754 1985 5.7, NaN не меньше, равен или больше любого операнда, включая самого себя. неупорядочено . Это означает, что b == NAN
должно возвращать false, если используется IEEE-754. C 2018 не требует использования IEEE-754, но в сноске 22 (в п. 5.2.4.2.2 4) говорится, что, если IEC 60559: 1989 (фактически IEEE-754) не поддерживается, термины «Тихий NaN» и «сигнальный NaN» в стандарте C предназначены для применения к кодировкам с аналогичным поведением. И 7.12 5 говорит нам, что NAN
расширяется до float
, представляющего тихий NaN. Таким образом, в b == NAN
, NAN
должен вести себя как NaN IEEE-754, и поэтому b == NAN
должен давать 0 для false.
Следовательно, этот код, определяемый else if (b == NAN)
, никогда не выполняется:
y = b;
Вместо этого выполнение переходит к else
, который выполняет:
y = a * sqrt(2);
Если a
- это NaN, результатом является NaN, по желанию. Однако, если a
- это число, а b
- это NaN, в результате получается число, когда желаемым результатом будет NaN. Таким образом, код не работает.