БлогNot. Об остатке от деления и округлении до числа, кратного чему-то...

Об остатке от деления и округлении до числа, кратного чему-то...

Изначально нужно было округлять целые числа (обозначим одно число n) вверх или вниз до ближайших значений, кратных некоторому целому k. Например, при n=27, k=20 получится 40 при округлении вверх и 20 при округлении вниз.

Естественный и простой код типа

if (n%k) n = (n/k)*k+k; //вверх
if (n%k) n = (n/k)*k; //вниз

которого полно в инете, практически весь неправильный. Дело в том, что нигде не сказано, что n и k обязаны быть положительными, а операция % (остаток от деления) в C++ сама по себе реализована некорректно, например, мой Studio выдаёт следующие результаты:

 10 %  3 =  1
-10 %  3 = -1
 10 % -3 =  1
-10 % -3 = -1

В стандарте по этому поводу написано вот что:

If both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined.

Поэтому более-менее надёжной представляется реализация, которая использует не остаток от деления, а модуль от него, взятый, скажем, стандартной функцией abs. Вот функции для корректного округления и тестовая программка:

#include <locale.h>
#include <windows.h>
#include <iostream>
#include <cmath>
using namespace std;

//Округлить целое n вверх до ближайшего целого числа, кратного k
int ceil_mod (int n, int k) {
 if (!k) return 0;
 int tmp = abs(n%k);
 if (tmp) n += (n>-1 ? (abs(k)-tmp) : (tmp));
 return n;
}

//Округлить целое n вниз до ближайшего целого числа, кратного k
int floor_mod (int n, int k) {
 if (!k) return 0;
 int tmp = abs(n%k);
 if (tmp) n -= (n>-1 ? (tmp) : (abs(k)-tmp));
 return n;
}

int main() { 
 setlocale(LC_ALL,"Rus"); SetConsoleCP(1251); SetConsoleOutputCP(1251);
 
 cout << endl << "ceil_mod(27,20)=" << ceil_mod(27,20);
 cout << endl << "ceil_mod(-134,40)=" << ceil_mod(-134,40);
 cout << endl << "ceil_mod(10,-3)=" << ceil_mod(10,-3);
 cout << endl << "ceil_mod(-35,-4)=" << ceil_mod(-35,-4); 
 cout << endl << "floor_mod(27,20)=" << floor_mod(27,20);
 cout << endl << "floor_mod(-134,40)=" << floor_mod(-134,40);
 cout << endl << "floor_mod(10,-3)=" << floor_mod(10,-3);
 cout << endl << "floor_mod(-16,-5)=" << floor_mod(-16,-5);
 cin.sync(); cin.get();  return 0;
}

28.01.2016, 19:11 [5769 просмотров]


теги: c++ ошибка числа алгоритм

К этой статье пока нет комментариев, Ваш будет первым