하자 x
, y
두 개의 부동 소수점 숫자합니다. 평균을 계산하는 올바른 방법은 무엇입니까?
순진 방법은 (x+y)/2
오버 플로우가 발생할 때 수 x
와 y
너무 큽니다. 내 생각 엔 0.5 * x + 0.5 * y
아마도 더 나은,하지만 (아마도 비효율적 인)이 곱셈을 포함, 그것은 충분히 좋은 경우에 나는 확실하지 않다. 더 좋은 방법이 있습니까?
내가 놀고있는 또 다른 아이디어는 (y/2)(1 + x/y)
if x<=y
입니다. 그러나 다시, 나는 이것을 분석하는 방법을 모르겠고 그것이 내 요구 사항을 충족한다는 것을 증명합니다.
또한 계산 된 평균이 >= min(x,y)
및 일 것이라는 보장이 필요합니다 <= max(x,y)
. Don Hatch의 답변 에서 지적 했듯이이 질문을 제기하는 더 좋은 방법은 아마도 가장 정확한 결과를 제공하는 두 숫자의 평균 구현은 무엇입니까? 경우 즉, x
및 y
부동 소수점 숫자는 어떻게 부동 소수점 숫자에 가장 가까운을 계산하는 (x+y)/2
? 이 경우 계산 평균은 자동 >= min(x,y)
이며 <= max(x,y)
입니다. 자세한 내용은 Don Hatch의 답변 을 참조하십시오.
참고 : 우선 순위는 강력한 정확성입니다. 효율성이 소모됩니다. 그러나 강력하고 정확한 알고리즘이 많은 경우 가장 효율적인 알고리즘을 선택합니다.
답변
Higham의 수치 알고리즘 의 정확성과 안정성은 이러한 유형의 문제를 분석 할 수있는 방법을 다루고 있다고 생각 합니다. 2 장, 특히 운동 2.8을 참조하십시오.
이 답변에서 나는 Higham의 책에서 실제로 다루지 않은 것을 지적하고 싶습니다 (그 문제에 대해서는 널리 알려지지 않은 것으로 보입니다). 이와 같은 간단한 수치 알고리즘의 속성을 증명 하려는 경우 Haskell의 sbv 와 같은 패키지를 사용하여 z3 과 같은 최신 SMT 솔버 ( 만족도 모듈로 이론 ) 의 기능을 사용할 수 있습니다 . 이것은 연필과 종이를 사용하는 것보다 다소 쉽습니다.
주어졌고 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 , Y 와 0 ≤ X ≤ Y .
λ> prove $ test1 (\x y -> (x + y) / 2)
Falsifiable. Counter-example:
x = 2.3089316e36 :: Float
y = 3.379786e38 :: Float
넘친다. 이제 다른 공식을 취한다고 가정 해보십시오
λ> prove $ test1 (\x y -> x/2 + y/2)
Falsifiable. Counter-example:
x = 2.3509886e-38 :: Float
y = 2.3509886e-38 :: Float
점진적 언더 플로로 인해 작동하지 않습니다 ( 모든 산술이 기본 2 이므로 직관적이지 않을 수 있음).
이제 :
λ> prove $ test1 (\x y -> x + (y-x)/2)
Q.E.D.
공장! 는 Q.E.D.
A는 증거 것을 test1
위에서 정의 된 속성은 모든 수레를 위해 보유하고 있습니다.
동일하지만 ( 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 )는 어떻습니까?
λ> prove $ test2 (\x y -> x + (y/2 - x/2))
Q.E.D.
그래서 내가 여기에서 시도한 수식 중 가 작동하는 것처럼 보입니다 (증거와 함께). SMT 솔버 접근법은 연필과 종이로 부동 소수점 오류 분석을 수행하는 것보다 간단한 부동 소수점 수식에 대한 의심에 훨씬 빠른 방법으로 보입니다.
마지막으로 정확성과 안정성의 목표는 종종 성능의 목표와 상충됩니다. 성능을 위해, 나는 컴파일러가 보다 나은 방법을 실제로 보지 못합니다 . 특히 컴파일러는 이것을 기계 명령어로 번역하는 데 많은 노력을 기울이고 있기 때문입니다.
PS 이것은 모두 단 정밀도 IEEE754 부동 소수점 산술입니다. 나는 검사 배정 밀도 연산 (교체와를 함께 ), 그것도 작동합니다.
SFloat
SDouble
-ffast-math
PPPS 조건부없이 간단한 대수적 표현 만 살펴 보았습니다 . 돈 해치 의 공식 은 엄청나게 좋습니다.
답변
첫째, 모든 경우에 가장 정확한 답변을 제공하는 방법이 있다면 필요한 조건을 만족시킬 것입니다. (주 내가 말할 것을 보다는 가장 정확한 답 가장 정확한 대답은, 이후이 승자가있을 수 있습니다.) 증명 : 만약이, 반대로, 당신은 않는 정확한 것과 같이 가능한 대답이 없다 , 그 요구 조건을 만족을 어느 수단 (케이스가되는 또는 더 않음 모순이다) (케이스가있는 더 않음 모순이다).answer<min(x,y)<=max(x,y)
min(x,y)
min(x,y)<=max(x,y)<answer
max(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
있습니다.
- 하위 케이스 x와 y는 비정규 화되지 않습니다.이 경우 계산 된 답변
- 사례
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. ( 온라인 초안 )
binary64
특정 사용 사례에 가장 적합한 성능을 제공합니다.
다음과 같은 예제 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
완전히 이동 되지 않은 경우 가수에 정수를 더합니다 . 두 지수가 모두 최소 인 경우 선행하는 오버플로가 발생합니다. 오버플로는 암시 적 선행 리더가되기 때문입니다.
- 그러나 표현에 따라 지수에 하한이 있습니다. 1을 빼기 전에 지수가 이미 최소 인 경우이 방법은 특별한 경우 처리가 필요합니다. 최소 지수 는 표현할
- 하나의 부동 소수점 추가.
- 특별한 경우는 생각할 수 없습니다. 반올림을 제외하고는 위에서 설명한 이동에도 적용됩니다.