2010-07-28 6 views
8

Dijkstra 알고리즘을 사용하여 그래프에서 최소 경로를 찾는 응용 프로그램을 작성하고 있습니다. 그래프의 노드와 에지의 가중치는 float이며, 알고리즘은 부동 소수점 숫자에 대해 많은 연산을 수행합니다. 모든 체중을 int s로 변환하면 실행 시간이 향상 될 수 있습니까? int 산술 연산은 자바에서 더 빠르다.int에서 Java의 부동 소수점 연산 효율성

나는 그것을 체크하기 위해 간단한 벤치 마크를 쓰려고했지만, 내가 얻은 결과에 만족하지 않는다. 아마도 컴파일러가 프로그램의 일부분을 최적화하여 결과가 저에게 적합하지 않을 수도 있습니다.


편집 :

내가 해결하기 위해 노력하고있어 문제는 정보 검색 필드에 있습니다. 애플리케이션은 키워드 세트로 제기 된 검색어에 대한 답변을 표시해야합니다.

내 데이터 구조는 가중치 적용 그래프입니다. 잎 노드 집합을 감안할 때이 노드를 연결하고 사용자에게 대답을 표시하는 가장 작은 트리를 찾아야합니다. 가중치는 부분적으로 tf/idf 기법을 기반으로하는 가중치 함수에 의해 할당됩니다. 사용자는 자신이 제기 한 쿼리와 관련된 답변을 보려고하는 노드와 에지에 어떤 가중치를 할당했는지 알지 못합니다. 정확한 결과가 필요하지 않으며, 가중치에 따라 답변을 열거 할 수 있습니다. 가중치 함수 (tf/idf를 기반으로한다고 언급했듯이)의 본래 용도는 플로트 가중치를 제공하므로 지금까지 수레를 사용했습니다.

질문에 배경이 추가되기를 바랍니다.

+0

어쨌든 결과는 무엇입니까? – Amarghosh

+0

나는 곱셈 된 int 값이 약 13 % 빨라졌지만, 두 int 값을 비교하면 약 22 % 느리다. – jutky

+0

나는 완전히 확신 할 수는 없지만 Dijkstra의 경우 추가 및 비교 연산만으로 충분할 것입니다. 그리고 이러한 연산의 경우 float 또는 int에 대해 그다지 변하지 않습니다. 나는 정수 비교가 22 % 더 느릴 것이라고 정말로 놀랍다. 어떤 종류의 벤치마킹을 수행했는지 알 수 있습니까? – tafa

답변

1

이런 종류의 일과 마찬가지로, 성능 목표를 스스로 설정 한 다음 앱이 프로필을 충족하는지 확인해야합니다.

종종 놀라운 결과가 나타날 수 있습니다. 가져온 시간은 기본 숫자 유형에 전혀 영향을받지 않으며 알고리즘이 차선책임을 알 수 있습니다.

컴파일러 최적화와 관련하여 성능 최적화의 실제적이고 효과적인 부분입니다.

유형 A를 사용하는 것이 이론적으로 유형 B를 사용하는 것보다 빠르지 만 컴파일러는 유형 B가 실제 시나리오에서 더 빠르도록 최적화 할 수 있습니다. 그러면 dissapointment의 출처가 아닌 중요한 증거가됩니다.

+2

성능이 향상되면 응용 프로그램의 꽤 좋은 부분을 변경하는 데 걸리는 시간을 가질 수 있다는 것을 듣고 싶었습니다. 그러나 이것이 내가 미리 알 수없는 것 같으며, 이것을 체크하는 가장 좋은 방법은 알고리즘의 두 가지 버전을 구현하고 실행 시간을 측정하는 것입니다. – jutky

2

int가 더 빠르지 만 int를 사용하면 동일한 결과를 얻으려면 더 많은 작업을해야 할 수도 있습니다. 예 : INT

int i = 15 * 987/1000; 

여분 분할 같은 플로트

float f = 15 * 0.987; 

같은

INT는 조작이 더 걸릴 수 있다는 것을 의미한다.

+0

Dijkstra 알고리즘에서 나는 단지 경로의 무게를 요약하고 비교합니다. 따라서 계산 작업은 나에게 꽤 뒷전입니다. 간단한 작업 int가 더 빠르다는 것을 어떻게 알 수 있습니까? 공통점이 있거나 주제에 관한 몇 가지 문헌을 가르쳐 줄 수 있습니다. – jutky

+1

JVM에서 생성 된 원시 코드를보고 클록주기를 비교해야합니다. 그러나 두 작업 모두 캐시 누락 및 시스템 호출 비용에 비해 상당히 빠릅니다. 데이터 유형의 선택이 큰 차이를 만들지는 않을 가능성이 높습니다. –

-6

나는 그렇게 생각하지 않는다.

플로트는 4 바이트입니다. 그리고 자바에서 Int 또한 4 바이트입니다.

실행 시간을 가져 오기 위해 Date (java.util.Date)를 사용하지 않는 이유는 무엇입니까?

고유 한 100000 노드의 그래프를 정의 할 수 있습니다. 그런 다음 그것을 계산하십시오.

+0

"bit"대신 "byte"라는 단어를 사용하는 것이 좋습니다. 4 * 비트 * 정수는 16 개의 고유 한 값만 가질 수 있습니다 ... –

+0

죄송합니다 ... 영어가 가난합니다. 그래서 저는 잘못된 단어를 사용했습니다. (내 모국어는 영어가 아닙니다) 사실, float보다 빠릅니다. 하드웨어 때문입니다. 물리학에서, int는 float보다 쉽게 ​​달성 할 수 있습니다. – rainisic

0

가중치를 비교하려는 경우 int를 선호해야합니다.

+0

다른 답변과 동일한 코멘트는 공통된 장면이거나 주제에 관한 몇 가지 문헌을 가르쳐 줄 수 있다는 것입니다. – jutky

0

일반적으로 성능상의 이유로 intfloat 사이의 선택에 대해 걱정할 필요가 없습니다.

부동 소수점 산술가 정확 :

여기 Java Puzzlers의 부록에서 발췌이다. 정확한 결과가 필요한 곳에서는 부동 소수점을 사용하지 마십시오. 대신 정수형 또는 BigDecimal을 사용하십시오. double ~ float이 바람직합니다. 당신이 정말 좋은 이유가없는 한 부동 소수점 연산을 사용해야하는 경우

, 당신은 일반적으로 floatdouble를 선호한다. 정확한 결과를 원하면 BigDecimal을 사용하십시오. 프리미티브가 아니기 때문에 속도가 느려질 것입니다. 그러나 프로파일 링을 통해 허용되지 않는다고 표시되지 않는 경우가 가장 좋은 옵션입니다.

부동 소수점 연산을 사용해야하는 경우 int을 사용하여 최적화하려는 경우 좋지 않습니다. 이것은 조숙 한 최적화 일 가능성이 높으며 코드가 불필요하게 복잡해질뿐입니다. 가장 자연스럽고 가장 읽기 쉬운 방법으로 작성하십시오. 약간의 성능 향상을 위해 코드를 불필요하게 복잡하게 만들지 마십시오.

실제로 부동 소수점 연산이 필요하지 않다면, 반드시 int 또는 long을 사용하십시오.

+0

http://stackoverflow.com/questions/2550281/floating-point-vs-integer-calculations-on-modern-hardware 및 http://stackoverflow.com/questions/2010252/float-versus-integer-arithmetic도 참조하십시오. -performance-on-modern-chips – polygenelubricants

+0

질문에 대한 배경 지식을 추가했습니다. 희망을 분명히하는 몇 가지. 링크를 가져 주셔서 감사합니다. – jutky

0

성능은 소프트웨어가 실행되는 알고리즘과 플랫폼에 따라 크게 달라집니다.

X86 플랫폼에서 행렬/배열 계산을 수행하는 경우 런타임에서 float/double 전용 확장 명령 세트 인 SSE를 사용하도록 런타임을 최적화 할 수 있습니다.

다른 플랫폼에서는 런타임이 OpenCL로 최적화 될 수 있습니다. (지금 당장은 그렇지 않습니다. 그러한 플랫폼에서 어떤 조건에서 가장 빨리 실행되는지 전혀 알 수 없습니다. OpenCL이 정수 워크로드에 최적화되어있을 수도 있습니다.

이 상황에서 나는이 시점에서 데이터 유형 (float 또는 int)을 최적화하고 코드의 가독성을 최적화하는 것이 좋지 않다고 결론을 내릴 것입니다.

코드가 매우 중요하며 시스템이 현재 및 미래에 어떤 하드웨어에서 실행되는지 정확히 알면 다양한 알고리즘을 사용하여 일반적인 작업을 테스트하고 필요에 가장 적합한 하드웨어를 선택할 수 있습니다.

일반적으로 이해할 수있는 알고리즘을 사용하고 코드를 읽을 수있게 유지하면 버그 수가 적습니다. 결과가 올바르지 않으면 빠른 코드는 그다지 가치가 없습니다.

1

정수 빼기는 내 기계에서 두 배의 빼기보다 2.5 배 빠릅니다. 그러나 정수 곱셈은 이중 곱셈보다 ~ 1.5 배 빠릅니다.

다음 테스트는 무작위 데이터에서 작동하므로 컴파일러가 최적화되지 않을 수 있습니다.

// test whether int subs are faster than double subs 
public void compareIntAndFloatSubtraction(){ 

    int N = 100000; // input array size 
    int k = 100000; // number of mathematical operations performed on each element 

    // generate random data 
    int[] ints = new int[N]; 
    double[] doubles = new double[N]; 
    Random r = new Random(1l); 
    for (int i = 0; i < N; i++) { 
     ints[i] = r.nextInt(); 
     doubles[i] = r.nextDouble(); 
    } 

    // measure integer subtractions 
    long before = System.currentTimeMillis(); 
    for (int i = 1; i < N; i++) { 
     for (int j = 0; j < k; j++) { 
      ints[i] -= ints[i-1]; // referring to another element might prevent from optimization also 
     } 
    } 
    System.out.println(String.format("time needed for int subs [ms]: %s", System.currentTimeMillis()-before)); 

    // measure double subtractions 
    before = System.currentTimeMillis(); 
    for (int i = 1; i < N; i++) { 
     for (int j = 0; j < k; j++) { 
      doubles[i] -= doubles[i-1]; 
     } 
    } 
    System.out.println(String.format("time needed for double subs [ms]: %s", System.currentTimeMillis()-before)); 

} 
+1

시험에 감사드립니다. 내 컴퓨터 (Xeon, 64 비트, Windows, Java 1.8)에서 빼기 테스트를 실행하면 int subs [7704], double subs [ms] : 10869에 필요한 시간이 늘어났습니다. TreeMap을 구축 할 때 사용법을 테스트했기 때문에 연산보다 작고 작습니다. 비교 연산의 결과/* if (doubles [i] double [i-1]) tmp ++; */was : int cmp [ms]에 필요한 시간 : 8479, double cmp [ms] : 15925에 필요한 시간. – Henry

+1

FYI, "long"데이터 유형에 대한 테스트를 다시 실행했습니다. 뺄셈을위한 결과 : 긴 subs [ms]에 필요한 시간 : 7513, double subs [ms]에 필요한 시간 : 10898. 그리고 비교 결과 : long cmp [ms]에 필요한 시간 : 15768, double cmp에 필요한 시간 [ ms] : 16012. "longs"의 경우, 성능이 동일성 검사와 비슷한 것처럼 보입니다. – Henry

+0

다른 값 유형에 대해 동일한 실행에서 벤치 마크를 수행 할 수 없으면 JVM이 뜨거울 것입니다 –