C ++: округление до ближайшего кратного числа

168

Хорошо - я почти смущен, когда публикую это здесь (и я буду удалять, если кто-то проголосует за закрытие), поскольку это кажется основным вопросом.

Это правильный способ округлить до кратного числа в C ++?

Я знаю, что есть другие вопросы, связанные с этим, но мне особенно интересно узнать, как лучше всего это сделать в C ++:

int roundUp(int numToRound, int multiple)
{
 if(multiple == 0)
 {
  return numToRound;
 }

 int roundDown = ( (int) (numToRound) / multiple) * multiple;
 int roundUp = roundDown + multiple; 
 int roundCalc = roundUp;
 return (roundCalc);
}

Обновление: Извините, я, вероятно, не прояснил намерение. Вот некоторые примеры:

roundUp(7, 100)
//return 100

roundUp(117, 100)
//return 200

roundUp(477, 100)
//return 500

roundUp(1077, 100)
//return 1100

roundUp(52, 20)
//return 60

roundUp(74, 30)
//return 90
Robben_Ford_Fan_boy
источник
3
В вашей логике есть ошибка - допустим, я хочу округлить 4 до ближайшего кратного 2. roundDown = (4/2) * 2 = 4; roundUp = 4 + 2; поэтому roundCalc = 6. Я предполагаю, что вы захотите вернуть 4 в этом случае.
Ники Йошиути
это не работает для раунда (30,30). Он дает 60 в качестве ответа, он все равно должен давать 30 в качестве ответа ..
bsobaid
@bsobaid: Проверьте мой ответ внизу. Здесь это немного проще, чем другие решения, хотя они тоже должны работать
Niklas B.
3
В ваших тестовых примерах явно отсутствуют примеры, включающие отрицательные числа, случаи, когда деление является точным, случаи, когда деление является почти точным, и случаи, когда числа очень близки к пределам диапазона int.
1
Robben_Ford_Fan_boy, редактирование с ответом, на который вы пошли, должно быть удалено. Если он отличается от данных ответов, вы можете опубликовать свой собственный ответ. На самом деле, у этого ответа есть проблемы, которые должны быть рассмотрены в разделе ответов.
chux - Восстановить Монику

Ответы:

161

Это работает для положительных чисел, а не для отрицательных. Используется только целочисленная математика.

int roundUp(int numToRound, int multiple)
{
    if (multiple == 0)
        return numToRound;

    int remainder = numToRound % multiple;
    if (remainder == 0)
        return numToRound;

    return numToRound + multiple - remainder;
}

Редактировать: вот версия, которая работает с отрицательными числами, если под «вверх» вы подразумеваете результат, который всегда> = ввод.

int roundUp(int numToRound, int multiple)
{
    if (multiple == 0)
        return numToRound;

    int remainder = abs(numToRound) % multiple;
    if (remainder == 0)
        return numToRound;

    if (numToRound < 0)
        return -(abs(numToRound) - remainder);
    else
        return numToRound + multiple - remainder;
}
Марк Рэнсом
источник
+1 На мой взгляд, определенно самое хорошее и читаемое решение.
Robben_Ford_Fan_boy
1
Добавьте if(number<0){ multiple = multiple*(-1); }в начале, чтобы округлить отрицательные числа в правильном направлении
Джош
4
@Josh: зачем использовать умножение? if(number<0) multiple = -multipleэто легче.
md5
это не работает для раунда (30,30). Он дает 60 в качестве ответа, он все равно должен давать 30 в качестве ответа.
bsobaid
@bsobaid невозможно. if (remainder == 0)Тест должен позаботиться о таком случае. Это работает для меня: ideone.com/Waol7B
Марк Рэнсом
115

Без условий:

int roundUp(int numToRound, int multiple) 
{
    assert(multiple);
    return ((numToRound + multiple - 1) / multiple) * multiple;
}

Это работает как округление от нуля для отрицательных чисел

РЕДАКТИРОВАТЬ: версия, которая работает также для отрицательных чисел

int roundUp(int numToRound, int multiple) 
{
    assert(multiple);
    int isPositive = (int)(numToRound >= 0);
    return ((numToRound + isPositive * (multiple - 1)) / multiple) * multiple;
}

тесты


Если multipleэто степень 2 (быстрее в ~ 3,7 раза http://quick-bench.com/sgPEZV9AUDqtx2uujRSa3-eTE80 )

int roundUp(int numToRound, int multiple) 
{
    assert(multiple && ((multiple & (multiple - 1)) == 0));
    return (numToRound + multiple - 1) & -multiple;
}

тесты

KindDragon
источник
24
+1 за мощность 2 версии. Очень полезно, так как полностью исключает стоимость умножения, деления или по модулю.
Никос С.
Вы уверены, что у этих алгоритмов нет предварительных условий? А как насчет отрицательных чисел? Поведение кажется неопределенным в пре-C ++ 11 .
cubuspl42
> А как насчет отрицательных чисел? Как описано, это работает для отрицательных чисел, таких как округление от нуля.
Добрый Драгон
Я читаю «округление» как означающее округление до положительной бесконечности, а не округление от нуля.
8
Обратите внимание, что & ~(x - 1)это то же самое, что и & -xдля арифметики дополнения до двух.
Тодд Леман
39

Это работает, когда фактор всегда будет положительным:

int round_up(int num, int factor)
{
    return num + factor - 1 - (num - 1) % factor;
}

Редактировать: это возвращается round_up(0,100)=100. Пожалуйста, смотрите комментарий Павла ниже для решения, которое возвращается round_up(0,100)=0.

XLQ
источник
1
Выглядит как самый короткий случай, который обрабатывает случай «уже кратный».
Harningt
1
Лучшее решение с точки зрения количества дорогостоящих операций. Он использует только одно деление и без умножения
Никлас Б.
3
round_up (0, 100) == 100 вместо 0, как в принятом ответе
Грегори
7
Не должно ли это быть num + factor - 1 - (num + factor - 1) % factor?
Пол
6
num - 1 - (num - 1) % factor + factorвыполняет те же вычисления без риска переполнения целых чисел.
24

Это обобщение проблемы «как узнать, сколько байтов будет занимать n бит?» (A: (n бит + 7) / 8).

int RoundUp(int n, int roundTo)
{
    // fails on negative?  What does that mean?
    if (roundTo == 0) return 0;
    return ((n + roundTo - 1) / roundTo) * roundTo; // edit - fixed error
}
плинтус
источник
1
Это не округляется до следующего кратного числа.
aaaa bbbb
7
Мне нравится это решение, потому что если roundTo будет степенью 2, вы можете исключить / и * и в итоге ничего не делать, кроме дешевых операций (x = roundTo - 1; return (n + x) & ~ x;)
Trejkaz
@ Трейказ Нету. Должно быть так, (x = roundTo - 1; return (n+x)&~roundTo;)как в моем ответе
KindDragon
@KindDragon, который дает неправильный результат для меня, но если я исправлю его, сказав ~ x вместо ~ roundTo, я получу ожидаемый результат. На Яве 8 все равно.
Трейказ
@KindDragon: Маска AND должна быть 0xFFF...000, а не 0xFFF7FFFили чем-то, поэтому вы хотите либо отрицание дополнения 2 ( -: минус) со степенью 2, либо переворот на единицу меньше степени 2 (обратное дополнение дополнения ~: tilde не минус). Так (n+x) & ~xили (n-roundTo+1) & -roundTo.
Питер Кордес
14
int roundUp(int numToRound, int multiple)
{
 if(multiple == 0)
 {
  return 0;
 }
 return ((numToRound - 1) / multiple + 1) * multiple;  
}

И не надо возиться с условиями

Дорон
источник
11

Для тех, кто ищет короткий и сладкий ответ. Это то, что я использовал. Нет учета негативов.

n - (n % r)

Это вернет предыдущий фактор.

(n + r) - (n % r)

Вернется следующий. Надеюсь, это кому-нибудь поможет. :)

Арон-связь
источник
9
float roundUp(float number, float fixedBase) {
    if (fixedBase != 0 && number != 0) {
        float sign = number > 0 ? 1 : -1;
        number *= sign;
        number /= fixedBase;
        int fixedPoint = (int) ceil(number);
        number = fixedPoint * fixedBase;
        number *= sign;
    }
    return number;
}

Это работает для любого числа с плавающей точкой или базы (например, вы можете округлить -4 до ближайшего 6,75). По сути это преобразование в фиксированную точку, округление там, а затем обратное преобразование. Он обрабатывает негативы, округляя AWAY от 0. Он также обрабатывает отрицательный раунд до значения, по сути превращая функцию в roundDown.

Специфичная для int версия выглядит так:

int roundUp(int number, int fixedBase) {
    if (fixedBase != 0 && number != 0) {
        int sign = number > 0 ? 1 : -1;
        int baseSign = fixedBase > 0 ? 1 : 0;
        number *= sign;
        int fixedPoint = (number + baseSign * (fixedBase - 1)) / fixedBase;
        number = fixedPoint * fixedBase;
        number *= sign;
    }
    return number;
}

Что является более или менее ответом плинтуса с добавленной отрицательной поддержкой ввода.

дельфин
источник
Я протестировал код с плавающей запятой с двойным, он работает для меня. Действительно решает мою проблему.
Ашиф
1
Как насчет double round(double value, double multiple) { double sign = value; multiple = std::copysign(multiple, 1.0); value = std::copysign(value, 1.0); return std::copysign(multiple * std::ceil(value / multiple), sign); }Или поменять потолок на раунд, чтобы получить округление.
Тройсеф,
8

Это современный подход c ++, использующий шаблонную функцию, которая работает для float, double, long, int и short (но не для long long и long double из-за используемых значений double).

#include <cmath>
#include <iostream>

template<typename T>
T roundMultiple( T value, T multiple )
{
    if (multiple == 0) return value;
    return static_cast<T>(std::round(static_cast<double>(value)/static_cast<double>(multiple))*static_cast<double>(multiple));
}

int main()
{
    std::cout << roundMultiple(39298.0, 100.0) << std::endl;
    std::cout << roundMultiple(20930.0f, 1000.0f) << std::endl;
    std::cout << roundMultiple(287399, 10) << std::endl;
}

Но вы можете легко добавить поддержку long longи long doubleспециализацию шаблонов, как показано ниже:

template<>
long double roundMultiple<long double>( long double value, long double multiple)
{
    if (multiple == 0.0l) return value;
    return std::round(value/multiple)*multiple;
}

template<>
long long roundMultiple<long long>( long long value, long long multiple)
{
    if (multiple == 0.0l) return value;
    return static_cast<long long>(std::round(static_cast<long double>(value)/static_cast<long double>(multiple))*static_cast<long double>(multiple));
}

Чтобы создать функции для округления, используйте std::ceilи всегда округляйте std::floor. Мой пример сверху округляет с помощьюstd::round .

Создайте шаблонную функцию «округление вверх» или более известную как «круглый потолок», как показано ниже:

template<typename T>
T roundCeilMultiple( T value, T multiple )
{
    if (multiple == 0) return value;
    return static_cast<T>(std::ceil(static_cast<double>(value)/static_cast<double>(multiple))*static_cast<double>(multiple));
}

Создайте шаблонную функцию «круглый вниз» или более известную как «круглый пол», как показано ниже:

template<typename T>
T roundFloorMultiple( T value, T multiple )
{
    if (multiple == 0) return value;
    return static_cast<T>(std::floor(static_cast<double>(value)/static_cast<double>(multiple))*static_cast<double>(multiple));
}
Flovdis
источник
1
плюс 1, хотя некоторые люди могут счесть более разумным возвращать 0, когда множитель == 0
stijn
3
Осторожно, потому что преобразование int64_t в double может привести к потерям, поэтому оно не так типично, как может показаться.
Эдриан Маккарти
@AdrianMcCarthy Да, вы должны создать правильную специализацию шаблона, как показано выше. Как видите, я реализую две дополнительные функции для long longи long double. То же самое должно быть сделано для двух других функций, очевидно.
Flovdis
Я думаю, что это, безусловно, самый медленный из всех, но это не должно быть. Все, что вам нужно сделать, это std :: enable_if_t и сделать две ветви для целых чисел и чисел с плавающей точкой. Вы также можете лучше использовать numeric_limits и посмотреть, достаточно ли велика мантисса, чтобы соответствовать значению. Это добавило бы к безопасности.
свинья
5

Во-первых, ваше условие ошибки (множественное == 0) должно иметь возвращаемое значение. Какой? Я не знаю. Может быть, вы хотите выбросить исключение, это зависит от вас. Но возвращать ничего не опасно.

Во-вторых, вы должны проверить, что numToRound уже не кратен. В противном случае, когда вы добавляете multipleвroundDown , вы получите неправильный ответ.

В-третьих, ваши высказывания неверны. Вы бросилиnumToRound приводите к целому числу, но это уже целое число. Вам нужно привести к удвоению до деления и обратно к int после умножения.

Наконец, что вы хотите для отрицательных чисел? Округление «вверх» может означать округление до нуля (округление в том же направлении, что и положительные числа) или от нуля («большее» отрицательное число). Или, может быть, вам все равно.

Вот версия с первыми тремя исправлениями, но я не имею дело с отрицательной проблемой:

int roundUp(int numToRound, int multiple)
{
 if(multiple == 0)
 {
  return 0;
 }
 else if(numToRound % multiple == 0)
 {
  return numToRound
 }

 int roundDown = (int) (( (double) numToRound / multiple ) * multiple);
 int roundUp = roundDown + multiple; 
 int roundCalc = roundUp;
 return (roundCalc);
}
Майк Карон
источник
@ Питер Это так? Я предполагал, int / intчто вернет int, а это не то, что мы хотели.
Майк Карон,
int / int действительно возвращает int, но это именно то, что вы хотите. Например, numToRound = 7, несколько = 3. 7/3 = 2.
Питер Рудерман
4

Округление до степени двойки:

На всякий случай, если кому-то нужно решение для положительных чисел, округленных до ближайшего кратного степени, равной двум (потому что именно так я здесь и оказался):

// number: the number to be rounded (ex: 5, 123, 98345, etc.)
// pow2:   the power to be rounded to (ex: to round to 16, use '4')
int roundPow2 (int number, int pow2) {
    pow2--;                     // because (2 exp x) == (1 << (x -1))
    pow2 = 0x01 << pow2;

    pow2--;                     // because for any
                                //
                                // (x = 2 exp x)
                                //
                                // subtracting one will
                                // yield a field of ones
                                // which we can use in a
                                // bitwise OR

    number--;                   // yield a similar field for
                                // bitwise OR
    number = number | pow2;
    number++;                   // restore value by adding one back

    return number;
}

Введенный номер останется прежним, если он уже кратен.

Вот вывод x86_64, который GCC выдает с помощью -O2или -Os(9Sep2013 Build - Godbolt GCC онлайн):

roundPow2(int, int):
    lea ecx, [rsi-1]
    mov eax, 1
    sub edi, 1
    sal eax, cl
    sub eax, 1
    or  eax, edi
    add eax, 1
    ret

Каждая строка кода C идеально соответствует своей строке в сборке: http://goo.gl/DZigfX

Каждая из этих инструкций очень быстрая , поэтому функция тоже очень быстрая. Поскольку код такой маленький и быстрый, он может быть полезен inlineфункции при его использовании.


Кредит:

haneefmubarak
источник
1
Именно то, что я искал. Спасибо!
Кийо
1
int roundUpPow2 (int num, int pow2) {возвращаемое число + (pow2 - 1) & ~ (pow2 - 1); } примерно на 30% быстрее и проще в использовании (вы передаете 16, а не 4, чтобы округлить до следующего кратного 16.
Аксель Ритщин,
3

Я использую:

template <class _Ty>
inline _Ty n_Align_Up(_Ty n_x, _Ty n_alignment)
{
    assert(n_alignment > 0);
    //n_x += (n_x >= 0)? n_alignment - 1 : 1 - n_alignment; // causes to round away from zero (greatest absolute value)
    n_x += (n_x >= 0)? n_alignment - 1 : -1; // causes to round up (towards positive infinity)
    //n_x += (_Ty(-(n_x >= 0)) & n_alignment) - 1; // the same as above, avoids branch and integer multiplication
    //n_x += n_alignment - 1; // only works for positive numbers (fastest)
    return n_x - n_x % n_alignment; // rounds negative towards zero
}

и для полномочий двух:

template <class _Ty>
bool b_Is_POT(_Ty n_x)
{
    return !(n_x & (n_x - 1));
}

template <class _Ty>
inline _Ty n_Align_Up_POT(_Ty n_x, _Ty n_pot_alignment)
{
    assert(n_pot_alignment > 0);
    assert(b_Is_POT(n_pot_alignment)); // alignment must be power of two
    -- n_pot_alignment;
    return (n_x + n_pot_alignment) & ~n_pot_alignment; // rounds towards positive infinity (i.e. negative towards zero)
}

Обратите внимание, что оба из этих округленных отрицательных значений до нуля (что означает округление до положительной бесконечности для всех значений), ни одно из них не полагается на переполнение со знаком (которое не определено в C / C ++).

Это дает:

n_Align_Up(10, 100) = 100
n_Align_Up(110, 100) = 200
n_Align_Up(0, 100) = 0
n_Align_Up(-10, 100) = 0
n_Align_Up(-110, 100) = -100
n_Align_Up(-210, 100) = -200
n_Align_Up_POT(10, 128) = 128
n_Align_Up_POT(130, 128) = 256
n_Align_Up_POT(0, 128) = 0
n_Align_Up_POT(-10, 128) = 0
n_Align_Up_POT(-130, 128) = -128
n_Align_Up_POT(-260, 128) = -256
свиньи
источник
Я использую ваш с n_Align_Up_POTтех пор, как увидел его в классе Delphi TList. У него есть свои ограничения, такие как выравнивание (кратное), являющееся степенью 2, но это редко является проблемой, потому что я в основном использую его для получения / проверки правильного выравнивания для SMID. Это потрясающе, и, кажется, мало кто знает об этом.
user1593842
2

Вероятно, безопаснее привести к float и использовать ceil () - если только вы не знаете, что деление int даст правильный результат.

Мартин Беккет
источник
1
Обратите внимание, что double может содержать только 54 бита на машинах на базе x86. Если у вас есть 64-битные целые числа, это в конечном итоге потерпит неудачу.
свинья
Стандарт двойного стандарта IEEE754 не может, но процессор x64 имеет 80-битную внутреннюю плавающую точку, поэтому операции над одним числом надежны
Мартин Беккет,
1
Хотя это и так, у вас очень мало контроля над этим округлением из C / C ++. Это зависит от настроек командного слова и может фактически округляться до менее 80 бит. Также у вас есть наборы инструкций SSE и другие SIMD, которые не имеют такого расширенного промежуточного звена (векторизованный компилятор может легко их использовать).
свинья
2
int noOfMultiples = int((numToRound / multiple)+0.5);
return noOfMultiples*multiple

C ++ округляет каждое число вниз, поэтому, если вы добавите 0,5 (если его 1,5, то это будет 2), но 1,49 будет 1,99, следовательно, 1.

РЕДАКТИРОВАТЬ - Извините, не видел, что вы хотели округлить, я бы предложил использовать метод ceil () вместо +0,5

Михал Цехан
источник
2

ну с одной стороны, так как я не очень понимаю, что вы хотите сделать, линии

int roundUp = roundDown + multiple;
int roundCalc = roundUp;
return (roundCalc); 

определенно может быть сокращено до

int roundUp = roundDown + multiple;
return roundUp;
Джесси Наухер
источник
2

может быть, это может помочь:

int RoundUpToNearestMultOfNumber(int val, int num)
{
  assert(0 != num);
  return (floor((val + num) / num) * num);
}
Арсен
источник
Зачем использовать пол и целочисленное деление? Там нет ничего для пола. Если бы оно было двойным, вы могли бы по крайней мере унаследовать обработку отрицательных значений.
свинья
2

Чтобы всегда округлять

int alwaysRoundUp(int n, int multiple)
{
    if (n % multiple != 0) {
        n = ((n + multiple) / multiple) * multiple;

        // Another way
        //n = n - n % multiple + multiple;
    }

    return n;
}

alwaysRoundUp (1, 10) -> 10

alwaysRoundUp (5, 10) -> 10

alwaysRoundUp (10, 10) -> 10


Чтобы всегда округлять

int alwaysRoundDown(int n, int multiple)
{
    n = (n / multiple) * multiple;

    return n;
}

alwaysRoundDown (1, 10) -> 0

alwaysRoundDown (5, 10) -> 0

alwaysRoundDown (10, 10) -> 10


Округлить нормальный путь

int normalRound(int n, int multiple)
{
    n = ((n + multiple/2)/multiple) * multiple;

    return n;
}

normalRound (1, 10) -> 0

normalRound (5, 10) -> 10

normalRound (10, 10) -> 10

onmyway133
источник
2

Округление до ближайшего кратного, который оказывается степенью 2

unsigned int round(unsigned int value, unsigned int multiple){
    return ((value-1u) & ~(multiple-1u)) + multiple;
}

Это может быть полезно при распределении по кеш-линиям, где желаемый прирост округления является степенью двойки, но результирующее значение должно быть только кратным ему. На gccтеле этой функции генерируется 8 инструкций по сборке без деления или ветвей.

round(  0,  16) ->   0
round(  1,  16) ->  16
round( 16,  16) ->  16
round(257, 128) -> 384 (128 * 3)
round(333,   2) -> 334
Энн Куинн
источник
1

Я нашел алгоритм, который несколько похож на тот, который выложен выше:

int [(| x | + n-1) / n] * [(nx) / | x |], где x - это значение, введенное пользователем, а n - это кратное число.

Работает для всех значений x, где x - целое число (положительное или отрицательное, включая ноль). Я написал это специально для программы на C ++, но в принципе это можно реализовать на любом языке.

Джошуа Уэйд
источник
1

Для отрицательного numToRound:

Это должно быть действительно легко, но стандартный оператор по модулю% не обрабатывает отрицательные числа, как можно было бы ожидать. Например, -14% 12 = -2, а не 10. Первое, что нужно сделать, это получить оператор по модулю, который никогда не возвращает отрицательные числа. Тогда раунд действительно прост.

public static int mod(int x, int n) 
{
    return ((x % n) + n) % n;
}

public static int roundUp(int numToRound, int multiple) 
{
    return numRound + mod(-numToRound, multiple);
}
user990343
источник
1

Вот что я бы сделал:

#include <cmath>

int roundUp(int numToRound, int multiple)
{
    // if our number is zero, return immediately
   if (numToRound == 0)
        return multiple;

    // if multiplier is zero, return immediately
    if (multiple == 0)
        return numToRound;

    // how many times are number greater than multiple
    float rounds = static_cast<float>(numToRound) / static_cast<float>(multiple);

    // determine, whether if number is multiplier of multiple
    int floorRounds = static_cast<int>(floor(rounds));

    if (rounds - floorRounds > 0)
        // multiple is not multiplier of number -> advance to the next multiplier
        return (floorRounds+1) * multiple;
    else
        // multiple is multiplier of number -> return actual multiplier
        return (floorRounds) * multiple;
}

Код может быть неоптимальным, но я предпочитаю чистый код, чем сухую производительность.

Попался
источник
Приведение intк floatлегко теряет точность и делает для неправильных ответов.
chux - Восстановить Монику
1
int roundUp (int numToRound, int multiple)
{
  return multiple * ((numToRound + multiple - 1) / multiple);
}

хотя:

  • не будет работать для отрицательных чисел
  • не будет работать, если numRound + множественные переполнения

предложил бы вместо этого использовать целые числа без знака, что определило поведение переполнения.

Вы получите исключение, кратное == 0, но в любом случае это не является четко определенной проблемой.

user3392484
источник
1

с:

int roundUp(int numToRound, int multiple)
{
  return (multiple ? (((numToRound+multiple-1) / multiple) * multiple) : numToRound);
}

и для вашего ~ / .bashrc:

roundup()
{
  echo $(( ${2} ? ((${1}+${2}-1)/${2})*${2} : ${1} ))
}
nhed
источник
1

Я использую комбинацию модулей, чтобы аннулировать добавление остатка, если xон уже кратен:

int round_up(int x, int div)
{
    return x + (div - x % div) % div;
}

Мы находим обратное значение остатка, а затем модуль, который снова делим с делителем, чтобы обнулить его, если это сам делитель, и затем прибавляем x.

round_up(19, 3) = 21
Ник Бедфорд
источник
1

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

Избегая модуля и используя вместо этого деление, отрицательное число является естественным результатом, хотя оно округляется в меньшую сторону. После вычисления округленной версии выполняется математическое вычисление для округления в отрицательную или положительную сторону.

Также обратите внимание, что никакие специальные функции не используются для вычисления чего-либо, поэтому здесь есть небольшое повышение скорости.

int RoundUp(int n, int multiple)
{
    // prevent divide by 0 by returning n
    if (multiple == 0) return n;

    // calculate the rounded down version
    int roundedDown = n / multiple * multiple;

    // if the rounded version and original are the same, then return the original
    if (roundedDown == n) return n;

    // handle negative number and round up according to the sign
    // NOTE: if n is < 0 then subtract the multiple, otherwise add it
    return (n < 0) ? roundedDown - multiple : roundedDown + multiple;
}
weatx
источник
Сбой с , RoundUp(INT_MIN, -1)как n / multipleэто intпереполнение.
chux - Восстановить Монику
1

Я думаю, что это должно помочь вам. Я написал следующую программу на C.

# include <stdio.h>
int main()
{
  int i, j;
  printf("\nEnter Two Integers i and j...");
  scanf("%d %d", &i, &j);
  int Round_Off=i+j-i%j;
  printf("The Rounded Off Integer Is...%d\n", Round_Off);
  return 0;
}
Ниль
источник
0
/// Rounding up 'n' to the nearest multiple of number 'b'.
/// - Not tested for negative numbers.
/// \see http://stackoverflow.com/questions/3407012/
#define roundUp(n,b) ( (b)==0 ? (n) : ( ((n)+(b)-1) - (((n)-1)%(b)) ) )

/// \c test->roundUp().
void test_roundUp() {   
    // yes_roundUp(n,b) ( (b)==0 ? (n) : ( (n)%(b)==0 ? n : (n)+(b)-(n)%(b) ) )
    // yes_roundUp(n,b) ( (b)==0 ? (n) : ( ((n + b - 1) / b) * b ) )

    // no_roundUp(n,b) ( (n)%(b)==0 ? n : (b)*( (n)/(b) )+(b) )
    // no_roundUp(n,b) ( (n)+(b) - (n)%(b) )

if (true) // couldn't make it work without (?:)
{{  // test::roundUp()
    unsigned m;
                { m = roundUp(17,8); } ++m;
    assertTrue( 24 == roundUp(17,8) );
                { m = roundUp(24,8); }
    assertTrue( 24 == roundUp(24,8) );

    assertTrue( 24 == roundUp(24,4) );
    assertTrue( 24 == roundUp(23,4) );
                { m = roundUp(23,4); }
    assertTrue( 24 == roundUp(21,4) );

    assertTrue( 20 == roundUp(20,4) );
    assertTrue( 20 == roundUp(19,4) );
    assertTrue( 20 == roundUp(18,4) );
    assertTrue( 20 == roundUp(17,4) );

    assertTrue( 17 == roundUp(17,0) );
    assertTrue( 20 == roundUp(20,0) );
}}
}
Adolfo
источник
0

Это дает результаты, которые вы ищете для положительных целых чисел:

#include <iostream>
using namespace std;

int roundUp(int numToRound, int multiple);

int main() {
    cout << "answer is: " << roundUp(7, 100) << endl;
    cout << "answer is: " << roundUp(117, 100) << endl;
    cout << "answer is: " << roundUp(477, 100) << endl;
    cout << "answer is: " << roundUp(1077, 100) << endl;
    cout << "answer is: " << roundUp(52,20) << endl;
    cout << "answer is: " << roundUp(74,30) << endl;
    return 0;
}

int roundUp(int numToRound, int multiple) {
    if (multiple == 0) {
        return 0;
    }
    int result = (int) (numToRound / multiple) * multiple;
    if (numToRound % multiple) {
        result += multiple;
    } 
    return result;
}

А вот и выводы:

answer is: 100
answer is: 200
answer is: 500
answer is: 1100
answer is: 60
answer is: 90
Дейв
источник
0

Я думаю, что это работает:

int roundUp(int numToRound, int multiple) {
    return multiple? !(numToRound%multiple)? numToRound : ((numToRound/multiple)+1)*multiple: numToRound;
}
user13783520
источник
-1

Это работает для меня, но не пытался обрабатывать негативы

public static int roundUp(int numToRound, int multiple) {
    if (multiple == 0) {
        return 0;
    } else if (numToRound % multiple == 0) {
    return numToRound;
    }

    int mod = numToRound % multiple;
    int diff = multiple - mod;
    return numToRound + diff;
}
user1100538
источник
-3

Вот супер простое решение, чтобы показать концепцию элегантности. Это в основном для привязки сетки.

(псевдокод)

nearestPos = Math.Ceil( numberToRound / multiple ) * multiple;
Indivelope
источник
Вы проверили свою идею перед отправкой? даешь точный ответ
яодав
Это даже не правильный код.
user13783520