2012-05-30 3 views
6

Я использую функцию sqrt() из математической библиотеки, когда я строю для 64-битного с использованием -m64. Я получаю правильный результат, но когда я строю для 32-битного, у меня есть очень непоследовательное поведение.поведение или sqrt при компиляции с 64 или 32 битами

Например на 64-битных

double dx = 0x1.fffffffffffffp+1023; 
sqrt(dx); // => 0x1.fffffffffffffp+511 
sqrt(0x1.fffffffffffffp+1023);// => 0x1.fffffffffffffp+511 

(который я считаю, это правильно округленный результат, проверено с MPFR)

Но на 32 битном же входного значения он ведет себя по-разному.

double dx = 0x1.fffffffffffffp+1023; 
sqrt(dx); // => 0x1.0p+512 
sqrt(0x1.fffffffffffffp+1023); // => 0x1.fffffffffffffp+511 

Когда одно и то же значение передается переменной, я получаю неправильный результат. Я проверил режим округления до и после каждого звонка, и все они настроены на округление до ближайшего. Какая причина? Я использую gcc 4.6 на 64-битной машине, а опции - -mfpmath=sse и -march=pentium для обоих случаев x86 nad x64.

+0

Кажется, одна ошибка открыта на этом по адресу http://sources.redhat.com/bugzilla/show_bug.cgi?id=14032, даже когда я использую -msse2 для 32-битного кода i386, который получает казнены. – kanna

ответ

6

Вы не сказали, какой компилятор или архитектура вы используете, но при условии, gcc на x86/x86-64 то разница, вероятно, сводится к тому, что по умолчанию GCC использует 387 команд с плавающей точкой на 32 битной x86, в то время как использует инструкции SSE на x86-64.

Регистры с плавающей запятой 387 имеют ширину 80 бит, а double - 64 бит. Это означает, что промежуточные результаты могут иметь более высокую точность с использованием инструкций 387, что может привести к несколько другому ответу после округления. (Инструкции SSE2 работают на упакованных 64-битных удвоениях).

Там несколько способов, чтобы изменить способ компилятора работает, в зависимости от того, что вы хотите:

  • Если вы используете -ffloat-store опцию x86 сборок, компилятор будет отбрасывать дополнительную точность всякий раз, когда вы сохраняете значение в a double переменная;
  • Если вы используете опции -mfpmath=sse в сборках x86, а также -msse2 или коммутатор -march=, который указывает архитектуру, поддерживающую SSE2, компилятор будет использовать инструкции SSE для с плавающей запятой, как и на x86-64. Код будет работать только на процессорах, поддерживающих SSE2 (Pentium-M/Pentium 4 и выше).
  • Если вы используете опцию -mfpmath=387 на сборках x86-64, компилятор будет использовать 387 инструкций для с плавающей запятой точно так же, как и на x86. Это не рекомендуется, хотя - ABI x86-64 указывает, что значения с плавающей запятой передаются в регистры SSE, поэтому компилятор должен сделать много перетасовки между регистрами 387 и SSE с этой опцией.
+0

Я использую gcc 4.6 на 64-битной машине, а опции - '-mfpmath = sse' и' -march = pentium' для x86 nad x64 случаев. Shoudln't Я получаю одинаковый результат от обоих случаев? Меня больше всего интересует 32-битная сборка, поэтому я думаю, что '-mfpmath = 387' может дать мне правильный результат, если нет других проблем. – kanna

+1

@giridhart:' -march = pentium' только позволяет SSE1, который делает только одноточность - для двойной точности он должен вернуться к 387, который имеет бонусную точность. Вы хотите использовать '-msse2' или' -march = pentium-m' или аналогично вместе с '-mfpmath = sse'. – caf

+0

На самом деле я использую '-mfpmath = sse' и' -msse', теперь я изменился на '-mfpmath = sse2', но я по-прежнему получаю неправильный результат. пожалуйста, предложите правильный вариант для исправления этого. благодаря – kanna

6

Некоторые компиляторы, такие как gcc, когда они видят определенные функции математической библиотеки, выполняемые на статических литералах, фактически вычисляют значение во время компиляции, где, как и с переменной, оно по необходимости вычисляется во время выполнения. Значение времени компиляции обычно вычисляется компилятором с использованием математической библиотеки, такой как MPFR, GNU MP и т. Д., Поэтому результаты будут более точными или, по крайней мере, настолько точными, насколько это возможно, от платформы к платформе.

+1

Я также помню, что gcc готов выполнить компиляцию математики на литералах с использованием 80-битной точности на x86, а значение, которое хранится в 'double', должно быть уменьшено до 64-битной точности. – hobbs

+0

Да, это тоже ... – Jason

+0

Да, я думаю, что причина для правильного результата при использовании константы. Есть ли способ исправить проблему с 32-битной библиотекой? Аналогичная проблема возникает при переполнении стека, но она связана с C# http://stackoverflow.com/questions/2461319/c-sharp-inconsistent-math-operation-result-on-32-bit-and-64-bit – kanna

 Смежные вопросы

  • Нет связанных вопросов^_^