하자 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를 만족 하는지 알고 싶습니다 . 다음 하스켈 코드
0≤x≤yz=(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 .
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≤y0≤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−xz=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)/2PS 이것은 모두 단 정밀도 IEEE754 부동 소수점 산술입니다. 나는 검사 배정 밀도 연산 (교체와를 함께 ), 그것도 작동합니다.
x≤x+(y/2−x/2)≤ySFloat
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. ( 온라인 초안 )
(x+y)/2
x/2+y/2
binary64
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
완전히 이동 되지 않은 경우 가수에 정수를 더합니다 . 두 지수가 모두 최소 인 경우 선행하는 오버플로가 발생합니다. 오버플로는 암시 적 선행 리더가되기 때문입니다.
- 그러나 표현에 따라 지수에 하한이 있습니다. 1을 빼기 전에 지수가 이미 최소 인 경우이 방법은 특별한 경우 처리가 필요합니다. 최소 지수 는 표현할
- 하나의 부동 소수점 추가.
- 특별한 경우는 생각할 수 없습니다. 반올림을 제외하고는 위에서 설명한 이동에도 적용됩니다.