Как запретить спецификатору формата float/double автоматически изменять мои десятичные значения в C?

У меня есть странная проблема, когда я ввожу, скажем, 720,60 в

sscanf("%f", &amount);

где сумма имеет тип float, значение переменной меняется на 720,59967.

Как я могу обойти это и предотвратить изменение моего значения?


person harshalizee    schedule 13.09.2013    source источник


Ответы (3)


Существует альтернатива использованию чисел с плавающей запятой, если вам нужно фиксированное количество цифр после запятой, например 2.

Разделите входную строку на «.» и обработайте «720,60» как два целых числа, 720 и 60. Умножьте 720 на 100 и прибавьте 60, получив 72060. Выполните всю свою арифметику с точки зрения целых чисел сотых. Чтобы отобразить, напечатайте x/100 и x%100, разделенные десятичной точкой, а второе число напечатано как две цифры с возможным начальным нулем.

Если вы предпочитаете работать с числами с плавающей запятой, double гораздо точнее, чем float. Ближайший плавающий курс к 720,60 — 720,5999755859375. Ближайший двойной 720.6000000000000227373675443232059478759765625. Оба будут округлены до «720,60», если будут напечатаны только с двумя цифрами после запятой, но ошибка округления может возникнуть при выполнении арифметических действий.

person Patricia Shanahan    schedule 13.09.2013

Вы можете напечатать меньше цифр или использовать double. Значение одинарной точности IEEE-754 float имеет 23-битную мантисса, что означает, что имеет точность около 7 десятичных знаков. Значение, которое вы видите, максимально близко: нет значения float ближе к 720,60, чем 720,59967.

Фактически, точные значения двух значений float, наиболее близких к 720,60, таковы:

720.5999755859375      (slightly less than 720.60)
720.60003662109375     (slightly more than 720.60)
person Joni    schedule 13.09.2013
comment
Любые обходные пути, которые вы могли бы предложить при обработке таких данных, где мне не нужны цифры после двух знаков после запятой. - person harshalizee; 13.09.2013
comment
Если вам нужны только две цифры после точки: printf(".2f", amount) - person Joni; 13.09.2013
comment
Я знаю. Но по какой-то причине спецификатор формата .2f не работает с sscanf. Мне нужно, чтобы он сканировал входной файл для чтения в переменную с плавающей запятой. Любые идеи? - person harshalizee; 13.09.2013
comment
Вы уже правильно читаете значение и с точностью, поддерживаемой типом данных. Что именно вы спрашиваете? - person Joni; 13.09.2013
comment
При сканировании из файла я копирую его в поплавок. Когда это значение используется в вычислениях, я получаю разницу около 0,01, так как мне нужно сохранить точность до двух десятичных значений. - person harshalizee; 13.09.2013
comment
Затем используйте double, более высокая точность уменьшает ошибки, так что ошибки округления не накапливаются до 0,01 так быстро. - person Joni; 13.09.2013

Ты не можешь сделать это. Это проблема точности, то есть формат с плавающей запятой, используемый в C, не может точно представлять 720,60. Вы можете попробовать тип double для amount, это повысит вашу точность, но вы все равно не получите точного значения.

Подробнее см. эту ссылку.

person Don't You Worry Child    schedule 13.09.2013