2012-02-29 4 views
1
#include <stdio.h> 
#include <wchar.h> 
int main() 
{ 
    double f = 1717.1800000000001; 
    wprintf(L"double  %.20G\n", f); 
    return 0; 
} 

выходов (и ожидаемые ниже):GCC двойной точности Printf - неправильный выход

double  1717.1800000000000637 
double  1717.1800000000001 

Это на Ubuntu 11.10 x64 (но при компиляции для 32 бит).

Проблема, которую я пытаюсь решить, заключается в том, что в Windows она выводит число точно так же, как в коде, и мне нужно сделать низкоуровневое форматирование (swprintf) для работы, как в Windows, для проблем с переносимостью.

+0

1717.1800000000001 не является точно представимым как double, поэтому вы можете получить значение рядом с ним в 'f'. Значение, сохраненное в f, равно 1717.180000000000063664629124104976654052734375. Проблема в том, что окна обрабатывают только 17 значащих цифр, хотя было запрошено 20 (это известная ошибка, AFAIK - это где-то в их баг-файле). Если вы не можете ограничить длину поля значением разумного (например, 17), вам понадобится обертка для имитации этой ошибки. – hirschhornsalz

+0

Это очень интересно знать, можете ли вы вспомнить точную ошибку? Это то, что мне нужно, чтобы linux-версия работала, как Windows, даже с ее ошибками. – queen3

+0

На самом деле я установил 0,17 вместо .20, и теперь linux/windows полностью совместимы. Если вы измените свой комментарий, чтобы ответить, я бы с радостью принял его. Но если вы найдете точную ссылку на ошибку, это будет еще более полезно. – queen3

ответ

2

1717.1800000000001 не является точно представимым как double, поэтому вы получаете только значение рядом с ним в f. Значение, сохраненное в f, равно 1717.180000000000063664629124104976654052734375.

Проблема заключается в том, что окна выдают только 17 значащих цифр, хотя было запрошено 20 (что является известной ошибкой, AFAIK - это где-то в их базе данных ошибок).

Если вы не можете ограничить длину поля до нормального значения (например, "%.17G"), вам нужна обертка для имитации этой ошибки.

+0

Ошибка выглядит так: http://connect.microsoft.com/VisualStudio/feedback/details/329278/printf -sprintf-do-not-print-enough-important-digits-for-exact-binary-fraction – queen3

+2

@ queen3: Да, это отчет об ошибке (я написал его). См. Мою статью http://www.exploringbinary.com/print-precision-of-dyadic-fractions-varies-by-language/ для подробностей. –

+0

@ queen3: Хорошо пятнистый. Интересно посмотреть историю этой ошибки. – hirschhornsalz

1

wprintf функция реализована стандартной библиотекой C, а не gcc.

Номер 1717.1800000000001 имеет 13 цифр после плавающей запятой. Однако он не имеет точного представления в 64-битном двоичном формате с плавающей запятой.

Формат "%.20G" требует вывода 20 значащих цифр, что является количеством цифр в 1717.1800000000000637. Следовательно, этот результат является ожидаемым. Любая стандартная библиотека Windows C обрабатывает формат по-разному или делает неправильное округление.

С другой стороны, после плавающей запятой может потребоваться определенное количество цифр, используя формат "%f", например. "%.13f" округляет результат до 13 цифр после плавающей запятой и печатает 1717.1800000000001, как и ожидалось.

0

Ну, ваш ожидаемый результат конфликтует с вашей строкой формата. «% .20G» означает, что вы хотите получить 20 значащих цифр, и это то, что вы получаете. Если вы хотите 17 значащих цифр, как ваш ожидаемый результат, используйте «% .17G».

0
double f = 1717.1800000000001; 

Эта строка кода не может быть выполнена точно. Константа имеет 17 десятичных цифр точности, двойная - 15.9.

+0

Значение, заданное OP, не может быть точно представлено, это действительно так. Но остальная часть вашего ответа неверна, что можно легко показать: строка 'f = 1717.180000000000063664629124104976654052734375' будет выполнена точно, хотя она имеет еще больше цифр. – hirschhornsalz

+0

Но это не то, что находится в строке кода, которая не может быть выполнена точно, не так ли? И вам придется показать мне двоичное представление 1717.180000000000063664629124104976654052734375, потому что у double все еще только 53 бит, и это значение нужно больше. – EJP

+0

Нет, ему нужно _exactly_ 53 бит. Просто попробуйте. Выполнение с помощью калькулятора, способного обрабатывать произвольную арифметическую длину (например, gp) «15466982416256137216.0/2^53» – hirschhornsalz

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