2010-11-18 2 views
23

Мне нужна помощь по поддержанию точности double. Если я присваиваю литерал двойному, фактическое значение было усечено.Как «вывести» правильное количество десятичных знаков двойного значения?

int main() { 
    double x = 7.40200133400; 
    std::cout << x << "\n"; 
} 

Для приведенного выше фрагмента кода, выход был 7.402
Есть ли способ, чтобы предотвратить этот тип усечения? Или есть способ точно рассчитать, сколько плавающих точек для double? Например, number_of_decimal(x) даст 11, так как вход неизвестен во время выполнения, поэтому я не могу использовать setprecision().


Я думаю, что я должен изменить свой вопрос: Как преобразовать двойной в строку без усечения плавающей точки. т.е.

#include <iostream> 
#include <string> 
#include <sstream> 

template<typename T> 
std::string type_to_string(T data) { 
    std::ostringstream o; 
    o << data; 
    return o.str(); 
} 

int main() { 
    double x = 7.40200; 
    std::cout << type_to_string(x) << "\n"; 
} 

Ожидаемый выход должен быть 7.40200, но фактический результат был 7.402. Итак, как я могу обойти эту проблему? Есть идеи?

+1

«Ожидаемый результат» - проблема с вашими ожиданиями. «7.40200, но фактический результат был 7.402» - они равны, поэтому ничего не было «усечено». cout не может знать, сколько нулей вы ввели в ваш исходный файл. –

+0

См. [This] (http://www.cplusplus.com/reference/iostream/ios_base/precision/) для точности с плавающей точкой. – Benoit

ответ

27

Из-за фактом float и double внутренне хранится в двоичном виде, в буквальном смысле 7.40200133400 на самом деле стоит за номер 7,40200133400000037653398976544849574565887451171875

... так сколько точности вы действительно хотите? :-)

#include <iomanip>  
int main() 
{ 
    double x = 7.40200133400; 
    std::cout << std::setprecision(51) << x << "\n"; 
} 

И да, эта программа действительно печатает 7.40200133400000037653398976544849574565887451171875!

+0

Hi Fred, Я не хочу никакой определенной точности. Я просто хочу преобразовать его в строку в качестве исходного формата. Исправьте меня, если я неправильно понял вашу инструкцию. Спасибо, – Chan

+0

@Chan: Вы хотите '7.402001334' или' 7.40200133400' или '7.402001334000000'? – fredoverflow

+0

Я хочу 7.40200133400, не больше и не меньше. – Chan

9
std::cout << std::setprecision(8) << x; 

Обратите внимание, что setprecision является постоянным и все последующие поплавки вы распечатываете будут печататься с этой точностью, пока вы не измените его на другое значение. Если это проблема, и вы хотите, чтобы работать вокруг этого, вы можете использовать прокси-stringstream объект:

std::stringstream s; 
s << std::setprecision(8) << x; 
std::cout << s.str(); 

Для получения дополнительной информации о форматировании iostream, проверьте раздел Input/output manipulators в cppreference.

+0

Привет, Кос, я понимаю, что вы сказали, но проблема заключалась в том, что точность меняется от одного значения к другому. Например: 1.233 и 3.99945, у одного есть 3, а у одного есть 5. – Chan

+0

-1, а не то, о чем спрашивают OP .. :( – Nim

+3

@Chan: все числа с плавающей точкой имеют одинаковую точность. – You

5

Решение с помощью Boost.Format:

#include <boost/format.hpp> 
#include <iostream> 

int main() { 
    double x = 7.40200133400; 
    std::cout << boost::format("%1$.16f") % x << "\n"; 
} 

Это выводит 7.4020013340000004.

Надеюсь, это поможет!

+0

Во-первых, спасибо Даниэлю. Но я думаю, что форсирование :: format ведет себя точно так же, как cout.set (0, std :: ios :: floatfield), а ваш результат не является оригинальным. Моя проблема в том, что я хочу преобразуйте это двойное значение в строку. – Chan

+0

Исходный текст - это то, что вы набрали в текстовый файл. Это необязательно представляет фактическое значение. –

3

Единственный ответ на этот вопрос, который я придумал, заключается в том, что нет способа сделать это (как в вычислении десятичных знаков) правильно! Основная причина этого заключается в том, что представление числа может быть не таким, как вы ожидаете, например, 128.82, кажется достаточно безобидным, однако фактическое представление - это 128.8199999999 ... как вы вычисляете количество десятичных знаков там?

+1

Вы можете добавить или удалить его 0.0000000001, затем распечатать его снова и посмотреть, новый вывод использует меньшее количество символов. Сумма, которую нужно добавить или удалить, зависит от точности, которой вы довольны. –

+1

Если вы действительно не обеспокоены уровнем точности, в этом случае вы, вероятно, делаете свое дело, вы всего лишь на 15 мест. После 15 вы не имеете очень хорошей точности в любом случае. –

+0

На самом деле, я хочу преобразовать это значение в строку, и я хочу сохранить его формат, поскольку он был прочитан из файла. – Chan

17

Вы должны использовать setiosflags(ios::fixed) и setprecision(x).

Например, cout << setiosflags(ios::fixed) << setprecision(4) << myNumber << endl;

Кроме того, не забудьте #include <iomanip.h>.

+2

+1 для ios :: fixed as: setiosflags (ios :: fixed) помогает в случае, когда num == (int) num, позволяет выводить число в формате, таком как 2.00, без него будет 2 –

2

Ответ на ваш ответ-редактирование: нет способа сделать это. Как только вы назначаете значение double, любые конечные нули теряются (для компилятора/компьютера 0,402, 0,4020 и 0,40200 указаны ТОЛЬКО НОМЕР). Единственный способ сохранить конечные нули, как вы указали, - это сохранить значения в виде строк (или сделать обман, где вы отслеживаете количество цифр, о которых вы заботитесь, и отформатировать его до такой длины).

1

Давайте сделаем аналогичный запрос: после инициализации целого числа с 001 вы хотели бы напечатать его с помощью ведущих нулей. Эта информация о форматировании просто не хранилась.

Для дальнейшего понимания хранилища с плавающей точкой с двойной точностью взгляните на стандарт IEEE 754.

2

Удваивает не есть десятичные знаки. У них есть бинарные места. А бинарные места и десятичные знаки несоизмеримы (потому что log2(10) не является целым числом).

То, о чем вы просите, не существует.

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