2016-12-09 7 views
3

C++ 헤더 <complex>abs(z)norm(z)을 제공합니다.C++은 어떻게 오버플로를 방지하면서 복소수의 절대 값을 계산합니까?

복소수 z = x + iy의 norm은 norm(z) : = x^2 + y^2입니다.

z의 절대 값은 abs(z) : = sqrt (norm (z))입니다.

그러나 다음 예제에서는 abs(z)이 다르게 구현되어야 함을 보여줍니다. norm(z)이 오버플로하지 않기 때문에. 적어도 g ++ 6.2.1에서는 오버플로가 발생하지 않습니다.

표준에 따라 오버플로가 보장되지 않습니까? 그것은 어떻게 성취됩니까?

#include <iostream> 
#include <complex> 
typedef std::complex<double> complex_t; 

int main() 
{ 
    complex_t z = { 3e200, 4e200 }; 
    double a = abs(z); 
    double n = norm(z); 

    std::cout << a << " -> " << std::isinf(a) << "\n"; 
    std::cout << n << " -> " << std::isinf(n) << "\n"; 

    return 0; 
} 

출력 : std::complex::abs 실제로 계산의 중간 단계에서 오버 플로우와 언더 플로우를 방지하도록 보장 std::hypot 함수에 상당

5e+200 -> 0 
inf -> 1 
+1

봐. 적어도 내 시스템에서는 abs (실수 부분), abs (imag 부분)의 최대 값을 먼저 나눈 다음 곱합니다. 이는 오버 플로우가 발생하지 않는 이유 일 수 있습니다. –

+1

libstdC++와 다른 점이 있습니다 :'abs'에 대한 계산은 direct ([source] (https://code.woboq.org/gcc/libstdc++-v3/include/std/complex.html#572)입니다.)), norm에 대한 계산은 절대 값 ([source] (https://code.woboq.org/gcc/libstdc++-v3/include/std/complex.html#652))을 제곱합니다. Abs는 또한 실제 부분과 허수 부분을 최대로 나누었습니다. 아마도 오버플로를 방지하기 위해서입니다. – peppe

답변

2

.

Wikipedia page on Hypot function 구현에 대한 통찰력을 제공합니다.

나는 경우에는 바로 의사를 인용합니다 : 헤더 파일에서 구현을

// hypot for (x, y) != (0, 0) 
double hypot(double x,double y) 
{ 
    double t; 
    x = abs(x); 
    y = abs(y); 
    t = min(x,y); 
    x = max(x,y); 
    t = t/x; 
    return x*sqrt(1+t*t); 
} 
+1

libm이 할 일이 아니라는 점에 유의하십시오. 이 구현은 1ULP 에러 바운드를주지 않을 것입니다. –

+1

@ YanZhou 오, 그렇습니다. 정밀도는이 의사 코드가 전혀 발생하지 않습니다. 그러나 오버 플로우 상황을 설명합니다. "실제 코드"는 [this]와 유사합니다 (https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=sysdeps/ieee754/dbl-64/e_hypot.c). – Ap31