C/C++의 정수 분할의 빠른 상한
된 " " "x
★★★★★★★★★★★★★★★★★」y
, 와 C는 모두 C++의q = x/y
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★를 들어, 「」라고 하는 것은,ceil(10/5)=2
★★★★★★★★★★★★★★★★★」ceil(11/5)=3
.
분명한 접근법에는 다음과 같은 것이 포함됩니다.
q = x / y;
if (q * y < x) ++q;
이 더 제가 본 . 그리고 제가 본 (실제로 사용된) 다른 방법에는 캐스팅이 포함됩니다.float
★★★★★★★★★★★★★★★★★」double
추가 곱셈(또는 두 번째 나눗셈)과 분기를 피하고 부동소수점수로 주조하는 것을 피하는 보다 직접적인 방법이 있습니까?
양수일 경우
unsigned int x, y, q;
반올림하려면...
q = (x + y - 1) / y;
또는 (x+y 단위의 오버플로우)
q = 1 + ((x - 1) / y); // if x != 0
양수의 경우:
q = x/y + (x % y != 0);
부정적이기도 한 x
, y
가지도 : 1분할만 하다.
int div_ceil(int x, int y) {
return x / y + (x % y > 0);
}
★★의 경우:x
0으로 하다리마인더가 0이 아니면 1을 추가해야 합니다.
ifx
나눗셈이이 되고 나눗셈은 0이 되고 나눗셈은 0이 되기 때문에 하지 않겠습니다.그것이 우리가 필요한 것입니다.그리고 우리는 아무것도 추가하지 않을 것입니다.왜냐하면x % y
이지 않다
Sparky의 답변은 이 문제를 해결하는 표준적인 방법 중 하나이지만, 제 코멘트에서도 언급했듯이, 당신은 오버플로우의 위험을 안고 있습니다.는 좀 더 풀 수 , 할까요?long long
s?s?
Nathan Ernst의 답변은 하나의 솔루션을 제공하지만 함수 호출, 변수 선언 및 조건부로 구성되어 있기 때문에 최적화하기가 어렵기 때문에 OPS 코드보다 짧지 않고 더 느릴 수 있습니다.
저의 솔루션은 다음과 같습니다.
q = (x % y) ? x / y + 1 : x / y;
모듈로와 나눗셈은 프로세서에서 동일한 명령을 사용하여 수행되기 때문에 OPS 코드보다 약간 빠릅니다. 컴파일러는 그것들이 동등하다는 것을 알 수 있기 때문입니다.적어도 gcc 4.4.1은 x86에서 -O2 플래그를 사용하여 이 최적화를 수행합니다.
이론적으로 컴파일러는 Nathan Ernst의 코드로 함수 호출을 인라인화하여 같은 것을 출력할 수 있지만, 제가 테스트했을 때 gcc는 그렇게 하지 않았습니다.컴파일된 코드를 표준 라이브러리의 단일 버전에 연결하기 때문일 수 있습니다.
마지막으로, 최신 머신에서는 이 모든 것이 매우 엄격한 루프 상태에 있고 모든 데이터가 레지스터 또는 L1-캐시에 저장되어 있는 경우를 제외하고 문제가 되지 않습니다.그렇지 않으면 Nathan Ernst를 제외하고 모든 솔루션이 동일하게 빠릅니다. Nathan Ernst는 함수를 메인 메모리에서 가져와야 할 경우 상당히 느려질 수 있습니다.
를 사용할 수 있습니다.div
cstdlib로 기능하여 한 번의 호출로 몫과 나머지를 얻은 후 다음과 같이 상한을 개별적으로 처리합니다.
#include <cstdlib>
#include <iostream>
int div_ceil(int numerator, int denominator)
{
std::div_t res = std::div(numerator, denominator);
return res.rem ? (res.quot + 1) : res.quot;
}
int main(int, const char**)
{
std::cout << "10 / 5 = " << div_ceil(10, 5) << std::endl;
std::cout << "11 / 5 = " << div_ceil(11, 5) << std::endl;
return 0;
}
나는 차라리 코멘트를 하고 싶었지만 나는 충분히 높은 평판을 가지고 있지 않다.
내가 아는 한, 긍정적인 주장과 2의 거듭제곱인 제수의 경우, 이것이 가장 빠른 방법입니다(CUDA에서 테스트됨).
//example y=8
q = (x >> 3) + !!(x & 7);
일반적인 긍정적인 주장의 경우에만 다음과 같이 하는 경향이 있습니다.
q = x/y + !!(x % y);
부호 있는 정수 또는 부호 없는 정수.
q = x / y + !(((x < 0) != (y < 0)) || !(x % y));
서명된 배당금 및 서명되지 않은 제수.
q = x / y + !((x < 0) || !(x % y));
서명되지 않은 배당금과 서명된 제수를 위해.
q = x / y + !((y < 0) || !(x % y));
부호 없는 정수의 경우.
q = x / y + !!(x % y);
제로 제수가 실패한다(네이티브 조작과 같다).오버플로를 일으킬 수 없습니다.
대응하는 플로어 및 모듈로constexpr
필요한 오버로드를 선택하기 위한 템플릿과 함께 구현(완전 최적화 및 부호 비교 경고 불일치 방지):
https://github.com/libbitcoin/libbitcoin-system/wiki/Integer-Division-Unraveled
단순화된 범용 형식,
int div_up(int n, int d) {
return n / d + (((n < 0) ^ (d > 0)) && (n % d));
} //i.e. +1 iff (not exact int && positive result)
보다 일반적인 답변을 위해 C++는 잘 정의된 반올림 전략으로 정수 나눗셈에 대해 기능합니다.
이는 양수 또는 음수에 적용됩니다.
q = x / y + ((x % y != 0) ? !((x > 0) ^ (y > 0)) : 0);
나머지가 있는 경우는, 가 체크합니다.x
그리고.y
같은 부호를 가지며 덧붙인다.1
따라서.
이건 어때?(y가 음이 아닌 경우는 음이 아니므로 y가 음이 아닌 보증이 없는 변수인 경우는 이 값을 사용하지 마십시오.
q = (x > 0)? 1 + (x - 1)/y: (x / y);
줄였다y/y
1대 1로, 그 용어를 없애다x + y - 1
넘칠 가능성이 있어요.
나는 피한다x - 1
감쌀 때x
는 부호 없는 유형으로 0을 포함합니다.
서명필x
, 음수와 0은 여전히 하나의 케이스로 결합됩니다.
현대의 범용 CPU에서는 그다지 큰 메리트는 없지만 임베디드 시스템에서는 다른 어떤 정답보다 훨씬 빠릅니다.
컴파일러는 O3로 컴파일하여 최적화가 잘 됩니다.
q = x / y;
if (x % y) ++q;
언급URL : https://stackoverflow.com/questions/2745074/fast-ceiling-of-an-integer-division-in-c-c
'source' 카테고리의 다른 글
Vuex Store에서 'this'로 액세스 상태 (0) | 2022.08.30 |
---|---|
Vuex - mapState 데이터로 작업하기 전에 API 호출과 초기 저장소를 기다립니다. (0) | 2022.08.30 |
Clibcurl이 출력을 문자열로 가져옵니다. (0) | 2022.08.30 |
C복소수 및 프린트 f (0) | 2022.08.30 |
익명 클래스에서 최종 변수만 액세스할 수 있는 이유는 무엇입니까? (0) | 2022.08.30 |