Какой обходной путь для неточности с плавающей запятой? - PullRequest
0 голосов
/ 13 октября 2010

Вот фрагмент кода:

float pNum = 9.2;
char* l_tmpCh = new char[255];

sprintf_s(l_tmpCh, 255, "%.9f", pNum);

cout << l_tmpCh << endl;

delete l_tmpCh;

вывод: 9.199999809
Что нужно сделать, чтобы результат был 9.200000000
Примечание.Точность 9 десятичных знаков, поэтому я не хочу иметь 9.2

Ответы [ 6 ]

8 голосов
/ 13 октября 2010

Обходной путь - не использовать числа с плавающей запятой.

Не каждое число может быть точно представлено в формате с плавающей запятой, например, 9.2.Или 0,1.

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

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

Обязательное чтение

3 голосов
/ 13 октября 2010

32-разрядное двоичное число с плавающей запятой никоим образом не может иметь точность в 9 цифр ( - только 7 ).Вы можете подделать его, добавив 3 ноля.

sprintf_s(l_tmpCh, 255, "%.6f000", pNum);

Это не будет работать, если целая часть уже исчерпала большую точность, например, 9222.2f даст 9222.200195000.

1 голос
/ 13 октября 2010

То, что вы просите, невозможно в общем случае, так как числа с плавающей запятой по определению являются приближениями, которые могут иметь или не иметь точное представление в десятичном виде. Прочитайте знаменитую статью Гольдберга: http://docs.sun.com/source/806-3568/ncg_goldberg.html

0 голосов
/ 13 октября 2010

Важно понимать, что собственные числа с плавающей точкой редко бывают «точными» из-за того, как они представлены в компьютере. Таким образом, большую часть времени вы получаете только приближение. И с printf, вы также указываете точность, с которой округлять это приближение к выводу. Например. "% .20f" даст вам представление, округленное до 20 цифр после "."

0 голосов
/ 13 октября 2010

Это должно сделать это:

double pNum = 9.2;

Суффикс f делает его литералом float, который имеет только около 7 десятичных цифр точности и, конечно, страдает от ошибок представления .Назначение его переменной double не исправляет это.Конечно, это предполагает, что float и double соответствуют типам одинарной и двойной точности IEEE 754.

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

0 голосов
/ 13 октября 2010

Используйте двойной литерал вместо плавающего.

double pNum = 9.2;
char* l_tmpCh = new char[255];

sprintf_s(l_tmpCh, 255, "%.9f", pNum);

cout << l_tmpCh << endl;

delete l_tmpCh;

Этот f делал буквальное число поплавком; без него значение является двойным литералом (точнее, около 15 десятичных цифр).

Конечно, если 15 цифр недостаточно, вы можете создать свой собственный класс для представления значений.

...