C ++ 함수에서 수치 오류 분석


20

여러 부동 소수점 값 (단일 또는 이중)을 입력으로 사용하고 계산을 수행하며 출력 부동 소수점 값 (단일 또는 이중)을 생성하는 함수가 있다고 가정합니다. 저는 주로 MSVC 2008과 함께 일하고 있지만 MinGW / GCC 와도 함께 일할 계획입니다. C ++로 프로그래밍 중입니다.

결과적으로 얼마나 많은 오류가 발생하는지 프로그래밍 방식으로 측정하는 일반적인 방법은 무엇입니까? 임의의 정밀 라이브러리를 사용해야한다고 가정하면 속도에 신경 쓰지 않으면 가장 좋은 라이브러리는 무엇입니까?

답변:


17

반올림 오류에 대한 좋은 경계를 찾고 있다면 반드시 수차 정밀도 라이브러리가 필요하지 않습니다. 대신 오류 분석 실행을 사용할 수 있습니다.

좋은 온라인 참고 자료를 찾을 수 없었지만 Nick Higham의 저서 "숫자 알고리즘의 정확성과 안정성"의 섹션 3.3에 설명되어 있습니다. 아이디어는 매우 간단합니다.

  1. 각 라인에 단일 산술 연산을 단일 할당 할 수 있도록 코드를 리팩터링하십시오.
  2. 예를 들어 x, 각 변수 에 대해 상수가 할당 x_err되면 0으로 초기화 되는 변수 를 만듭니다 x.
  3. 각 작업, 예를 들어 z = x * y, 변수 업데이트 z_err부동 소수점 연산의 표준 모델을 사용하고 결과 z및 실행 오류 x_erry_err.
  4. 그런 다음 함수의 반환 값에도 해당 _err값이 첨부되어야합니다. 이것은 총 반올림 오류에 대한 데이터 종속적입니다.

까다로운 부분은 3 단계입니다. 가장 간단한 산술 연산의 경우 다음 규칙을 사용할 수 있습니다.

  • z = x + y -> z_err = u*abs(z) + x_err + y_err
  • z = x - y -> z_err = u*abs(z) + x_err + y_err
  • z = x * y -> z_err = u*abs(z) + x_err*abs(y) + y_err*abs(x)
  • z = x / y -> z_err = u*abs(z) + (x_err*abs(y) + y_err*abs(x))/y^2
  • z = sqrt(x) -> z_err = u*abs(z) + x_err/(2*abs(z))

u = eps/2단위 반올림은 어디에 있습니까 ? 예, 대한 규칙 +-동일합니다. 다른 작업에 대한 규칙은에 op(x)적용된 결과의 Taylor 시리즈 확장을 사용하여 쉽게 추출 할 수 있습니다 op(x + x_err). 또는 인터넷 검색을 시도 할 수 있습니다. 또는 Nick Higham의 책을 사용하십시오.

예를 들어 Horner 체계를 사용하여 a점에서 계수의 다항식을 평가하는 다음 Matlab / Octave 코드를 고려하십시오 x.

function s = horner ( a , x )
    s = a(end);
    for k=length(a)-1:-1:1
        s = a(k) + x*s;
    end

첫 번째 단계에서는 다음 두 가지 작업을 분할합니다 s = a(k) + x*s.

function s = horner ( a , x )
    s = a(end);
    for k=length(a)-1:-1:1
        z = x*s;
        s = a(k) + z;
    end

그런 다음 _err변수 를 소개합니다 . 참고 입력 것을 ax가정은 정확하게,하지만 우리는 단지뿐만 아니라 또한 값을 해당 통과하도록 사용자에게 요구할 수 a_errx_err:

function [ s , s_err ] = horner ( a , x )
    s = a(end);
    s_err = 0;
    for k=length(a)-1:-1:1
        z = x*s;
        z_err = ...;
        s = a(k) + z;
        s_err = ...;
    end

마지막으로 위에서 설명한 규칙을 적용하여 오류 조건을 얻습니다.

function [ s , s_err ] = horner ( a , x )
    u = eps/2;
    s = a(end);
    s_err = 0;
    for k=length(a)-1:-1:1
        z = x*s;
        z_err = u*abs(z) + s_err*abs(x);
        s = a(k) + z;
        s_err = u*abs(s) + z_err;
    end

우리는 더이 있기 때문에주의 a_err또는 x_err예를 들어, 그들은 0으로 가정되지는 각각의 용어는 단순히 오류 표현식에서 무시됩니다.

vo! 이제 결과와 함께 데이터 종속 오류 추정값 (참고 : 오류의 상한값) 을 반환하는 Horner 체계가 있습니다.

부수적으로, C ++을 사용하고 있기 때문에, _err용어를 둘러싼 부동 소수점 값을위한 클래스를 직접 만들고 모든 산술 연산을 오버로드하여 위에서 설명한대로 이러한 값을 업데이트하는 것을 고려할 수 있습니다 . 큰 코드의 경우 계산이 덜 효율적이지만 경로가 더 쉬울 수 있습니다. 그렇게 말하면 온라인에서 그러한 수업을 찾을 수 있습니다. 빠른 Google 검색 으로이 링크가 제공되었습니다 .

±엑스(1±)


1
이 분석은 +1이기 때문에 흥미 롭습니다. 나는 Higham의 일을 좋아한다. 나에게 중요한 것은 사용자가 숫자 연산의 수가 많아짐에 따라 반자동과 같은 반자동 대신 수동으로 추가 코드를 작성하도록 요구하면 오류가 발생하기 쉽다는 것입니다.
Geoff Oxberry

1
@ GeoffOxberry : 나는 복잡성 문제에 전적으로 동의합니다. 더 큰 코드의 경우 각 작업을 한 번만 올바르게 구현 해야하는 것처럼 더블에 작업을 오버로드하는 클래스 / 데이터 유형을 작성하는 것이 좋습니다. Matlab / Octave에는 이와 같은 것이없는 것 같습니다.
Pedro

이 분석이 마음에 들지만 오류 항의 계산도 부동 소수점으로 수행되므로 부동 소수점 오류로 인해 해당 오류 항이 부정확하지 않습니까?
plasmacel

8

임의의 정밀 부동 소수점 산술 (및 기타 여러 가지)을위한 이식성이 뛰어난 휴대용 오픈 소스 라이브러리는 Victor Shoup의 NTL 이며 C ++ 소스 형식으로 제공됩니다.

하위 레벨 에는 오픈 소스 패키지 인 GMP (GNU Multiple Precision) Bignum 라이브러리 가 있습니다.

NTL은 GMP와 함께 사용할 수 있지만 더 빠른 성능이 필요하지만 NTL은 "속도에 신경 쓰지 않으면"확실히 사용할 수있는 자체 기본 루틴을 제공합니다. GMP는 "가장 빠른 빅넘 라이브러리"라고 주장합니다. GMP는 주로 C로 작성되었지만 C ++ 인터페이스가 있습니다.

추가 : 간격 산술은 자동으로 정확한 답에 상한과 하한을 줄 수 있지만 간격 크기는 일반적으로 각 작업마다 증가합니다 (상대 또는 절대 오류 감지).

반올림 오류 또는 이산화 오류 등의 오류 크기를 찾는 일반적인 방법은 추가 정밀도 값을 계산하고이를 "표준"정밀도 값과 비교하는 것입니다. 반올림 오류만으로도 추가 정밀도 계산에서보다 "표준"정밀도에서 실질적으로 더 크기 때문에, 오차 크기 자체를 합리적인 정확도로 결정하기 위해서는 약간의 추가 정밀도 만 필요합니다.

단 정밀도와 배정 밀도 계산을 비교하여 요점을 설명 할 수 있습니다. C ++에서 중간 표현식은 항상 (최소한) 배정 밀도로 계산되므로 "순수한"단 정밀도의 계산이 어떤지 설명하려면 중간 값을 단 정밀도로 저장해야합니다.

C 코드 스 니펫

    float fa,fb;
    double da,db,err;
    fa = 4.0;
    fb = 3.0;
    fa = fa/fb;
    fa -= 1.0;

    da = 4.0;
    db = 3.0;
    da = da/db;
    da -= 1.0;

    err = fa - da;
    printf("Single precision error wrt double precision value\n");
    printf("Error in getting 1/3rd is %e\n",err);
    return 0;

위의 출력 (Cygwin / MinGW32 GCC 툴 체인) :

Single precision error wrt double precision value
Error in getting 1/3rd is 3.973643e-08

따라서 오차는 1/3을 단 정밀도로 반올림하는 데 필요한 것입니다. 오차의 측정은 정확도가 아니라 크기에 대한 것이기 때문에 오차 정정 에서 소수점 이하 두 자리 이상을 얻는 것에 대해서는 신경 쓰지 않을 것입니다.


당신의 접근 방식은 수학적으로 확실합니다. 트레이드 오프가 엄격하다고 생각합니다. 오류에 대해 pedantic 한 사람들은 간격 산술의 엄격함을 지적하지만 많은 응용 프로그램에서 추가 정밀도로 컴퓨팅하면 충분할 것으로 예상되며 결과 오류 추정은 더 엄격 할 것입니다.
Geoff Oxberry

이것이 내가 사용할 것이라고 상상했던 접근법입니다. 응용 프로그램에 가장 적합한 기술을 찾기 위해 이러한 여러 가지 기술을 시도해 볼 수 있습니다. 코드 예제 업데이트는 대단히 감사합니다!
user_123abc

7

GMP (GNU 다중 정밀도 라이브러리)는 내가 아는 최고의 임의 정밀도 라이브러리입니다.

임의의 부동 소수점 함수의 결과에서 오류를 측정하는 프로그래밍 방식을 모르겠습니다. 시도 할 수있는 한 가지는 간격 산술을 사용하여 함수의 간격 확장을 계산하는 것 입니다. C ++에서는 간격 확장을 계산하기 위해 일종의 라이브러리를 사용해야합니다. 그러한 라이브러리 중 하나는 Boost Interval Arithmetic Library입니다. 기본적으로 오류를 측정하기 위해 관심있는 값을 중심으로 너비가 단위 반올림 (거의)의 2 배인 함수 간격에 인수로 제공 한 다음 출력은 간격의 모음이됩니다. 이는 오류에 대한 보수적 인 추정치를 제공합니다. 이 방식의 어려움은 이러한 방식으로 사용되는 구간 산술이 오류를 상당량 과대 평가할 수 있지만이 방식은 제가 생각할 수있는 가장 "프로그래밍 방식"입니다.


아, 방금 당신의 대답에 언급 된 간격 산술을 보았습니다 ... 공감!
Ali

2
Richard Harris는 ACCU 저널 Overload 에서 Floating Point Blues에 관한 훌륭한 기사를 썼습니다 . 구간 산술 에 대한 그의 기사 는 과부하 103 ( pdf , p19-24)에 있습니다.
Mark Booth

6

간격 분석을 통해 엄격하고 자동적 인 오류 추정을 수행 할 수 있습니다 . 숫자 대신 간격으로 작업합니다. 예를 들면 다음과 같습니다.

[a,b] + [c,d] = [min(a+c, a+d, b+c, b+d), max (a+c, a+d, b+c, b+d)] = [a+c, b+d]

반올림도 엄격하게 처리 할 수 ​​있습니다 ( 반올림 간격 산술 참조) .

입력 값이 좁은 간격으로 구성되어 있으면 추정값은 정상이며 계산하기에 비용이 많이 들지 않습니다. 불행히도, 오류는 종종 과대 평가 됩니다. 종속성 문제를 참조하십시오 .

나는 임의의 정밀 간격 산술 라이브러리를 모른다.

인터벌 산술이 귀하의 요구를 충족시킬 수 있는지 여부는 귀하의 문제에 달려 있습니다.


4

GNU MPFR 라이브러리는 자신의 주요 초점 포인트 중 하나 (쉽게는 소리없는 모든 작업 특히, 정확한 반올림에) 높은 정확도를 가지고 임의의 정밀도 부동 소수점 라이브러리입니다. 후드 아래에서 GNU MP를 사용합니다. Geoff의 답변에서 알 수 있듯이 MPFI 라는 확장 기능 은 간격 산술을 수행 하여 확인 목적으로 유용 할 수 있습니다. 결과 간격이 작은 범위 내에 들어갈 때까지 작업 정밀도를 계속 유지하십시오.

그러나 이것이 항상 작동하지는 않습니다. 특히 모든 단계가 반올림 문제와 무관하게 "오류"를 발생시키는 수치 적분과 같은 작업을 수행하는 경우 반드시 효과적 일 필요는 없습니다. 이 경우 특정 알고리즘을 사용하여 통합 오류를 제한하고 간격 대신 소위 Taylor 모델을 사용하는 COZY 무한대 와 같은 특수 패키지를 사용해보십시오 .


동의한다; 수치 적분은 순진한 간격 산술이 잘못 될 수있는 경우입니다. 그러나 Taylor 모델조차도 구간 산술을 사용합니다. 나는 Makino와 Berz의 작업에 익숙하며 RE Moore의 의미에서 Taylor 모델을 사용한다고 생각하지만 "differential algebra"라고하는 트릭도 사용합니다.
Geoff Oxberry

@GeoffOxberry : 예-이 미분 대수는 적분 단계의 오류에 구속력이 있다고 생각합니다.
Erik P.

0

MPIR은 Visual Studio로 작업하는 경우 사용할 수있는 좋은 라이브러리라고 들었습니다.

http://mpir.org/


SciComp.SE에 오신 것을 환영합니다! 이 라이브러리를 사용하여 부동 소수점 계산 오류를 측정하는 방법에 대한 세부 정보를 추가 할 수 있습니까?
Christian Clason

나는 시도 할 것이다; 실제로 컴퓨터에 아직 MPIR을 설정하지 않았습니다! GMP와 MPFR을 설정했습니다.
fishermanhat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.