Чтобы округлить в С в float
, есть 3 <math.h>
функции для удовлетворения потребности. Рекомендовать rintf()
.
float nearbyintf(float x);
В nearbyint
функции вокруг своего аргумента целого значения в формате с плавающей точкой, используя текущее направление округления и без повышения „неточного“ «» исключения с плавающей точкой. C11dr §7.12.9.3 2
или
float rintf(float x);
В rint
функции отличаются от nearbyint
функций (7.12.9.3) только в том, что rint
функции могут поднимать '' неточное» «исключение с плавающей точкой», если результат отличается от значения аргументом. C11dr §7.12.9.4 2
или
float roundf(float x);
В round
функции круглого аргумента до ближайшего целого значения в формате с плавающей точкой, округление случаи на полпути от нуля, независимо от того, текущее направление округления. C11dr §7.12.9.6 2
Пример
#include <fenv.h>
#include <math.h>
#include <stdio.h>
void rtest(const char *fname, double (*f)(double x), double x) {
printf("Clear inexact flag :%s\n", feclearexcept(FE_INEXACT) ? "Fail" : "Success");
printf("Set round to nearest mode:%s\n", fesetround(FE_TONEAREST) ? "Fail" : "Success");
double y = (*f)(x);
printf("%s(%f) --> %f\n", fname,x,y);
printf("Inexact flag :%s\n", fetestexcept(FE_INEXACT) ? "Inexact" : "Exact");
puts("");
}
int main(void) {
double x = 8.5;
rtest("nearbyint", nearbyint, x);
rtest("rint", rint, x);
rtest("round", round, x);
return 0;
}
Выход
Clear inexact flag :Success
Set round to nearest mode:Success
nearbyint(8.500000) --> 8.000000
Inexact flag :Exact
Clear inexact flag :Success
Set round to nearest mode:Success
rint(8.500000) --> 8.000000
Inexact flag :Inexact
Clear inexact flag :Success
Set round to nearest mode:Success
round(8.500000) --> 9.000000
Inexact flag :Exact
Что слаб о коде OP в?
(int)(num < 0 ? (num - 0.5) : (num + 0.5))
Должен num
иметь значение не вблизи int
диапазона, литые (int)
результатов в непредсказуемом поведении.
Когда num +/- 0.5
приводит к неточному ответу. Здесь маловероятно, что 0.5
является double
, в результате чего добавление происходит с большей точностью, чем float
. Когда num
и 0.5
имеют одинаковую точность, добавление 0.5
к числу может привести к числовое округленное ответ. (Это не целое число округления позиции OP.) Пример: число, равное менее 0,5, должно округляться до 0 на цель OP, но num + 0.5
приводит к точному ответу между 1.0 и наименьшим double
всего менее 1.0. Поскольку точный ответ не является представимым, эта сумма округляется, как правило, до 1.0, приводя к неправильному ответу. Аналогичная ситуация имеет место с большими числами.дилемма
OP о "Эта строка всегда печатает значение как 4, даже когда float num =4.9
." не объяснимо, как указано. Требуется дополнительный код/информация. Я подозреваю, что ОП мог использовать int num = 4.9;
.
// avoid all library calls
// Relies on UINTMAX_MAX >= FLT_MAX_CONTINUOUS_INTEGER - 1
float my_roundf(float x) {
// Test for large values of x
// All of the x values are whole numbers and need no rounding
#define FLT_MAX_CONTINUOUS_INTEGER (FLT_RADIX/FLT_EPSILON)
if (x >= FLT_MAX_CONTINUOUS_INTEGER) return x;
// Positive numbers
// Important: _no_ precision lost in the subtraction
// This is the key improvement over OP's method
if (x > 0) {
float floor_x = (float)(uintmax_t) x;
if (x - floor_x >= 0.5) floor_x += 1.0f;
return floor_x;
}
if (x < 0) return -my_roundf(-x);
return x; // x is 0.0, -0.0 or NaN
}
Испытано мало - будет делать это позже, когда у меня есть время.
Существует много разных типов округления - какие (ы) вы хотите использовать? Пожалуйста, разместите примеры желаемого поведения. – 2010-04-03 10:24:43
Я думаю, что проблема в другом месте, это должно обязательно напечатать 5 для ввода 4.9. – IVlad
Да, преобразование типа с плавающей точкой в целочисленный тип, который может представлять собой число требуемой подписи и величины, должно работать просто путем усечения десятичных знаков; этот код делает ± 0.5, чтобы заставить это усечение округлить исходное значение от нуля. – Arkku