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

3
У вас є помилка у вашій логіці - скажімо, я хочу округлити 4 до найближчого кратного 2. roundDown = (4/2) * 2 = 4; roundUp = 4 + 2; так roundCalc = 6. Я припускаю, що ви хочете повернути 4 у такому випадку.
Нікі Йошіучі

це не працює для roundUp (30,30). Він дає 60 як відповідь, він все ж повинен дати 30 як відповідь ..
bsobaid

@bsobaid: Перевірте мою відповідь внизу. Тут дещо простіше, ніж інші рішення, хоча і вони повинні працювати
Ніклас Б.

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

це не працює для roundUp (30,30). Він дає 60 як відповідь, він все одно повинен дати 30 як відповідь.
bsobaid

@bsobaid неможливо. if (remainder == 0)Тест повинен подбати про такий випадок. Для мене це працює: ideone.com/Waol7B
Mark Ransom

112

Без умов:

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

Це працює як округлення від нуля для від’ємних чисел

EDIT: Версія, яка працює і для від'ємних чисел

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;
}

Тести


24
+1 за потужність 2 версії. Дуже корисно, оскільки повністю уникає витрат на множення, ділення або модуль.
Нікос С.

Ви впевнені, що ці алгоритми не мають передумов? А як щодо негативних чисел? Здається, що поведінка не визначена в попередньому С ++ 11 .
cubuspl42

> А як щодо негативних чисел? Як описано, це працює для негативних чисел, таких як округлення від нуля.
KindDragon

Я читаю "округлення" як сенс округлення до позитивної нескінченності, а не округлення від нуля.

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.


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

@Trejkaz nope. Це має бути (x = roundTo - 1; return (n+x)&~roundTo;)як у моїй відповіді
KindDragon

@KindDragon, який видає неправильний результат для мене, але якщо я виправлю це, кажу: ~ x замість ~ roundTo, я отримую очікуваний результат. На Java 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 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;
}

Що більш-менш відповідь плінтуса, з доданою негативною підтримкою введення.


Я перевірив float roundUp код з подвійним, він працює для мене. Дійсно вирішує мою проблему.
Ашиф

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 через використовувані подвійні значення).

#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));
}

1
плюс 1, хоча деякі люди можуть вважати більш резонним повернути 0, коли mulitple == 0
стилі

3
Будьте обережні, адже перетворення int64_t в подвійний може бути втратним, тому це не настільки загально типове, як може здатися.
Адріан Маккарті

@AdrianMcCarthy Так, ви повинні створити правильні спеціалізації шаблонів, як показано вище. Як бачите, я реалізую дві додаткові функції для long longі long double. Те саме потрібно зробити для двох інших функцій.
Фловдіс

Я думаю, що це далеко найповільніше, але цього не повинно бути. Все, що вам потрібно зробити - це std :: enable_if_t і зробити дві гілки для цілих чисел і плавців. Ви також можете краще скористатися числовим_лімітом і побачити, чи мантісса достатньо велика, щоб насправді відповідати значенню. Це додало б безпеці.
свиня

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);
}

@Peter Це? Я припускав, що 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або -Os9Sep2013 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функція може бути корисною при його використанні.


Кредит:


1
Саме те, що я шукав. Дякую!
kiyo

1
int roundUpPow2 (int num, int pow2) {повернути число + (pow2 - 1) & ~ (pow2 - 1); } приблизно на 30% швидший і простіший у використанні (ви пройдете 16, а не 4, щоб
подолати

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тих пір, як я його бачив у класі TList Delphi. Він має свої обмеження, такі як вирівнювання (кратне) є потужністю 2, але це рідко є проблемою, оскільки я в основному використовую його для отримання / перевірки правильності вирівнювання на SMID. Це дивовижно, і, здається, мало хто про це знає.
користувач1593842

2

Напевно, безпечніше кидати плавати та використовувати ceil () - якщо ви не знаєте, що поділ int дасть правильний результат.


1
Зауважте, що лише у подвійному розміщенні може зберігатися 54 біта ознакиі на машинах на базі x86. Якщо у вас є 64-бітні ints, вони в кінцевому рахунку вийдуть з ладу.
свиня

IEEE754 стандартний подвійний не може, але x64 cpus має 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.

EDIT - Вибачте, що ви не хотіли округлитись, я б запропонував використовувати метод 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


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. Перше, що потрібно зробити, це отримати оператор модуля, який ніколи не повертає від'ємні числа. Тоді roundUp дійсно простий.

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);
}

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, але все одно це не чітко визначена проблема.


1

c:

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

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

roundup()
{
  echo $(( ${2} ? ((${1}+${2}-1)/${2})*${2} : ${1} ))
}

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;
}

Не вдається з 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) );
}}
}

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;
}

-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;
}

-2

Ось надзвичайно просте рішення, щоб показати концепцію елегантності. Це в основному для оснащення сітки.

(псевдокод)

nearestPos = Math.Ceil( numberToRound / multiple ) * multiple;

Ви перевіряли свою ідею, подаючи подання? це дози дають правильну відповідь
yaodav

Це навіть не дійсний код.
користувач13783520
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.