Создание обобщенной функции округления в C
Большинство вопросов округления по переполнению стека касаются конкретных случаев, и, поскольку я только что сделал общую функцию округления, я решил поделиться ею.
У меня есть число f, начальное значение a и приращение b, и я хочу "округлить" f до ближайшего элемента множества { a + b • i | я целое число}. Например:
a
знак равно0.0
,b
знак равно0.5
: округлить до одного из значений0.0
,0.5
,1.0
,1.5
, так далее.a
знак равно0.25
,b
знак равно0.5
: округлить до одного из значений0.25
,0.75
,1.25
,1.75
, так далее.a
знак равно0.21
,b
знак равно0.23
: округлить до одного из значений0.21
,0.44
,0.67
,0.80
, так далее.
Стандартная библиотека C имеет roundf()
но это только округляет до ближайшего целого числа.
Как мне это сделать?
1 ответ
#include <stdio.h>
#include <math.h>
float round_float(float x, float inc, float start_val)
{
return ( roundf( (x - start_val) / inc ) * inc + start_val );
}
int main(void)
{
printf("%f\n", round_float(12.522, 0.5, 0));
printf("%f\n", round_float(12.522, -0.5, -0.1));
printf("%f\n", round_float(5.318, 0.23, 125));
printf("%f\n", round_float(-12.522, 12, 5));
printf("%f\n", round_float(-12.522, 3.6, -2));
}
выход:
12.500000
12.400000
5.400002
-7.000000
-12.799999
первый пример: round_float(10.1521, 0.5, 0)
Второй пример: round_float(10.1521, 0.5, 0.25)
последний пример: round_float(10.1521, 0.23, 0.21)
Расширенный пример
Этот код показывает, как значения случайной выборки округляются до ближайшей записи в каждой из трех последовательностей, указанных начальным значением и приращением - с использованием значений, указанных в вопросе.
#include <stdio.h>
#include <math.h>
static inline float round_float(float x, float inc, float start_val)
{
return roundf((x - start_val) / inc) * inc + start_val;
}
int main(void)
{
printf("%f\n", round_float(12.522, 0.5, 0));
printf("%f\n", round_float(12.522, -0.5, -0.1));
printf("%f\n", round_float(5.318, 0.23, 125));
printf("%f\n", round_float(-12.522, 12, 5));
printf("%f\n", round_float(-12.522, 3.6, -2));
static const float samples[] =
{
-14.2751, -12.3080, -10.5320, -6.4804, -1.0859,
0.1999, 0.2099, 5.2980, 5.7819, 11.7052,
};
enum { NUM_SAMPLES = sizeof(samples) / sizeof(samples[0]) };
static const float control[][2] =
{
{ 0.00, 0.50 },
{ 0.25, 0.50 },
{ 0.21, 0.23 },
};
enum { NUM_CONTROL = sizeof(control) / sizeof(control[0]) };
for (int i = 0; i < NUM_CONTROL; i++)
{
float a = control[i][0];
float b = control[i][1];
printf("Start: %8.4f; increment %8.4f\n", a, b);
for (int j = 0; j < NUM_SAMPLES; j++)
{
printf(" Sample: %8.4f rounds to %8.4f\n",
samples[j], round_float(samples[j], b, a));
}
}
return 0;
}
Пример вывода:
12.500000
12.400000
5.400002
-7.000000
-12.799999
Start: 0.0000; increment 0.5000
Sample: -14.2751 rounds to -14.5000
Sample: -12.3080 rounds to -12.5000
Sample: -10.5320 rounds to -10.5000
Sample: -6.4804 rounds to -6.5000
Sample: -1.0859 rounds to -1.0000
Sample: 0.1999 rounds to 0.0000
Sample: 0.2099 rounds to 0.0000
Sample: 5.2980 rounds to 5.5000
Sample: 5.7819 rounds to 6.0000
Sample: 11.7052 rounds to 11.5000
Start: 0.2500; increment 0.5000
Sample: -14.2751 rounds to -14.2500
Sample: -12.3080 rounds to -12.2500
Sample: -10.5320 rounds to -10.7500
Sample: -6.4804 rounds to -6.2500
Sample: -1.0859 rounds to -1.2500
Sample: 0.1999 rounds to 0.2500
Sample: 0.2099 rounds to 0.2500
Sample: 5.2980 rounds to 5.2500
Sample: 5.7819 rounds to 5.7500
Sample: 11.7052 rounds to 11.7500
Start: 0.2100; increment 0.2300
Sample: -14.2751 rounds to -14.2800
Sample: -12.3080 rounds to -12.2100
Sample: -10.5320 rounds to -10.6000
Sample: -6.4804 rounds to -6.4600
Sample: -1.0859 rounds to -1.1700
Sample: 0.1999 rounds to 0.2100
Sample: 0.2099 rounds to 0.2100
Sample: 5.2980 rounds to 5.2700
Sample: 5.7819 rounds to 5.7300
Sample: 11.7052 rounds to 11.7100
Я уверен, что более разумный выбор значений выборки сделает это еще яснее; это просто набор случайных чисел в диапазоне -20.. +20 в отсортированном порядке.
Извините за дополнительный уровень отступа в последнем примере. Предварительный просмотр не показывал "код", когда не было отступа в два уровня, и я понятия не имею, почему. (Конфигурация: Firefox Quantum 57.0.1 (ожидается перезапуск) в macOS High Sierra 10.13.2 и SO 2017.12.22.28257)