Есть ли функция для округления числа с плавающей точкой в C или мне нужно написать свою собственную?
-
20-08-2019 - |
Вопрос
Есть ли функция для округления числа с плавающей точкой в C или мне нужно написать свою собственную?
значение с плавающей запятой = 45.592346543;
Я хотел бы округлить фактическое значение до одного знака после запятой, conver = 45.6.
Решение
Как упоминал Роб, вы, вероятно, просто хотите Печать значение с плавающей точкой до 1 знака после запятой.В этом случае вы можете сделать что-то вроде следующего:
#include <stdio.h>
#include <stdlib.h>
int main()
{
float conver = 45.592346543;
printf("conver is %0.1f\n",conver);
return 0;
}
Если вы действительно хотите округлить сохраненное значение, это немного сложнее.Во-первых, ваше представление с одним десятичным знаком редко будет иметь точный аналог в формате с плавающей запятой.Если вы просто хотите подобраться как можно ближе, что-то вроде этого может сработать:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
float conver = 45.592346543;
printf("conver is %0.1f\n",conver);
conver = conver*10.0f;
conver = (conver > (floor(conver)+0.5f)) ? ceil(conver) : floor(conver);
conver = conver/10.0f;
//If you're using C99 or better, rather than ANSI C/C89/C90, the following will also work.
//conver = roundf(conver*10.0f)/10.0f;
printf("conver is now %f\n",conver);
return 0;
}
Я сомневаюсь, что этот второй пример - то, что вы ищете, но я включил его для полноты картины.Если вам действительно требуется представлять свои числа таким образом внутренне, а не только на выходе, рассмотрите возможность использования представление с фиксированной точкой вместо этого.
Другие советы
Конечно, вы можете использовать roundf() раунд().Если вы хотите округлить до одного знака после запятой, то вы могли бы сделать что-то вроде: roundf(10 * x) / 10
#include <math.h>
double round(double x);
float roundf(float x);
Не забудьте установить ссылку на -lm.Смотрите также ceil(), floor() и trunc().
Просто чтобы немного обобщить ответ Роба, если вы не делая это на выходе, вы все еще можете использовать тот же интерфейс с sprintf()
.
Однако я думаю, что есть другой способ сделать это.Вы можете попробовать ceil()
и floor()
округлять вверх и вниз.Хороший трюк заключается в добавлении 0,5, так что все, что больше 0,5, округляется в большую сторону, а все, что меньше, - в меньшую. ceil()
и floor()
работайте только над double
хотя.
Редактировать:Кроме того, для поплавков вы можете использовать truncf()
для усечения поплавков.Тот же самый прием + 0,5 должен сработать для точного округления.
Существует round()
функция, также fround()
, который будет округлен до ближайшего целого числа, выраженного в виде double.Но это не то, чего вы хотите.
У меня была такая же проблема, и я написал это:
#include <math.h>
double db_round(double value, int nsig)
/* ===============
**
** Rounds double <value> to <nsig> significant figures. Always rounds
** away from zero, so -2.6 to 1 sig fig will become -3.0.
**
** <nsig> should be in the range 1 - 15
*/
{
double a, b;
long long i;
int neg = 0;
if(!value) return value;
if(value < 0.0)
{
value = -value;
neg = 1;
}
i = nsig - log10(value);
if(i) a = pow(10.0, (double)i);
else a = 1.0;
b = value * a;
i = b + 0.5;
value = i / a;
return neg ? -value : value;
}
Для Печать округленное значение, @Мэтт Джей хорошо отвечает на вопрос.
float x = 45.592346543;
printf("%0.1f\n", x); // 45.6
Поскольку большая часть значений с плавающей запятой (FP) равна бинарный основанный, точный округление до единицы десятичная дробь место невозможно, когда математически правильный ответ равен x.1, x.2, ...
.
Чтобы преобразовать номер FP в ближайший 0.1
это другое дело.
Переполнение:Подходы, которые сначала масштабируются на 10 (или 100, 1000 и т.д.), Могут переполняться при больших x
.
float round_tenth1(float x) {
x = x * 10.0f;
...
}
Двойное округление:Добавляя 0,5 f, а затем используя floorf(x*10.0f + 0.5f)/10.0
возвращает неверный результат, когда промежуточная сумма x*10.0f + 0.5f
округляет до нового целого числа.
// Fails to round 838860.4375 correctly, comes up with 838860.5
// 0.4499999880790710449 fails as it rounds to 0.5
float round_tenth2(float x) {
if (x < 0.0) {
return ceilf(x*10.0f + 0.5f)/10.0f;
}
return floorf(x*10.0f + 0.5f)/10.0f;
}
Кастинг Для int
имеет очевидную проблему, когда float x
намного больше , чем INT_MAX
.
Используя roundf()
и семья, доступные в <math.h>
это наилучший подход.
float round_tenthA(float x) {
double x10 = 10.0 * x;
return (float) (round(x10)/10.0);
}
Чтобы избежать использования double
, просто проверьте, нуждается ли число в округлении.
float round_tenthB(float x) {
const float limit = 1.0/FLT_EPSILON;
if (fabsf(x) < limit) {
return roundf(x*10.0f)/10.0f;
}
return x;
}
вы можете использовать #define round(a) (int) (a + 0.5) в качестве макроса поэтому всякий раз, когда вы пишете round(1.6), он возвращает 2, а всякий раз, когда вы пишете round (1.3), он возвращает 1.