Об остатке от деления и округлении до числа, кратного чему-то...
Изначально нужно было округлять целые числа (обозначим одно число 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 просмотров]