r — округление удваивается до n десятичных знаков, используя «округление до четного»; в переполнении стека

Я хочу реализовать функцию в C ++:

double round_to_even(double num, int decimal_places);

/* rounds the first argument to three decimal places
using round-to-even (unbiased rounding) */

который ведет себя так, как работает округление в R, используя метод, известный как округление до четного, непредвзятое округление или округление статистики:
https://stat.ethz.ch/R-manual/R-devel/library/base/html/Round.html
Лучший способ проиллюстрировать это на нескольких примерах из R, где decimal_place = 3:

> round(0.1247,3) # rounding the first argument to three decimal places
[1] 0.125

> round(0.1244,3)
[1] 0.124

Обратите внимание на то, как он ведет себя так, как и следовало ожидать, округляя в большую сторону, когда цифра справа от указанного десятичного_значения больше 5 (здесь равно 7), и обрезая, когда она меньше 5 (здесь равна 4). Однако, когда цифра справа от указанного decimal_place равна 5 (или в «средней точке»), она ведет себя следующим образом:

> round(0.1255,3) # will round up
[1] 0.126

> round(.1275,3) # will round up
[1] 0.128

> round(0.1265,3) # will truncate
[1] 0.126

> round(0.1245,3) # will truncate
[1] 0.124

путем округления, когда цифра слева от decimal_place нечетная, и усечения, когда четная.

Есть ли краткий способ реализовать это, и в частности без преобразования цифр в символы?

Редактировать:
Это лучшее, что я мог придумать:

double round_to_even(double number, int decimal_points)
/* rounds the first argument to three decimal places
using round-to-even (unbiased rounding) */
{
double num_left = number, num_right = number;
int digit_left, digit_right;

num_left *= pow(10, decimal_points + 1);
digit_left = fmod(num_left, 10);

if (digit_left == 5)
{
num_right *= pow(10, decimal_points);
digit_right = fmod(num_right, 10);

if (digit_right % 2 == 0) // if even
return floor(number * pow(10, decimal_points)) / pow(10, decimal_points);
else // otherwise it's odd
return ceil(number * pow(10, decimal_points)) / pow(10, decimal_points);
}
else { // standard round-to-nearest
return round(number * pow(10, decimal_points)) / pow(10, decimal_points);
}
}

И я проверил это:

std::vector<double> test_vector({ 0.1247, 0.1244, 0.1255, 0.1275, 0.1265, 0.1245 });
std::vector<double> expected_values({ 0.125, 0.124, 0.126, 0.128, 0.126, 0.124 });

for (std::vector<double>::size_type i = 0; i < test_vector.size(); i++)
std::cout << "expected: " << expected_values[i] << "\t got: " << round_to_even(test_vector[i], 3) << std::endl;

Что дает следующий вывод:

expected: 0.125  got: 0.125
expected: 0.124  got: 0.124
expected: 0.126  got: 0.126
expected: 0.128  got: 0.128
expected: 0.126  got: 0.126
expected: 0.124  got: 0.124

-1

Решение

double round(double d, int n) {
double last = d * pow(10, n + 1);
int last_dig = floor(last) % 10;
if (last_dig != 5)
return reg_round(d, n); //round as normal

double pre_last = d * pow(10, n);
int pre_last_dig = floor(pre_last) % 10;
if (pre_last_dig %2 == 0)
return floor(d,n); //last digit is even, floor.
else
return ceil(d,n); //last digit is odd, ceil.
}

Если предположить, reg_round нормальный раунд.

1

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector