C ++ : 가장 가까운 수의 배수로 올림


168

OK-기본 질문처럼 보일 정도로 여기에 게시하는 것이 거의 창피합니다 (누군가가 투표를 마치면 삭제하겠습니다).

이것이 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; 올림 = 4 + 2; 그래서 roundCalc = 6입니다.이 경우 4를 반환한다고 가정합니다.
Niki Yoshiuchi

roundUp (30,30)에서는 작동하지 않습니다. 60은 답변으로, 30은 답변으로 제공해야합니다.
bsobaid

@bsobaid : 하단에서 내 답변을 확인하십시오.
Niklas B.

3
테스트 케이스는 음수, 나눗셈이 정확한 경우, 나눗셈이 거의 정확한 경우 및 숫자가 범위의 한계에 매우 가까운 경우를 포함하는 예제가 눈에 띄지 int않습니다.

1
Robben_Ford_Fan_boy, 당신이 간 답을 가진 편집은 제거되어야합니다. 주어진 답변과 다른 경우 자신의 답변을 게시 할 수 있습니다. 이 답변에는 답변 섹션에서 해결해야 할 문제가 있습니다.
chux-복원 Monica Monica

답변:


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); }음수를 올바른 방향으로 반올림하기 시작할 때 추가
Josh

4
@ 조쉬 : 왜 곱셈을 사용 하는가? 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;
}

이것은 0에서 반올림하는 것처럼 작동 합니다.음수의 경우

편집 : 음수에도 작동하는 버전

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

테스트


multiple2의 거듭 제곱 인 경우 (~ 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
2 버전의 거듭 제곱은 +1입니다. 곱셈, 나눗셈 또는 모듈로의 비용을 완전히 피할 수 있으므로 매우 유용합니다.
Nikos C.

이 알고리즘에 전제 조건이없는 것입니까? 음수는 어떻습니까? 동작은 C ++ 11 이전에 정의되지 않은 것으로 보입니다 .
cubuspl42

> 음수는 어떻습니까? 설명한 바와 같이, 이것은 0에서 반올림하는 것과 같은 음수에 적용됩니다.
KindDragon

"반올림"은 0에서 반올림하지 않고 양의 무한대로 반올림하는 것을 의미합니다.

8
& ~(x - 1)와 동일한 & -x2의 보수 연산합니다.
Todd Lehman

39

요인이 항상 긍정적일 때 작동합니다.

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

편집 :이 반환합니다 round_up(0,100)=100. 를 반환하는 솔루션에 대해서는 아래의 Paul 의견을 참조하십시오 round_up(0,100)=0.


1
'다수의'사건을 처리하는 가장 짧은 경우처럼 보입니다.
harningt

1
비용이 많이 드는 작업 수 측면에서 최상의 솔루션입니다. 단일 분할 만 사용하고 곱셈은 사용하지 않습니다
Niklas B.

3
허용 된 답변 에서처럼 0 대신에 round_up (0, 100) == 100
Gregory

7
그렇지 num + factor - 1 - (num + factor - 1) % factor않습니까?
Paul

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 나에게 잘못된 결과를 생성하지만 ~ roundTo 대신 ~ x라고 수정하면 예상 결과가 나타납니다. 어쨌든 Java 8에서.
Trejkaz

@KindDragon : AND 마스크는 이거나 0xFFF...000그렇지 않아야 0xFFF7FFF합니다. 따라서 2의 -거듭 제곱에서 2의 보수 부정 ( : 빼기) 또는 2의 거듭 제곱보다 작은 비트 플립 (1의 보수 역, ~: 틸드)을 원합니다. 빼기). 그래서 (n+x) & ~x(n-roundTo+1) & -roundTo.
Peter Cordes

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

부정적인 입력 지원이 추가 된 플 린스의 대답은 어느 정도입니다.


float roundUp 코드를 두 배로 테스트했는데 나에게 효과적입니다. 내 문제를 정말 해결합니다.
Ashif

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); }라운드 반올림하려면 또는 스왑 천장을 만들다.
Troyseph

8

이것은 float, double, long, int 및 short에서 작동하는 템플릿 함수를 사용하는 최신 c ++ 접근법입니다 (그러나 사용되는 double 값으로 인해 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
공명

3
int64_t를 double로 변환하면 손실이 발생할 수 있으므로 일반적인 형식은 아닙니다.
Adrian McCarthy

@AdrianMcCarthy 예, 위와 같이 올바른 템플릿 전문화를 만들어야합니다. 보다시피, long long와에 대한 두 가지 추가 기능을 구현 long double합니다. 다른 두 기능에 대해서도 동일하게 수행해야합니다.
플 로브 디스

나는 이것이 가장 느리다고 생각하지만 반드시 그럴 필요는 없습니다. std :: enable_if_t를 수행하고 정수와 부동 소수점에 대해 두 개의 분기를 수행하기 만하면됩니다. numeric_limits를 더 잘 사용하고 가수가 실제로 값에 맞도록 충분히 큰지 확인할 수 있습니다. 그것은 안전에 추가 될 것입니다.
돼지

5

우선, 오류 조건 (multiple == 0)은 아마도 반환 값을 가져야합니다. 뭐? 모르겠어요 아마도 예외를 던지고 싶을 수도 있습니다. 그러나 아무것도 돌려주는 것은 위험하지 않습니다.

둘째, numToRound가 이미 배수가 아닌지 확인해야합니다. 그렇지 않으면에 추가 multiple할 때 roundDown오답이 표시됩니다.

셋째, 캐스트가 잘못되었습니다. numToRound정수로 캐스트 했지만 이미 정수입니다. 나누기 전에 두 배로 캐스팅하고 곱셈 후에 다시 int로 캐스팅해야합니다.

마지막으로 음수로 무엇을 원하십니까? 반올림 "위"는 0으로 반올림하거나 (양수와 같은 방향으로 반올림) 또는 0에서 멀어짐 ( "더 큰"음수)을 의미 할 수 있습니다. 아니면 신경 쓰지 않을 수도 있습니다.

다음은 처음 세 가지 수정 사항이있는 버전이지만 부정적인 문제는 다루지 않습니다.

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 / intint를 반환 한다고 가정했는데 , 이것은 우리가 원하는 것이 아닙니다.
Mike Caron

int / int는 실제로 int를 반환하지만 정확히 원하는 것입니다. 예를 들어, numToRound = 7, 배수 = 3. 7 / 3 = 2입니다.
Peter Ruderman

4

2의 거듭 제곱으로 반올림 :

누군가가 2의 거듭 제곱의 가장 가까운 배수로 반올림 한 양수에 대한 솔루션이 필요한 경우를 대비하여 (내가 여기서 끝났기 때문에) :

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

입력 번호가 이미 여러 개인 경우 입력 번호는 그대로 유지됩니다.

다음은 GCC가 제공하는 x86_64 출력 -O2또는 -Os(9Sep2013 Build-godbolt GCC online)입니다.

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) {return num + (pow2-1) & ~ (pow2-1); } 빠른 30 %에 대해, 그리고 사용하기 쉬운 (당신은 (16)의 다음 배수로 올림 (4) (16)을하지 통과
악셀 Rietschin

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
}

그리고 2의 거듭 제곱 :

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

음수 값을 모두 0으로 반올림하면 (즉, 모든 값에 대해 양의 무한대로 반올림 됨) 서명 된 오버플로 (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 클래스에서 본 이후로 귀하의 사용을 해왔습니다 . 정렬 (여러)이 2의 거듭 제곱과 같은 제한 사항이 있지만 SMID에 대한 올바른 정렬을 얻거나 확인하는 데 주로 사용하기 때문에 거의 문제가되지 않습니다. 그것은 굉장하며 많은 사람들이 그것에 대해 알지 못하는 것 같습니다.
user1593842

2

int 디비전이 올바른 결과를 생성한다는 것을 알지 못하면 float로 캐스팅하고 ceil ()을 사용하는 것이 더 안전합니다.


1
x86 기반 시스템에서는 double이 54 비트의 유효 값 만 보유 할 수 있습니다. 64 비트 정수가 있으면 결국 실패합니다.
돼지

IEEE754 표준 double은 불가능하지만 x64 CPU는 80 비트 내부 부동 소수점을 가지므로 단일 숫자에서의 작동이 안정적입니다.
Martin Beckett

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입니다.

편집-죄송합니다 반올림하고 싶지 않아 + 0.5 대신 ceil () 메서드를 사용하는 것이 좋습니다


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

이것은 원하는 반올림 증분이 2의 거듭 제곱 인 캐시 라인을 따라 할당 할 때 유용 할 수 있지만 결과 값은 그 배수 만 필요합니다. 일 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는 정수입니다 (양수 또는 음수, 0 포함). 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);
}

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

코드가 최적은 아니지만 건조 성능보다 깨끗한 코드를 선호합니다.


를 캐스팅하면 정밀도 intfloat쉽게 떨어지고 오답을 만듭니다.
chux-복원 Monica Monica

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

이기는 하지만:

  • 음수에는 작동하지 않습니다
  • numRound + 다중 오버플로 인 경우 작동하지 않습니다

대신 부호없는 정수를 사용하는 것이 좋습니다. 오버플로 동작을 정의했습니다.

배수 == 0이라는 예외가 있지만 어쨌든 잘 정의 된 문제는 아닙니다.


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

1

x이미 여러 배인 경우 나머지의 추가를 무효화하기 위해 모듈러스 조합을 사용합니다 .

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

우리는 나머지의 역수를 구한 다음, 제수 자체가 있다면 제수를 사용하여 다시 무효화하는 계수를 추가 x합니다.

round_up(19, 3) = 21

1

다음은 OP의 제안과 다른 사람들이 제시 한 예를 기반으로 한 솔루션입니다. 대부분의 사람들이 음수를 처리하기 위해 찾고 있었기 때문에이 솔루션은 특별한 기능 (예 : 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-복원 Monica Monica

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

그것은 유효한 코드조차 아닙니다.
user13783520
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.