Я читаю из текстового файла, который содержит следующую строку:
deltaT 0.005;
Как только у меня есть правильная строка в строке, я хочу прочитать значение с кодом, подобным этому:
double deltaT;
stringstream ss(line);
ss >> tag; //Contains: deltaT
ss >> deltaT; //Should contain: 0.005
Во время отладки я вижу, что deltaT содержит: 0,0050000000000000001
Так есть ли способ установить «точность» экстрактора, как для потокового вставщика?
Или как лучше всего гарантировать, что значение в текстовом файле — это двойное значение, которое у меня есть в моей программе.
Спасибо,
Мадлен.
Это обычная проблема двоичных типов с плавающей точкой: 0.005
не совсем представима double
Таким образом, преобразование из «десятичного литерала» дает наиболее похожее число, представимое double
,
Там нет решения, если вы хотите использовать double
или другие конечные, двоичные типы с плавающей запятой, так как 0.005
имеет конечную форму в десятичном виде, но является периодическим в двоичном (и мантисса любого типа FP ограничена).
Чтобы увидеть, как это возможно, рассмотрим дробь 1/3: в базе 3 она имеет конечное представление, а в базе 10 она периодическая:
(1/3)10 = 0,33333 …10 = 0,13
теперь любой «обычный» тип с плавающей запятой имеет только ограниченное пространство для мантиссы (то есть значащих цифр для хранения), поэтому каждое периодическое число должно быть обрезано (фактически округлено) в некоторой точке; это приводит к потере точности, которую вы видите.
Обратите внимание, что имеется несколько «библиотек произвольной точности» для решения таких проблем и выполнения математических операций с точностью, ограниченной только доступной памятью (например, GMP), но вы должны рассмотреть вопрос о том, оправдывает ли дополнительная сложность / потеря производительности выигрыш в точности.
Другое решение (обычно используемое при выполнении вычислений с использованием денег) заключается в использовании типов с фиксированной точностью, которые хранят сумму в виде целого числа, «неявно масштабируемого» с помощью некоторого десятичного множителя (концепция заключается в том, что центы хранятся в виде целых чисел, а не долларов как float
или что угодно); это позволяет избежать неожиданности, связанной с преобразованием десятичного числа в двоичное, поскольку все целые числа точно представлены с ограниченным числом цифр в любой базе.
Там нет таких вещей, как ограничение точности при чтении значения. В любом случае вы этого не хотите: вы хотите получить максимально приближенное значение. Из краткого взгляда кажется, что это то, что вы получили! Значение 0.005
не выглядит как значение, которое может быть точно представлено двоичной плавающей точкой. Тип double
и его друзья представлены как (-1)знак*мантисса* 2показатель степени и сразу видно, что это не может представлять все десятичные значения.
Проблема скорее в форматировании: вы должны позволить форматированию выбирать, сколько цифр он чувствует для форматирования. Предполагая, что исходное значение было просто прочитано из некоторого источника и является десятичным значением, а не результатом каких-либо вычислений, вы должны получить исходное значение при форматировании (за исключением конечных нулей, то есть).