부동 소수점에서 두 숫자의 평균에 대한 강력한 계산? 부동 소수점 숫자합니다. 평균을 계산하는

하자 x, y두 개의 부동 소수점 숫자합니다. 평균을 계산하는 올바른 방법은 무엇입니까?

순진 방법은 (x+y)/2오버 플로우가 발생할 때 수 xy너무 큽니다. 내 생각 엔 0.5 * x + 0.5 * y아마도 더 나은,하지만 (아마도 비효율적 인)이 곱셈을 포함, 그것은 충분히 좋은 경우에 나는 확실하지 않다. 더 좋은 방법이 있습니까?

내가 놀고있는 또 다른 아이디어는 (y/2)(1 + x/y)if x<=y입니다. 그러나 다시, 나는 이것을 분석하는 방법을 모르겠고 그것이 내 요구 사항을 충족한다는 것을 증명합니다.

또한 계산 된 평균이 >= min(x,y)및 일 것이라는 보장이 필요합니다 <= max(x,y). Don Hatch의 답변 에서 지적 했듯이이 질문을 제기하는 더 좋은 방법은 아마도 가장 정확한 결과를 제공하는 두 숫자의 평균 구현은 무엇입니까? 경우 즉, xy부동 소수점 숫자는 어떻게 부동 소수점 숫자에 가장 가까운을 계산하는 (x+y)/2? 이 경우 계산 평균은 자동 >= min(x,y)이며 <= max(x,y)입니다. 자세한 내용은 Don Hatch의 답변 을 참조하십시오.

참고 : 우선 순위는 강력한 정확성입니다. 효율성이 소모됩니다. 그러나 강력하고 정확한 알고리즘이 많은 경우 가장 효율적인 알고리즘을 선택합니다.



답변

Higham의 수치 알고리즘정확성과 안정성은 이러한 유형의 문제를 분석 할 수있는 방법을 다루고 있다고 생각 합니다. 2 장, 특히 운동 2.8을 참조하십시오.

이 답변에서 나는 Higham의 책에서 실제로 다루지 않은 것을 지적하고 싶습니다 (그 문제에 대해서는 널리 알려지지 않은 것으로 보입니다). 이와 같은 간단한 수치 알고리즘의 속성을 증명 하려는 경우 Haskell의 sbv 와 같은 패키지를 사용하여 z3 과 같은 최신 SMT 솔버 ( 만족도 모듈로 이론 ) 의 기능을 사용할 수 있습니다 . 이것은 연필과 종이를 사용하는 것보다 다소 쉽습니다.

주어졌고 z = ( x + y ) / 2x z y를 만족 하는지 알고 싶습니다 . 다음 하스켈 코드

0≤x≤y

z=(x+y)/2

x≤z≤y
import Data.SBV

test1 :: (SFloat -> SFloat -> SFloat) -> Symbolic SBool
test1 fun =
  do [x, y] <- sFloats ["x", "y"]
     constrain $ bnot (isInfiniteFP x) &&& bnot (isInfiniteFP y)
     constrain $ 0 .<= x &&& x .<= y
     let z = fun x y
     return $ x .<= z &&& z .<= y

test2 :: (SFloat -> SFloat -> SFloat) -> Symbolic SBool
test2 fun =
  do [x, y] <- sFloats ["x", "y"]
     constrain $ bnot (isInfiniteFP x) &&& bnot (isInfiniteFP y)
     constrain $ x .<= y
     let z = fun x y
     return $ x .<= z &&& z .<= y

이 작업을 자동으로 수행하겠습니다 . 다음 test1 fun은 IS 명제는 모든 유한 수레 X , Y0 X Y .

x≤fun(x,y)≤y

x,y

0≤x≤y
λ> prove $ test1 (\x y -> (x + y) / 2)
Falsifiable. Counter-example:
  x = 2.3089316e36 :: Float
  y = 3.379786e38 :: Float

넘친다. 이제 다른 공식을 취한다고 가정 해보십시오

z=x/2+y/2
λ> prove $ test1 (\x y -> x/2 + y/2)
Falsifiable. Counter-example:
  x = 2.3509886e-38 :: Float
  y = 2.3509886e-38 :: Float

점진적 언더 플로로 인해 작동하지 않습니다 ( 모든 산술이 기본 2 이므로 직관적이지 않을 수 있음).

(x/2)×2≠x

이제 :

z=x+(y−x)/2
λ> prove $ test1 (\x y -> x + (y-x)/2)
Q.E.D.

공장! 는 Q.E.D.A는 증거 것을 test1위에서 정의 된 속성은 모든 수레를 위해 보유하고 있습니다.

동일하지만 ( 0 x y 대신)로 제한되는 것은 어떻습니까?

x≤y

0≤x≤y
λ> prove $ test2 (\x y -> x + (y-x)/2)
Falsifiable. Counter-example:
  x = -3.1300826e34 :: Float
  y = 3.402721e38 :: Float

자, 넘치면 z = x + ( y / 2 x / 2 )는 어떻습니까?

y−x

z=x+(y/2−x/2)
λ> prove $ test2 (\x y -> x + (y/2 - x/2))
Q.E.D.

그래서 내가 여기에서 시도한 수식 중 가 작동하는 것처럼 보입니다 (증거와 함께). SMT 솔버 접근법은 연필과 종이로 부동 소수점 오류 분석을 수행하는 것보다 간단한 부동 소수점 수식에 대한 의심에 훨씬 빠른 방법으로 보입니다.

x+(y/2−x/2)

마지막으로 정확성과 안정성의 목표는 종종 성능의 목표와 상충됩니다. 성능을 위해, 나는 컴파일러가 보다 나은 방법을 실제로 보지 못합니다 . 특히 컴파일러는 이것을 기계 명령어로 번역하는 데 많은 노력을 기울이고 있기 때문입니다.

(x+y)/2

PS 이것은 모두 단 정밀도 IEEE754 부동 소수점 산술입니다. 나는 검사 배정 밀도 연산 (교체와를 함께 ), 그것도 작동합니다.

x≤x+(y/2−x/2)≤y

SFloatSDouble

-ffast-math

(x+y)/2

PPPS 조건부없이 간단한 대수적 표현 만 살펴 보았습니다 . 돈 해치공식 은 엄청나게 좋습니다.


답변

첫째, 모든 경우에 가장 정확한 답변을 제공하는 방법이 있다면 필요한 조건을 만족시킬 것입니다. (주 내가 말할 것을 보다는 가장 정확한 답 가장 정확한 대답은, 이후이 승자가있을 수 있습니다.) 증명 : 만약이, 반대로, 당신은 않는 정확한 것과 같이 가능한 대답이 없다 , 그 요구 조건을 만족을 어느 수단 (케이스가되는 또는 더 않음 모순이다) (케이스가있는 더 않음 모순이다).answer<min(x,y)<=max(x,y)min(x,y)min(x,y)<=max(x,y)<answermax(x,y)

따라서 귀하의 질문이 가장 정확한 답변을 찾는 것으로 요약됩니다. IEEE754 산술 전체를 가정하면 다음을 제안합니다.

if max(abs(x),abs(y)) >= 1.:
    return x/2. + y/2.
else:
    return (x+y)/2.

이것이 가장 정확한 답변을 제공한다는 주장은 다소 지루한 사례 분석입니다. 간다 :

  • 사례 max(abs(x),abs(y)) >= 1.:

    • 하위 케이스 x와 y는 비정규 화되지 않습니다.이 경우 계산 된 답변 x/2.+y/2.은 동일한 가수를 조작하므로 (x+y)/2오버플로를 방지하기 위해 확장 된 지수를 가정하면 산출량 과 정확히 동일한 답변을 제공합니다 . 이 답변은 반올림 모드에 따라 다를 수 있지만 어떤 경우이든 IEEE754는 최상의 답변임을 x+y보장 합니다 (계산 된 값 이 수학 x + y에 가장 가까운 근사값을 보장 한다는 사실에서 2로 나눈 값은 정확합니다) 케이스).
    • 하위 사례 x는 비정규 화되었습니다 abs(y)>=1.

      answer = x/2. + y/2.
      = y/2. since abs(x/2.) is so tiny compared to abs(y/2.)
      = the exact mathematical value of y/2
      = a best possible answer.

    • 하위 사례 y는 비정규 화되어 abs(x)>=1있습니다.

  • 사례 max(abs(x),abs(y)) < 1.:
    • 계산 된 하위 사례는 x+y비정규 화 또는 비정규 화 및 “짝수”입니다. 계산 x+y이 정확 하지는 않지만 IEEE754에서는 수학 x + y에 대한 가능한 근사값을 보장합니다. 이 경우 식에서 2로 나눈 이후의 (x+y)/2.정확한 나누기 이므로 계산 된 답 (x+y)/2.은 수학 (x + y) / 2에 대한 가장 근사치입니다.
    • 계산 된 하위 사례 x+y는 비정규 화되고 “홀수”입니다.이 경우 정확히 x, y 중 하나는 비정규 화 및 “홀수”여야합니다. 즉, x, y 중 다른 하나는 반대 부호로 비정규 화되어 계산 x+y됩니다. 정확하게 수학 x + y이므로 (x+y)/2.IEEE754는 수학 (x + y) / 2에 대한 가능한 근사값을 계산합니다.

답변

binary64(이중 정밀도) 계산으로 예시 된 IEEE-754 이진 부동 소수점 형식의 경우 S. Boldo는 아래에 표시된 간단한 알고리즘이 올림 된 평균을 제공함을 공식적으로 증명했습니다.

Sylvie Boldo, “부동 소수점 평균을 계산하는 프로그램의 공식 검증.” 에서 공식 엔지니어링 방법에 관한 국제 회의 , PP. 17-32. Cham, Springer, 2015. ( 온라인 초안 )

(x+y)/2

x/2+y/2

binary64

C∈[2−967,2970]

C

특정 사용 사례에 가장 적합한 성능을 제공합니다.

다음과 같은 예제 ISO-C99코드가 생성됩니다.

double average (double x, double y)
{
    const double C = 1; /* 0x1p-967 <= C <= 0x1p970 */
    return (C <= fabs (x)) ? (x / 2 + y / 2) : ((x + y) / 2);
}

최근 후속 작업에서 S. Boldo와 공동 저자는 FMA (fused multiply-add) 연산과 잘 알려진 정밀도를 사용하여 IEEE-754 10 진수 부동 소수점 형식에 대해 최상의 결과를 얻는 방법을 보여주었습니다. 배가 빌딩 블록 (TwoSum) :

Sylvie Boldo, Florian Faissole 및 Vincent Tourneur, “정확한 10 진수 부동 소수점 수의 평균을 계산하는 공식적으로 입증 된 알고리즘” 에서 컴퓨터 산술 (ARITH 25)에 25 IEEE 심포지엄 6 월 2018 PP. 69-75. ( 초안 온라인 )


답변

그것은 매우 효율적인 성능 현명한에 아주 간단한 방법이되지 않을 수 있지만 (1) 숫자의 확인 것도 이상 없는지 확인하거나 x또는 y(NO 오버 플로우)과 (2) 로 “정확한”부동 소수점을 유지 뺄셈이 사용 되더라도 가능한 추가 (및 (3)) 값은 음수로 저장되지 않습니다.

float difference = max(x, y) - min(x, y);
return min(x, y) + (difference / 2.0);

당신이 경우에 실제로, 정말 정확성을 위해 가고 싶어, 당신도 그 자리에서 분할을 수행 할 필요가 없습니다; 단지의 값을 반환 min(x, y)하고 difference논리적으로 단순화 이상 조작 할 수 있습니다.


답변

더 높은 정밀도로 변환하고 거기에 값을 추가 한 후 다시 변환하십시오.

더 높은 정밀도에는 오버플로가 없어야하며 둘 다 유효한 부동 소수점 범위에 있으면 계산 된 숫자도 내부에 있어야합니다.

그리고 그것들이 정확하지 않으면 최악의 경우 큰 숫자의 절반에 해당합니다.


답변

이론적으로 x/2가수에서 1을 빼서 계산할 수 있습니다.

그러나 실제로 이와 같은 비트 연산을 구현하는 것이 반드시 간단한 것은 아닙니다. 특히 부동 소수점 숫자의 형식을 모르는 경우 특히 그렇습니다.

이 작업을 수행 할 수 있으면 전체 작업이 3 더하기 / 빼기로 감소되어 크게 개선 될 것입니다.


답변

@Roland Heath와 같은 줄을 생각하고 있었지만 아직 언급 할 수는 없습니다.

x/2지수 에서 1을 빼서 계산할 수 있습니다 (가수가 아니라 가수에서 1을 빼면 2^(value_of_exponent-length_of_mantissa)전체 값에서 빼기 ).

일반적인 경우를 제한하지 않고를 가정 해 봅시다 x < y. (경우 x > y, 변수 레이블을 재.하면 x = y, (x+y) / 2간단하다.)

  • 변형 (x+y) / 2으로 x/2 + y/2, (지수에서 하나) 개의 정수 뺄셈에 의해 수행 될 수있는
    • 그러나 표현에 따라 지수에 하한이 있습니다. 1을 빼기 전에 지수가 이미 최소 인 경우이 방법은 특별한 경우 처리가 필요합니다. 최소 지수 는 표현할 x수있는 것 x/2보다 작게 만들 것입니다 (유니티가 암시 적 선행 1로 표시된다고 가정).
    • 대신 지수에서 1을 감산 x, 쉬프트 x(있는 경우, 상기 암시 적 선두 1을 추가)을 순차적으로 우측으로의 가수.
    • 최소값이 아닌 경우 y의 지수에서 1을 뺍니다. 최소값 (y는 가수로 인해 x보다 큼) 인 경우, 가수를 오른쪽으로 하나씩 이동합니다 (있는 경우 암시 적 선행 1 추가).
    • x의 지수에 따라 새 가수를 오른쪽으로 이동합니다 y.
    • 가수가 x완전히 이동 되지 않은 경우 가수에 정수를 더합니다 . 두 지수가 모두 최소 인 경우 선행하는 오버플로가 발생합니다. 오버플로는 암시 적 선행 리더가되기 때문입니다.
  • 하나의 부동 소수점 추가.
    • 특별한 경우는 생각할 수 없습니다. 반올림을 제외하고는 위에서 설명한 이동에도 적용됩니다.