2016-03-01 2 views
0

Я хочу преобразовать значение double в std::string. В настоящее время я пишуdouble to std :: string with dynamic precisicion (без конечных нулей)

return std::to_string(double_value); 

Но это только возвращает 7 цифр, потому что внутренне to_string() просто использует std::vsnprintf с форматом %f спецификатора (смотри также here).

Теперь я могу просто позвонить std::vsnprintf с помощью %.15f в качестве спецификатора формата, но это приведет к завершающим нулям.

My (в моих глазах очень очевидно) цель сейчас иметь такой подход, как это:

string o1 = to_string(3.14) 
string o2 = to_string(3.1415926536) 
assert(o1 == "3.14") 
assert(o2 == "3.1415926536") 

Here является хорошей разработкой на подрезки завершающих нулей из %.20 выхода, но этот ответ около 8 лет ,

Возможно, все изменилось? Можно ли преобразовать double с двойной точностью без конечных нулей в C++ сегодня?

Решение:

Основываясь на 2man сек ответ вы можете написать обобщенную функцию следующим образом:

template<typename T> 
inline std::string tostr(T value) { 
    std::ostringstream s; 
    s.precision(std::numeric_limits<T>::digits10); 
    s << value; 
    return s.str(); 
} 

, который ведет себя, как требуется для числовых типов. Обратите внимание, что я взял digits10, а не max_digits10 в пользу хороший десятичное представление, а не более цифр и задней ..0000001

Также ИМХО стоит добавить, что [v][s][n]printf() вместе с форматом строки «% +0,15 г» (а не " f ') также будет обрезать конечные нули (не будет работать с большим количеством цифр, потому что они не могут быть представлены с 64 бит, что приведет к вещам вроде «1», например, 3.12 -> «3.1200000000000001»)

Still странный:

Может быть, кто-то может мне сказать, почему std::to_string(double), который был введен с C++ - 11 жесткими кодами для vsnprintf(..., "%f", ...), а не чем-то вроде vsnprintf("%.15g"), что приведет к более точному представлению без влияния на код C?

+0

Одна хорошая вещь о C заключается в том, что она * чрезвычайно * обратная совместимость. То, что код C в связанном ответе составляет восемь лет, не имеет значения, он все равно будет работать, и ничто релевантное не изменилось со стандартом C11. Не следует также переводить на C++. Без чего-то подобного это невозможно, если вы действительно не знаете количество значащих цифр заранее. –

+1

Неважно, 8 лет или восемь часов: хороший код - хороший код. (Кроме того, это C++ ... Это не сильно меняется). – Ellis

+1

Как вы планируете обрабатывать округление с плавающей запятой? Я попытался сделать что-то простое добавление символов в строку, но '3.14' может быть не точно« 3.14 »при сохранении в памяти. Без ограничения цифр вы можете получить '2.12000000005', если хотите' 2.12'. – Matt

ответ

2

Вы можете использовать строковый поток (sstring) с потоковыми манипуляторами, смотрите пример ниже:

std::stringstream ss1; 
    std::stringstream ss2; 
    ss1.precision(15);  
    ss1 << 3.14; 
    std::cout << ss1.str()<<' '<<("3.14" == ss1.str())<<std::endl; 
    ss2.precision(15); 
    ss2 << 3.1415926536; 
    std::cout << ss2.str()<<' '<<("3.1415926536" == ss2.str())<<std::endl; 

Или вы можете использовать формат наддув. Вот a link!

std::cout<<format("%.2f") % 3.14 <<std::endl; 
    std::cout<<format("%.10f") % 3.1415926536 <<std::endl; 
+0

В этом примере вам все же нужно вручную указать точность. С 'vsnprintf()' он правильно обрезается, если вы не добавляете точность в '% f', но она ограничена 7 цифрами. – frans

+0

Вы можете установить точность до 15. Когда вы передаете поток в строку, строка не будет содержать «0» в конце. – 2man

+0

вы правы - и вы не должны использовать максимальное число десятичных цифр, которое может быть представлено «double» (это будет 17). (см. мое редактирование) – frans

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