2017-02-01 2 views
3

기본적으로 성능 관련 질문 : 예를 들어, 즉 이중 부문에만 정수 몫을 얻고 싶은정지 소수 전에 더블 부문 (낮은 정밀도, 빠른 부문, 단지 '지수'를 받고)

에 대한 부서 88.3/12.7 = 6.9527559055118110236220472440945, 나는 결과로 '6'을 얻고 싶다. 가능한 구현 방법은 물론 floor(x/y)이지만, 여기서는 먼저 성능 집약적 인 이중 분할이 수행되고 이후에 이중 바닥은 이중 분할이 수행 한 대부분의 '작업'을 버립니다.

기본적으로 나는이 소수점을 모두 계산하기 전에 '멈추는'double을 가진 나눗셈을 원합니다. 그리고 나에게 초기 이중 인수를 반올림하거나 자르지 않고 나눗셈의 올바른 정수 결과를 제공합니다. 누구든지이 우아한 구현을 알고 있습니까 (이 주제를 검색했지만 많이 찾지 못했습니까?)

내가 생각할 수있는 또 다른 구현은 다음과 같습니다. int(x*1000)/int(y*1000) 여기서 1000 대신 필요한 '정밀도'를 사용할 수 있습니다. 매우 간단한 구현은 결과가 0보다 작을 때까지 x에서 y를 간단히 뺍니다. 하지만 그래, 나는 그것을 할 수있는 최선의 방법이 궁금했다.

또한 간단히 int(x)/int(y)을 수행하는 것은 잘못된 결과가 쉽게 발생할 수 있으므로 선택 사항이 아닙니다.

그건 그렇고, 나는 이것이 아마 새로운 기계에서 중요하지 않은 문제를 다루는 이러한 '마이크로 최적화'질문 중 하나라는 것을 알고 있습니다. 그러나 글쎄, 나는 여전히 주제에 대해 좀 궁금해합니다! :-)

+1

정수와 부동 소수점 나누기는 같은 시간이 걸립니다. 32 비트 분할은 64 비트 분할보다 빠릅니다. 분모가 충분히 제한적이어서 상호 참조를 얻을 수있는 조회 테이블을 가질 수 있다면 곱셈은 훨씬 빠릅니다. –

+1

문제는 비 분수를 얻기 위해 부서의 "부분"을 실제로 수행 할 수 없다는 것입니다. 적어도 저는 진보 된 수학에 능숙하지 않기 때문에 그렇게 생각합니다. 코드를 절대적으로 원하지 않는 한 http://math.stackexchange.com/에서 부서의 비 소수 부분 만 얻는 방법을 물어보십시오. –

답변

3

이전에 중지 할 방법이 없으며 정수 나누기를 사용하는 것이 잠재적으로 느립니다. 스카이 레이크에 예를 들어

:

idiv r/m32 L: 26-27 T: 6 
divsd xmm, xmm L: 13-14 T: 4 

(source)

그래서 이중 부문은 배 빠른이며, 훨씬 더 나은 처리량을 가지고있다. 즉, 전에 여분의 곱셈 및 추가 캐스트 요인.

이전 μarch에서는 32 비트 정수 나누기가 두 배보다 더 낮은 대기 시간 수를 갖는 경우가 종종 있습니다 (부동 소수점의 경우보다 더 직사각형이 더 많이 사용됨) 더 빠른 작은 결과입니다. 이러한 특성의 차이는 무엇으로 나누는 지에 따라 어느 방향 으로든 흔들릴 수 있습니다.

이 경우 특정 목표를 염두에 두지 않고 최적화하는 것이 위험하지만, 최신 기계가 기존 기계보다 타겟이 될 가능성이 높다는 것을 알 수 있습니다. 이중 분할은 할 수있는 최선의 방법입니다. 어쨌든 (다른 최적화가 적용되지 않는 한). 단 정밀도 부동 소수점 나누기는 그 자체로는 더 빠르지 만 변환 비용이 발생합니다.이 값을 더하면 실제로 손실됩니다 (5 + 10).

+0

매우 흥미로운 데이터입니다. 감사합니다. –

+0

좋은 답변 주셔서 감사합니다. 프로그래밍보다 수학/물리학에 더 가까운 사람으로서, 정수 나누기가 실수/이중 나누기보다 느릴 수 있다는 사실에 놀랐습니다. – kushy

+1

@kushy는 더욱 놀랄 준비가되어 있습니다 : 일반적으로 64 비트 정수 나누기 (대부분의 μarch 에서처럼)는 90 사이클이 소요됩니다. 차트에서 완전히 벗어났습니다. 어쨌든 그것은 주로 초점의 문제라고 생각합니다. 상대적으로 32 비트 정수 나누기를 적어도 두 배로 빠르게 할 수 있습니다. (즉, 나눌 비트가 적습니다. 일종의 피연산자 최소한 두 배나 느릴 필요는 없습니다).하지만 선택하지 마십시오. – harold