Точность длинного двойного выхода неверна. Что может быть не так? - PullRequest
1 голос
/ 26 марта 2009

У меня есть константа long double, которую я устанавливаю как const или не-const. Это длиннее (40 цифр), чем точность long double на моей тестовой рабочей станции (19 цифр).

Когда я его распечатываю, он больше не отображается с точностью до 19 цифр, а с 16.

Вот код, который я тестирую:

#include <iostream>
#include <iomanip>
#include <limits>
#include <cstdio>

int main ()
{
    const long double constLog2 = 0.6931471805599453094172321214581765680755;
    long double log2 = 0.6931471805599453094172321214581765680755;    

    std::cout << std::numeric_limits<long double>::digits10 + 1 << std::endl;
    std::cout << "const via cout: " << std::setprecision(19) << constLog2 << std::endl;
    std::cout << "non-const via cout: " << std::setprecision(19) << log2 << std::endl;
    std::fprintf(stdout, "const via printf: %.19Lf\n", constLog2);
    std::fprintf(stdout, "non-const via printf: %.19Lf\n", log2);

    return 0;
}

Компиляция:

$ g++ -Wall precisionTest.cpp

Выход:

$ ./a.out
19
const via cout: 0.6931471805599452862
non-const via cout: 0.6931471805599452862
const via printf: 0.6931471805599452862
non-const via printf: 0.6931471805599452862

Я бы ожидал 0.6931471805599453094, но вместо этого получил бы 0.6931471805599452862.

Есть ли причина, по которой 19 цифр точности обрезаются до 16 цифр?

Вот мое окружение:

$ gcc --version
i686-apple-darwin9-g++-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5490)

Я вижу ту же проблему с другими версиями gcc, например ::1010 *

$ gcc --version
g++ (GCC) 3.4.6 20060404 (Red Hat 3.4.6-10)

Я могу заглянуть в NTL или другие библиотеки, но мне любопытно, что вызывает это. Спасибо за ваше понимание.

Ответы [ 2 ]

10 голосов
/ 26 марта 2009

Я получаю этот вывод:

19
const via cout: 0.6931471805599453094
non-const via cout: 0.6931471805599453094
const via printf: 0.6931471805599453094
non-const via printf: 0.6931471805599453094

Но я использую длинные двойные литералы вместо двойных:

const long double constLog2 = 0.6931471805599453094172321214581765680755L;
long double log2 = 0.6931471805599453094172321214581765680755L;    
4 голосов
/ 26 марта 2009

Существуют некоторые тонкие проблемы, связанные с аппаратными платформами и параметрами компиляции, которые могут представлять интерес:

Эти параметры `-m 'определены для компьютеров семейства i386 и x86-64:

-m96bit длиной двойной

-m128bit длиной двойной

Эти переключатели управляют размером длинного двойного типа. Двоичный интерфейс приложения i386 задает размер 96 бит, поэтому -m96bit-long-double - значение по умолчанию в 32-битном режиме. Современные архитектуры (Pentium и новее) предпочли бы долго удвоить, чтобы выровнять по 8 или 16 граница байта. В массивах или структурах в соответствии с ABI, это не будет быть возможным Так что указав -m128bit-long-double будет выравнивать long double с 16-байтовой границей обивка длинный двойной с дополнительные 32 бита ноль.

В компиляторе x86-64 -m128bit-long-double - выбор по умолчанию, поскольку его ABI указывает, что long double должен быть выровнен по 16 байтам граница.

Обратите внимание, что ни один из этих вариантов включить любую дополнительную точность над стандарт x87 80 бит для длинных двойной.

Предупреждение: если вы переопределите значение по умолчанию значение для вашей целевой ABI, то структуры и массивы, содержащие длинные двойные переменные изменят их размер, а также вызов функции соглашение для функции, занимающей много времени двойной будет изменен. Отсюда они не будет двоично совместимым с массивы или структуры в скомпилированном коде без этого переключателя.

...