Неправильная точность длинного двойного вывода.Что может быть не так?

StackOverflow https://stackoverflow.com/questions/684112

Вопрос

у меня есть long double константа, которую я устанавливаю либо как константную, либо как неконстантную.Он длиннее (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, например:

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

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

Это было полезно?

Решение

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

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;    

Другие советы

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top