Знак нуля с поплавками

Рассмотрим следующий код, выполняющий операции над комплексными числами с помощью float языка C/C++:

float real_part = log(3.f);
float imag_part = 0.f;

float real_part2 = (imag_part)*(imag_part)-(real_part*real_part);
float imag_part2 = (imag_part)*(real_part)+(real_part*imag_part);

Результат будет

real_part2= -1.20695 imag_part2= 0
angle= 3.14159

где angle — фаза комплексного числа, в данном случае — pi.

Теперь рассмотрим следующий код:

float real_part = log(3.f);
float imag_part = 0.f;

float real_part2 = (-imag_part)*(-imag_part)-(real_part)*(real_part);
float imag_part2 = (-imag_part)*(real_part)+(real_part)*(-imag_part);

Результат будет

real_part2= -1.20695 imag_part2= 0
angle= -3.14159

Мнимая часть результата равна -0, что делает фазу результата равной -pi.

Хотя по-прежнему выполняется с основным аргументом комплексного числа и с подписанным свойством числа с плавающей запятой 0, это изменение представляет собой проблему при определении функций комплексных чисел. Например, если определить sqrt комплексного числа по формуле де Муавра, это изменит знак мнимой части результата на неправильное значение.

Как бороться с этим эффектом?


person Vitality    schedule 28.10.2013    source источник
comment
В float imag_part2 = (-imag_part)*(real_part) ... есть -. В complex_number3b.y=complex_number3a.x*complex_number3a.y ... нет -. Это ваше намерение?   -  person chux - Reinstate Monica    schedule 29.10.2013
comment
@chux imag_part меняется в знаке в обоих случаях. При вычислении imag_part2 я меняю знак imag_part, как вы заметили. При вычислении complex_number3b изменение знака находится в пределах complex_number3a.x, что равно -imag_part.   -  person Vitality    schedule 29.10.2013
comment
В …+(real_part*imag_part) нет знака минус.   -  person Pascal Cuoq    schedule 29.10.2013
comment
@chux Прошу прощения. Ты был прав. Я отредактировал свой пост.   -  person Vitality    schedule 29.10.2013


Ответы (1)


РЕДАКТИРОВАТЬ: теперь, когда вопрос, кажется, имеет смысл, похоже, что вопрос, на который Кахан отвечает, когда пишет, в своей статье Разрезы для сложных элементарных функций:

Как правило, арифметика смешанного режима, объединяющая действительные и комплексные переменные, должна выполняться напрямую, а не путем предварительного приведения вещественных к комплексным, чтобы знак нуля не стал неинформативным; то же самое касается комбинаций чисто мнимых величин с комплексными переменными. И выполнение арифметических операций таким образом экономит время выполнения, которое в противном случае было бы потрачено впустую на манипулирование нулями.

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


Отвечая на первоначальный вопрос:

Я не вижу ничего плохого в приведенных вами расчетах.

float imag_part = 0.f;

float imag_part2 = (-imag_part)*(real_part)+(real_part*imag_part);

Это устанавливает imag_part2 в -0. + 0., что равно +0. в округлении к ближайшему.

complex_number3b.y=complex_number3a.x*complex_number3a.y+complex_number3a.y*complex_number3a.x;

Это оценивается как -0. + -0., которое само оценивается как -0..

Ваши два вычисления не эквивалентны, это нормально, что они не дают одинаковых результатов. Оба результата соответствуют правилам IEEE 754 для нулевого знака.

person Pascal Cuoq    schedule 28.10.2013
comment
Большое спасибо за быстрый ответ. Я не утверждаю, что что-то не так. Я несколько удивлен, так как вычисления кажутся полностью эквивалентными. По-видимому, они должны выполнять точно такие же операции, как можно вывести из буквальной замены -imag_part и real_part вместо complex_number3a.x и complex_number3a.y соответственно. Но, возможно, это связано с невидимым поведением компилятора. Мой настоящий вопрос внизу поста касается как бороться с этим эффектом? Существует ли согласованный способ работы с комплексными числами? - person Vitality; 29.10.2013
comment
@JackOLantern Вы написали …+(real_part*imag_part). Замена complex_number3a.x на -imag_part в …+complex_number3a.y*complex_number3a.x не дает …+(real_part*imag_part). Если вы сделаете замену правильно, вы получите тот же результат. Способ справиться с эффектом, который вы описываете, - это сделать правильную замену. - person Pascal Cuoq; 29.10.2013
comment
Извиняюсь. Ты прав. Я внес некоторую путаницу. Пожалуйста, смотрите мой отредактированный пост. Моя проблема в том, что в зависимости от знака 0 я могу получить разные результаты при применении формулы де Муавра. Есть ли какой-то стандартный трюк, чтобы справиться с этим? - person Vitality; 29.10.2013
comment
Большое спасибо за ваш ответ. Это прояснило мне, откуда возникла проблема, а также предложило возможные пути ее решения. - person Vitality; 30.10.2013