1 <10 비교가 1 <1000000보다 저렴합니까?


65

z-indexCSS에서 카운트로 ~ 10 억을 사용했으며 계속 해야하는 비교에 대해 생각하고있었습니다. 매우 큰 수와 매우 작은 수의 비교에서 ALU 수준의 성능에 차이가 있습니까?

예를 들어,이 두 스 니펫 중 하나가 다른 것보다 비쌀까요?

snippet 1

for (int i = 0; i < 10000000; i++){
    if (i < 10000000000000) {
        //do nothing
    }
}

snippet 2

for (int i = 0; i < 10000000; i++){
    if (i < 1000) {
        //do nothing
    }
}

9
분기 예측의 작동 방식대해 알고 있습니까?
gnat

12
OP는 분기에 소요되는 시간을 묻지 않습니다. 분명히이 예제는 두 스 니펫에서 정확히 같은 시간이 걸리도록하기위한 것입니다. 문제 는 더 큰 CMP경우 개별 기계 명령이 느려질 지에 관한 것 i입니다.
Kilian Foth

18
이 작업은 CSS에서 수행되므로 문자열을 정수로 변환하면 실행에 소요 된 시간 측면에서 비교 작업 자체를 지배 할 수 있습니다.

58
CSS 파일에서 1000000000을 z- 인덱스로 사용해야하는 경우 무언가 잘못한 것입니다.
Bergi

6
CSS의 경우 텍스트를 정수로 변환하는 오버 헤드는 변환되는 자릿수에 따라 다릅니다 (1000000과 같은 6 자리 숫자는 1과 같은 1 자리 숫자의 약 6 배일 수 있습니다). 이 오버 헤드는 정수 비교의 오버 헤드보다 수십 배 더 클 수있다.
Brendan

답변:


82

내가 작업 한 모든 프로세서는 피연산자 중 하나를 다른 피연산자에서 빼고 결과를 버리고 프로세서의 플래그 (0, 음수 등)를 그대로 두어 비교합니다. 빼기는 단일 연산으로 수행되므로 피연산자의 내용은 중요하지 않습니다.

확실하게 질문에 대답하는 가장 좋은 방법은 코드를 어셈블리로 컴파일하고 생성 된 명령어에 대해서는 대상 프로세서의 설명서를 참조하십시오. 현재 인텔 CPU의 경우 인텔 64 및 IA-32 아키텍처 소프트웨어 개발자 매뉴얼이 될 것 입니다.

의 설명 CMP( "비교") 명령은 볼륨 2A, 3-126 페이지, 또는 페이지의 PDF (618)에 있고, 같은 동작을 설명한다 :

temp ← SRC1 − SignExtend(SRC2);
ModifyStatusFlags; (* Modify status flags in the same manner as the SUB instruction*)

즉, 필요한 경우 두 번째 피연산자가 부호 확장되어 첫 번째 피연산자에서 빼고 결과는 프로세서의 임시 영역에 배치됩니다. 그런 다음 상태 플래그는 SUB( "빼기") 명령어 와 동일한 방식으로 설정됩니다 (PDF의 1492 페이지).

피연산자 값이 대기 시간과 관련이 있다는 문서 CMP또는 SUB설명서 에는 언급이 없으므로 사용하는 모든 값이 안전합니다.


5
32 비트 산술에 비해 숫자가 너무 커지면 어떻게됩니까? 그러면 더 느린 계산으로 분할되지 않습니까?
팔코

3
@Falco 64 비트 ALU가있는 CPU에는 없습니다 (요즘 임베디드 공간을 제외하고는 거의 모든
것들

8
@Falco : 예. 그러나 ALU 성능에 대한 질문 때문에 CPU의 워드 크기 또는 SIMD 명령어의 능력에 해당하는 값이 적용됩니다. 그보다 많은 수의 연산은 CPU 외부의 여러 명령어로 구현해야합니다. 30 년 전에는 8 비트 또는 16 비트 레지스터가 작동했을 때 매우 흔했습니다.
Blrfl

6
@Falco 어떻게 디버깅해야합니까? 버그가 아닙니다. 기본적으로 64 비트 연산을 지원하지 않는 CPU에서 64 비트 연산을 수행하는 것이 약간 느립니다. 2 ^ 31-1보다 큰 숫자를 사용해서는 안된다고 제안하는 것은 약간 터무니없는 것 같습니다.
reirab

2
@Falco 브라우저에서 렌더링 엔진은 정수를 사용하여 z- 표시를 나타내는가? 내가 익숙한 대부분의 렌더링 엔진은 모든 것에 단 정밀도 부동 소수점을 사용하지만 (최종 래스터 화 단계까지) 실제로 브라우저 렌더링 엔진을 연구하지는 않았습니다.
reirab

25

매우 큰 수와 매우 작은 수의 비교에서 ALU 수준의 성능에 차이가 있습니까?

많은 수의 소수에서가는 당신의 숫자 형식을 변경하지 않는 한 그것은 매우 가능성이있어,에서 말하는 intA와 long. 그럼에도 불구하고 그 차이는 크지 않을 수 있습니다. 프로그래밍 언어 가 덮개 아래에서 임의의 정밀 산술 로 자동 전환되면 차이가 발생할 가능성이 큽니다 .

그럼에도 불구하고 특정 컴파일러는 사용자가 모르는 영리한 최적화를 수행하고있을 수 있습니다. 당신이 알아내는 방법은 측정 하는 것입니다. 코드에서 프로파일 러를 실행하십시오. 어느 비교가 가장 오래 걸리는지보십시오. 또는 단순히 타이머를 시작하고 중지하십시오.


질문에서 제안 된 숫자는 전형적인 32 비트 정수 유형에서 다른 숫자 유형이라는 점을 언급해야합니다.
Falco

19

많은 프로세서에는 "작은"명령어가 있는데,이 명령어는 비교를 포함하여 특정 즉시 지정된 피연산자에 대한 산술 연산을 수행 할 수 있습니다. 이러한 특수 값 이외의 피연산자는 더 큰 명령어 형식을 사용하거나 경우에 따라 "메모리에서 값로드"명령어를 사용해야합니다. 예를 들어 ARM Cortex-M3 명령어 세트에는 값을 상수와 비교할 수있는 방법이 5 가지 이상 있습니다.

    cmp r0,#1      ; One-word instruction, limited to values 0-255

    cmp r0,#1000   ; Two-word instruction, limited to values 0-255 times a power of 2

    cmn r0,#1000   ; Equivalent to comparing value with -1000
                   ; Two-word instruction, limited to values 0-255 times a power of 2

    mov r1,#30000  ; Two words; can handle any value 0-65535
    cmp r0,r1      ; Could use cmn to compare to values -1 to -65535

    ldr r1,[constant1000000] ; One or two words, based upon how nearby the constant is
    cmp r0,r1
    ...

constant1000000:
    dd  1000000

첫 번째 형태는 가장 작습니다. 제 2 및 제 3 형태는 코드가 페치되는 메모리의 속도에 따라 빠르게 실행되거나 실행되지 않을 수있다. 네 번째 형식은 처음 세 가지 형식보다 거의 느리고 다섯 번째 형식은 훨씬 느리지 만 두 번째 형식은 32 비트 값으로 사용할 수 있습니다.

구형 x86 프로세서에서는 짧은 형식 비교 명령이 긴 형식의 명령보다 빠르게 실행되지만 많은 최신 프로세서는 처음 가져올 때 긴 형식과 짧은 형식을 모두 동일한 표현으로 변환하여 캐시에 균일 한 표현을 저장합니다. 따라서 임베디드 컨트롤러 (많은 모바일 플랫폼에서 사용되는 것과 같은)는 속도 차이가 있지만 많은 x86 기반 컴퓨터는 그렇지 않습니다.

또한 루프 내에서 상수를 많이 사용하는 많은 경우에 컴파일러는 루프가 시작되기 전에 타이밍 차이를 렌더링하여 레지스터에 상수를 한 번만로드하면됩니다. 반면에 작은 루프에서도 상황이 항상 발생하지는 않습니다. 루프가 작지만 많이 실행되는 경우, 짧은 값이 짧은 비교와 더 긴 값이 비교되는 경우가 종종 있습니다.


MIPS에서는 즉각 16 비트 만 가질 수 있으므로 1과의 비교는 1000000보다 짧아지고 (아마도) 빠를 것입니다. 아마도 Sparc 및 PowerPC와 같습니다. 필자는 인텔이 여러 사례에서 소규모
직책에

@ LưuVĩnhPhúc : 루프 전에 레지스터를로드 할 수 있습니다. 이 시점에서 실제 비교는 두 경우 모두 동일한 수의 명령이됩니다.
cHao

루프는 op의 예일 뿐이고 질문은 예를 들어 z- 인덱스입니다. 각각 고유 한 z- 인덱스가있는 1000 개의 개체가 있고 100000000 ... 1000000999 또는 10000으로 설정 한 경우 ... 렌더링하기 전에 정렬을 위해 10999를 반복하고 비교하고 많은로드 명령이 있습니다. 거기에 차이가 생길 수 있습니다!
팔코

@Falco :이 경우 즉각적인 요소도 고려하지 않습니다. 레지스터를로드하고 비교하는 것은 피할 수없는 것처럼 보입니다.
cHao

@cHao : Z 인덱스를 서로 비교하는 경우 레지스터에있게됩니다. 특정 범위의 지수를 다르게 취급하는 경우 즉각적인 비교가 필요할 수 있습니다. 일반적으로 상수는 루프가 시작되기 전에로드되지만, 예를 들어 하나의 메모리에서 값 쌍을 읽고 각 쌍의 첫 번째 값을 100000 범위의 5 개의 다른 (균일하지 않은 간격의) 상수와 비교해야하는 루프가있는 경우 -100499까지의 다른 값과 5 개의 다른 상수를 가진 다른 값은 100250을 빼고 (레지스터에 기록 된) -250에서 250 사이의 값과 비교하는 것이 훨씬 빠를 수 있습니다.
supercat

5

이 질문에 대한 짧은 대답은 아니오입니다 . 두 데이터가 동일한 데이터 형식 (예 : 32 비트 정수 또는 64 비트 길이)으로 저장되어 있다고 가정 할 경우 두 숫자를 비교할 때 시차가 없습니다.

또한 ALU 의 워드 크기 까지는 두 정수를 서로 비교하는 것이 빼기와 동등한 사소한 연산이기 때문에 1 클럭 사이클 이상이 걸리지 않을 것입니다. 내가 다루었던 모든 아키텍처에는 단일 사이클 정수 비교가 있다고 생각합니다.

두 숫자의 비교가 단일 사이클 작업이 아닌 경우에 만난 것으로 생각할 수있는 유일한 경우는 다음과 같습니다.

  • 피연산자를 가져 오는 데 실제로 메모리 대기 시간이 있지만 비교 자체의 작동 방식과 관련이없는 지침 (일반적으로 x86 / x64와 같은 CISC 디자인에서는 가능하지만 RISC 아키텍처에서는 불가능 함)
  • 부동 소수점 비교는 아키텍처에 따라 다중주기 일 수 있습니다.
  • 문제의 숫자는 ALU의 단어 크기에 맞지 않으므로 비교를 여러 명령으로 나눠야합니다.

4

@RobertHarvey의 답변 은 좋습니다. 이 답변을 그의 보충 자료로 생각하십시오.


분기 예측 도 고려해야합니다 .

컴퓨터 아키텍처에서, 분기 예측기는 분기 (예를 들어 if-then-else 구조)가 어떤 방식으로 진행 될지 추측하기 위해 시도하는 디지털 회로입니다. 분기 예측기의 목적은 명령 파이프 라인의 흐름을 개선하는 것입니다. 지점 예측자는 x86과 같은 많은 최신 파이프 라인 마이크로 프로세서 아키텍처에서 높은 효과적인 성능을 달성하는 데 중요한 역할을합니다.

기본적으로 예제 if에서 루프 내부 의 명령문이 항상 동일한 응답을 리턴하면 시스템은 분기 방식을 올바르게 추측하여 최적화 할 수 있습니다. 예를 들어, if첫 번째 경우 의 명령문은 항상 동일한 결과를 리턴하므로 두 번째 경우보다 약간 빠르게 실행됩니다.

주제에 대한 탁월한 스택 오버플로 질문


분기 예측은 분기 시간에 영향을 주지만 비교 시간 자체에는 영향을 미치지 않습니다.
reirab

3

구현에 따라 다르지만 매우 가능성이 적습니다 .

다양한 브라우저 엔진의 구현 세부 사항을 읽지 않았으며 CSS는 숫자에 대한 특정 유형의 저장소를 지정하지 않습니다. 그러나 모든 주요 브라우저가 CSS에서 숫자 요구 사항을 대부분 처리하기 위해 64 비트 배정 밀도 부동 소수점 숫자 ( "doubles", C / C ++에서 용어를 빌리기 위해)를 사용한다고 가정하는 것이 안전하다고 생각합니다 이는 자바 스크립트가 숫자에 사용하는 방식이므로 동일한 유형을 사용하면 통합이 더 쉬워집니다.

컴퓨터의 관점에서 볼 때, 모든 복식은 값이 1 또는 -3.14 또는 1000000 또는 1e100이든 상관없이 동일한 양의 데이터 (64 비트)를 전달합니다 . 이 숫자에 대해 작업을 수행하는 데 걸리는 시간은 항상 같은 양의 데이터에서 작업하기 때문에 해당 숫자의 실제 값에 의존하지 않습니다. 이러한 방식으로 작업을 수행하는 데있어 상충 관계가 있습니다. 복수는 모든 숫자 (또는 범위 내의 모든 숫자)를 정확하게 나타낼 수는 없지만 대부분의 문제에 충분히 가까워 질 수 있으며 CSS가 수행하는 종류의 숫자는 아닙니다. -그보다 더 정밀해야 할만큼 충분히 요구합니다. 이것을 JavaScript와의 직접적인 호환성의 이점과 결합하면 두 배의 경우가 있습니다.

누군가가 숫자에 가변 길이 인코딩을 사용하여 CSS를 구현하는 것은 불가능하지 않습니다. 누군가가 가변 길이 인코딩을 사용하는 경우 작은 숫자 비교하는 것이 큰 숫자를 비교하는 것보다 비용이 적게 듭니다. 큰 숫자는 더 많은 데이터를 처리하기 때문 입니다. 이러한 종류의 인코딩은 이진보다 더 정확할 수 있지만 속도가 훨씬 느리며 특히 CSS의 경우 정확도 게인이 성능 저하의 가치가 충분하지 않을 수 있습니다. 모든 브라우저가 이런 식으로 작동한다는 것을 알게되어 매우 놀랐습니다.

이론적으로는 위에서 언급 한 모든 것에 예외가있을 수 있습니다. 0과 비교하는 것이 다른 숫자와 비교하는 것보다 빠릅니다 . 이것은 0이 짧기 때문이 아닙니다 (이유가 원인이라면 1이 빠르지 만 그렇지는 않습니다). 제로가 당신을 속일 수 있기 때문입니다. 모든 비트가 꺼져있는 유일한 숫자이므로 값 중 하나가 0임을 알면 다른 값을 숫자로 볼 필요조차 없습니다. 비트 중 하나가 있으면 같지 않습니다. 0이면 1 비트 만보고 0보다 크거나 작은 지 확인해야합니다.


0

이 코드가 실행될 때마다 해석되는 경우 10000000000000와 비교하여 토큰 화하고 해석하는 데 시간이 오래 걸리므로 차이 가 1000있습니다. 그러나 이것은이 경우 통역사의 첫 번째 최적화입니다 : 한 번 토큰 화하고 토큰을 해석하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.