Я хотел бы преобразовать float или double в целое число с фиксированной запятой в C. Я ищу наиболее подходящее (надежное) решение этой проблемы, учитывая спецификацию языка C.Поплавок (или двойной) в десятичное целое число с фиксированной точкой
Проблема, например, вдоль линий этого:
double d = 15.6;
int i;
...
i = (int)(d * 10.0); /* I am excepting getting 156 in 'i' */
Соответствующие элементы стандарта (с использованием C99 один, ISO/IEC 9899: ТС3 см this question для загрузки), насколько я вижу, :
- 6.3.1.4/1: Когда конечное значение действительного типа с плавающим преобразуются в тип целого числа, отличный
_Bool
, дробная часть отбрасывается (то есть, значение усекается к нулю). (...) - 6.4.4.2/3: (...) Для десятичных плавающих констант (...) результат является либо ближайшим представимым значением, либо большим или меньшим представимым значением, немедленно примыкающим к ближайшему представляемое значение, выбранное в соответствии с реализацией. (...)
15.6
в примере не получил точное представление в IEEE двойной, так что я бы за исключением d
, чтобы получить что-то чуть выше или чуть ниже. Проблема заключается в части «чуть ниже», тогда i
в этом примере не получит результат, который был бы исключен (вместо этого получился бы 155
).
Мой очевидно взять бы что-то вроде этого (с учетом нулевой или только положительные значения):
i = (int)(d * 10.0 + 0.5);
По крайней мере, если я интерпретировал стандарт C правильно. Я спрашиваю, потому что из-за «поведения, определенного реализацией», можно получить согласованный результат, в то время как в реальности какая-то другая реализация может нарушить работу программы, поэтому проб и ошибок не является адекватным методом поиска подходящего решения.
В частности the following question связывает эту проблему, которая, как я считаю, имеет неверный принятый ответ.
В стандарте C не предусматривается использование плавающей точки IEEE. Теоретически возможно, что 'd' представляется как некоторое безумное число, например' 15.65'. Это становится гораздо более вероятным, так как 'd' становится больше. Я бы сказал, что 'd' уже не так, и вы должны использовать библиотеку произвольной точности с самого начала. – Kevin
@Kevin: Я только что упомянул IEEE, поскольку даже в IEEE этот пример показывает проблему. Если вы бросите «тяжелую артиллерию», строго придерживающуюся формулировки стандарта C, конечно, у вас скоро будет не только одна большая зияющая дыра. Библиотека произвольной точности может быть не всегда осуществимой, например, включить внедренную цель. – Jubatian
Ну, тогда вам нужно решить, что вы цените больше: производительность или правильность? – Kevin