비율 계산을 수행하는 가장 빠른 방법은 y = x * a/b
입니다. 모든 값은 부호가없고 32 비트이고 a
및 b
은 고정되어 있습니다 (한 번 초기화 됨 , 그리고 나서 변경하지 않음) 컴파일 타임에 알려지지 않았습니다. 결과는 오버 플로우되지 않도록 보장됩니다 (심지어 중간 곱셈이 64 비트를 필요로한다고 생각할지라도). 프로그래밍 언어는 그다지 중요하지 않지만 Java가 내 경우에 가장 적합 할 것입니다. 가능한 한 빨리해야합니다 (나노초 문제). 현재 사용 중 :곱하기 + 시프트 (32 비트) 곱하기 + 나눗셈
int result = (int) ((long) x * a/b);
하지만 분류가 느립니다. 그래서 가장 좋은 유형의 공식 것, 약 Perform integer division using multiplication 알고
factor
및
shift
이
a
및
b
(즉, 계산 속도가 느려질 수 있습니다)로부터 계산 될 수있다
int result = (int) (((long) x * factor) >>> shift);
.
는 단순히 원래 식의 분할 부품을 교체하려고했으나이 곱셈의 결과가 64 비트에 맞지 않기 때문에 작동하지 않습니다 :// init
int shift = 63 - Integer.numberOfLeadingZeros(b);
int factor = ((1L << shift)/b) + 1;
...
// actual calculation
int result = (int) ((long) x * a * factor) >>> shift);
결과는하지 않습니다 실제로 내 경우에는 완전히 정확해야한다. (하나는 괜찮을 것이다.)
나는 이제 (부분적인) 해결책을 가지고 있습니다 :'shift = 16; factor = ((long) a << 16)/b + 1;'- 그러나 일부 값 범위에서만 작동합니다. 가능한 경우 모든 부호없는 32 비트 값에 대해 작동하는 일반 솔루션을 갖는 것이 좋습니다. –
불변 제수로 정수 나누기를 알면 감춰진 부분이 명확하지 않습니다. 'a, b, x '가 모두'uint32_t' 인 것을 감안할 때, 서명되지 않은'uint64_t' 제품'x * a'를 계산 한 다음 상수 약수'b'를 갖는 64 비트 나누기를 적용합니다. 'b'가 컴파일 타임 상수이면, 나누기 연산자를 사용하고 컴파일러가 최적화하도록합니다. 마지막으로'uint64_t' 몫을'uint32_t'로 다시 캐스팅하십시오. (질문에있는 스펙에 따르면, 이것은 건설으로 성공할 것이고 추가적인 테스트는 필요 없습니다). – njuffa
@njuffa 불행히도 값은 컴파일 타임에 알려지지 않습니다. 나는 첨단 사례 (a, b 및 x 중 높은 값)에 대해 보장 된 행동으로 우아한 해결책을 찾기 위해 애를 썼다. 나는 그것을 지금 분류했다고 생각한다. –