Float to string без округления - PullRequest
3 голосов
/ 15 мая 2019

Я хотел извлечь десятичные знаки из десятичного числа. Не так сложно, верно?

Итак, я преобразовал число с плавающей точкой в ​​строку.

Затем я использовал substr(), чтобы обрезать строку, начиная с string.find('.')+1 до конца.

Ну ... проблема здесь. Когда у нас есть число, подобное этому: 5.7741589, это не так "точно", это на самом деле: 5.774159

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

Как преобразовать десятичное число в строку, не округляя ее?

РЕДАКТИРОВАТЬ: так как многие люди запрашивают фактический ввод и вывод и код, вот оно:

Input: 5.7741589
Output (let's say we want to output just decimal places): 7741589
Output (not expected one): 774159

Код:

float num;
cin>>num;
string s = to_string(num);
s = s.substr(s.find('.')+1,s.length());
cout<<s<<endl;

EDIT2: еще одна вещь. Мне это нужно для соревновательного программирования, я могу сделать это упражнение с вводом в виде строки. Представьте, что у вас есть проблема, когда у вас есть 2 десятичных числа, вам нужно умножить их и затем посчитать количество десятичных знаков. Тогда вы снова теряете десятичные разряды, что является проблемой.

Ответы [ 3 ]

4 голосов
/ 15 мая 2019

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

Если вы хотите точно смоделировать десятичные числа, используйте десятичный тип.

1 голос
/ 15 мая 2019

Давайте посмотрим, что произойдет (этот ответ предполагает IEEE-754, с плавающими 32-битными двоичными числами с плавающей точкой).

Сначала вы вводите десятичное число в качестве ввода: 5.7741589. Это число должно быть сохранено в 32-битном двоичном с плавающей запятой.

Это двоичное число 101.11000110001011110100011100010101011010000100011 ...

Чтобы сохранить это в число с плавающей точкой, нам нужно округлить его (в двоичном виде). Таким образом, cin>>num это с потерями . Он округляется до ближайшего 32-разрядного двоичного числа с плавающей запятой, которое:

  • в двоичном виде: 1.01110001100010111101001 * 2 ^ 2 = 101.110001100010111101001.
  • в десятичном виде: 1.44353973865509033203125 * 2 ^ 2 = 5.774158954620361328125.

Как видите, нет смысла говорить о десятичных разрядах после того, как ваш входной номер преобразован в число с плавающей точкой, потому что ваш входной номер был изменен (если смотреть на ваш номер в двоичном виде, он округлился Смотря на число как десятичное, оно получило много лишних цифр, его значение немного отличается от исходного).

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

1 голос
/ 15 мая 2019

В результате вы получаете округление десятичных разрядов. Это связано с тем, что как только вы вводите число с плавающей запятой, каким бы ни было число десятичных разрядов, оно сохраняется с таким количеством десятичных разрядов, как и точность типа данных. Так что для float (который может хранить 8 десятичных знаков), если вы введете

1.1234      ---- Stored as ---> 1.12339997
1.123       ---- Stored as ---> 1.12300003
5.7741589   ---- Stored as ---> 5.77415895

Таким образом, вы храните входные данные в этих числах (8) десятичных знаков. Что можно сделать, это то, что вы можете использовать приведенный ниже фрагмент, чтобы принудительно использовать желаемое количество цифр после десятичных разрядов и преобразовать его в строку.

float num;
cin >> num;

char buf[20];

// 8 is as per the (precision required + 1). So in this case,
// we have 7 digits after decimal, so 8 is used.
sprintf(buf, "%.8f", num); 

// Truncating the rounding off
buf[strlen(buf) - 1] = '\0';

string s(buf);
s = s.substr(s.find('.') + 1, s.length());
cout << s << endl;  

Хотя при таком подходе необходимо, чтобы все ваши входные данные имели одинаковое количество десятичных знаков.

Это своего рода обходной путь, потому что введенное вами значение 5.7741589 не сохраняется как есть. Итак, если сам источник не тот, который вы ввели, как вы можете получить желаемый результат, если предположить, что источник - это то, что вы предоставили.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...