Я хотел бы использовать для вычислений первые пять цифр числа.
Обычно числа с плавающей запятой кодируются с использованием двоичного кода, и OP хочет использовать 5 значащих десятичных цифр. Это проблематично, поскольку числа типа 4.23654897E-05
и 4.2365E-05
не точно представлены как float/double
. Лучшее, что мы можем сделать, это подойти поближе.
Подход floor*()
имеет проблемы с 1) отрицательными числами (следовало использовать trunc()
) и 2) значениями около x.99995
, которые во время округления могут изменить количество цифр. Я настоятельно рекомендую не использовать его здесь, так как такие решения, использующие его, терпят неудачу во многих угловых случаях.
Подход *10000 * power10
, round, /(10000 * power10)
страдает 1) power10
вычислением (в данном случае 1e5) 2) ошибками округления в кратном, 3) потенциалом переполнения. Необходимый power10
может быть неточным. *
ошибки появляются в тех случаях, когда продукт близок к xxxxx.5
. Часто этот промежуточный расчет выполняется с использованием более широкой double
математики, поэтому угловые случаи редки. Плохое округление с использованием (some_int_type)
, имеющего ограниченный диапазон и являющегося усечением вместо лучших round()
или rint()
.
Подход, который приближается к цели OP: вывести до 5 значащих цифр с помощью %e
и преобразовать обратно. Не очень эффективен, но хорошо справляется со всеми случаями.
int main(void) {
float num = 4.23654897E-05f;
// sign d . dddd e sign expo + \0
#define N (1 + 1 + 1 + 4 + 1 + 1 + 4 + 1)
char buf[N*2]; // Use a generous buffer - I like 2x what I think is needed.
// OP wants 5 significant digits so print 4 digits after the decimal point.
sprintf(buf, "%.4e", num);
float rounded = (float) atof(buf);
printf("%.5e %s\n", rounded, buf);
}
Вывод
4.23650e-05 4.2365e-05
Почему 5 в %.5e
: Обычно float
выводит до 6 значащих десятичных цифр, как и ожидалось (исследование FLT_DIG
), поэтому печатаются 5 цифр после десятичной точки. точное значение rounded
в этом случае было около 4.236500171...e-05
, так как 4.2365e-05 не может быть точно представлен как float
.
person
chux - Reinstate Monica
schedule
30.01.2018
4.23654897E-05
не является числом с плавающей запятой и не может быть точно представлен в виде числа с плавающей запятой одинарной точности (который имеет только ~ 7 цифр точности) - person phuclv   schedule 30.01.20184.23654897E-05*10000
и объясните, почему, по вашему мнению,floor
следует округлить так, как вы хотите. - person n. 1.8e9-where's-my-share m.   schedule 30.01.20184.23654897E-05
в первую очередь ... - person Lundin   schedule 30.01.2018num = 5.123499E-05
, вы хотите, чтобы результат был примерно5.1234E-05f
или5.1235E-05
? - person chux - Reinstate Monica   schedule 30.01.2018