Массив с плавающей точкой в ​​C - PullRequest
1 голос
/ 06 декабря 2009

Я разрабатываю код, в котором мне нужно загрузить значения с плавающей запятой, хранящиеся в каждой строке за раз в текстовом файле ... я загрузил все эти данные в массив с плавающей запятой, используя fscanf () ... однако я обнаружил, что плавающие точки были сохранены по-другому, пример 407.18 был сохранен как 407.179993, 414.35 как 414.350006 ... теперь я застрял, потому что это абсолютно важно, чтобы числа были сохранены в том виде, в котором они были в файле, но здесь это кажется, отличается, хотя по сути это то же самое .... как я могу получить числа для хранения в исходном виде?

Ответы [ 6 ]

17 голосов
/ 06 декабря 2009

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

За подробностями обращайтесь к статье "Что должен знать каждый компьютерный специалист об арифметике с плавающей точкой" [PDF link].

Вы должны хранить числа в строковой форме или в виде целых чисел.

11 голосов
/ 06 декабря 2009

То, что вы видите, верно, поскольку число с плавающей запятой не может точно представлять много действительных чисел. Это необходимо прочитать: Что должен знать каждый компьютерщик об арифметике с плавающей точкой

2 голосов
/ 06 декабря 2009

Sfactor, Небольшое уточнение: вы заявляете: «... абсолютно важно, чтобы числа сохранялись в той форме, в которой они были в файле» - что это за «форма»? Я предполагаю отображение формы ?! Вот сделка: если вы храните в файле 407.18, но он отображается как 407.179993 - это абсолютно нормально и ожидаемо. Когда вы создаете свой sprintf или любой другой форматированный отпечаток, который вы используете, вы должны указать ему ограничить точность после десятичной точки. Это должно сделать трюк:

#include <stdio.h>
void main(void);
void main()
{
   printf("%.2f",407.179993);
}
2 голосов
/ 06 декабря 2009

Типы C ++ float и double представлены как числа с плавающей точкой IEEE. Существуют двоичные числа с плавающей запятой, а не десятичные. Они не имеют бесконечной точности, и даже относительно «простые» десятичные значения изменятся при преобразовании в двоичную с плавающей запятой и обратно.

Языки, ориентированные на деньги (например, COBOL и PL / I), имеют десятичные типы данных, которые используют более медленные представления, которые не имеют этой проблемы. Для этой цели существуют библиотеки на C или C ++, или вы можете использовать масштабированные целые числа, если вам не нужен слишком большой диапазон.

0 голосов
/ 06 декабря 2009

Существует много разных способов хранения чисел - каждый со своими сильными и слабыми сторонами.

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

Масштабированные целые числа - это случай общей идиомы дизайна: отдельное представление от представления.

Определите, сколько цифр вы хотите после десятичной точки, например. 2 цифры как в 123,45. Затем вы должны внутренне представить число как целое число 12345. Всякий раз, когда вы отображаете значение для пользователя, вы должны вставить десятичную точку в соответствующем месте.

Short Статья InformIT о Scaled Integer by Дэнни Калев

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

0 голосов
/ 06 декабря 2009

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

...