알려진 가장 좋은 알고리즘은 계승을 주요한 힘의 곱으로 표현하는 것입니다. 체 접근법을 사용하여 각 프라임에 대한 올바른 힘뿐만 아니라 프라임을 신속하게 결정할 수 있습니다. 반복되는 제곱을 사용하여 각 전력을 효율적으로 계산 한 다음 계수를 곱할 수 있습니다. 이것은 Peter B. Borwein, 계승 계산의 복잡성 , Journal of Algorithms 6 376–380, 1985에 설명되어 있습니다. ( PDF ) 요컨대,정의를 사용할 때 필요한 시간 과 비교하여 시간 으로 계산할 수 있습니다 .n!O(n(logn)3loglogn)Ω ( n2로그n )
교과서의 의미는 나누고 정복하는 방법이었습니다. 제품의 규칙적인 패턴을 사용하여 곱셈을 줄일 수 있습니다 .n - 1
하자참조 부호 편리한 표기법. 의 요소를 재정렬하십시오 을
이제 정수 대해 라고 가정하십시오 . (이것은 다음 논의에서 합병증을 피하기위한 유용한 가정이며, 아이디어는 일반적인 으로 확장 될 수 있습니다 .) 그러면그리고이 재발을 확장함으로써,
컴퓨팅1 ⋅ 3 ⋅ 5 ⋯ ( 2 n - 1 ) ( 2 n ) ! = 1 ⋅ 2 ⋅ 3 ⋯ ( 2 n ) ( 2 n ) ! = n ! ⋅ 2 n ⋅ 3 ⋅ 5 ⋅ 7 ⋯ ( 2 n − 1 ) . n = 2 k k >n ?1 ⋅ 3 ⋅ 5 ⋯ ( 2 n − 1 )( 2 N ) ! = 1 ⋅ 2 ⋅ 3 ⋯ ( 2 n )
( 2 N ) ! = n ! ⋅ 2엔⋅ 3 ⋅ 5 ⋅ 7 ⋯ ( 2 n − 1 ) 입니다.
n = 2케이N ( 2 K ) ! = ( 2 k - 1 ) ! 2 2 k - 1 ( 2 k - 1 ) ? ( 2 k ) ! = ( 2 2 k − 1 + 2 k − 2 + ⋯ + 2 0 ) k − 1 ∏ i = 0 ( 2 i )k > 0엔( 2케이) ! = ( 2k - 1) ! 22k - 1( 2k - 1) ?( 2 K - 1 ) ? ( K - 2 ) + 2 K - 1 - 2 2 2 K - 2 2 2 K - 1( 2케이) ! = ( 22k - 1+ 2k - 2+ ⋯ + 20) ∏나는 = 0k - 1( 2나는) ? = ( 22케이− 1) ∏나는 = 1k - 1( 2나는) ? .
( 2k - 1) ?각 단계에서 부분 곱을 곱하면 곱셈이 필요합니다. 이것은 정의를 사용하여 곱셈 에서 거의 의 요소를 개선 한 것입니다 . 의 거듭 제곱을 계산하려면 몇 가지 추가 작업이 필요 하지만 이진 산술에서는이 값을 저렴하게 수행 할 수 있습니다 (정확히 필요한 항목에 따라 접미사 0 만 추가하면 됨 ).
( k − 2 ) + 2k - 1−222케이− 222케이− 1
다음 Ruby 코드는이 버전의 단순화 된 버전을 구현합니다. 이것은 다시 계산하는 것을 피하지그것이 가능한 곳조차도 :n ?
def oddprod(l,h)
p = 1
ml = (l%2>0) ? l : (l+1)
mh = (h%2>0) ? h : (h-1)
while ml <= mh do
p = p * ml
ml = ml + 2
end
p
end
def fact(k)
f = 1
for i in 1..k-1
f *= oddprod(3, 2 ** (i + 1) - 1)
end
2 ** (2 ** k - 1) * f
end
print fact(15)
이 첫 번째 패스 코드조차도 사소한 부분에서 향상
f = 1; (1..32768).map{ |i| f *= i }; print f
내 테스트에서 약 20 % 정도
약간의 작업으로 을 의 거듭 제곱으로 삼아야하는 요구 사항을 제거하면서 더 개선 할 수 있습니다 ( 광범위한 설명 참조 ).2엔2