가장 정확한 결과를 얻으려면 어떤 순서로 수레를 추가해야합니까?


105

이것은 최근 인터뷰에서 물어 본 질문이었고 알고 싶습니다 (실제로 수치 분석 이론을 기억하지 못하므로 저를 도와주세요 :)

부동 소수점 숫자를 누적하는 함수가있는 경우 :

std::accumulate(v.begin(), v.end(), 0.0);

vA는 std::vector<float>, 예를 들면.

  • 이 숫자를 누적하기 전에 정렬하는 것이 더 낫습니까?

  • 어떤 순서가 가장 정확한 답을 줄까요?

나는 의심 정렬 오름차순으로 번호 것은 실제로 수치 오류 만들 것 하지만, 불행히도 내가 직접 증명할 수 없습니다.

추신 : 나는 이것이 아마도 실제 프로그래밍과 관련이 없다는 것을 알고 있습니다.


17
이것은 실제로 실제 프로그래밍과 관련이 있습니다. 그러나 많은 응용 프로그램은 '아주 가깝다'는 한 계산의 절대적인 최고의 정확성에 대해 실제로 신경 쓰지 않습니다. 엔지니어링 애플리케이션? 매우 중요한. 의료 애플리케이션? 매우 중요한. 대규모 통계? 정확도가 다소 떨어집니다.
Zéychin 2011

18
실제로 알고 있고 자세한 이유를 설명하는 페이지를 가리킬 수있는 경우가 아니면 대답하지 마십시오. 이미 우리가 주위를 날아 다니는 부동 소수점 숫자에 대해 너무 많은 쓰레기가 있습니다. 당신이 알고 있다고 생각한다면. 중지. 당신이 알고 있다고 생각한다면 아마 틀렸을 것입니다.
Martin York

4
@ Zéychin "엔지니어링 애플리케이션? 매우 중요합니다. 의료 애플리케이션? 매우 중요합니다."??? 나는 당신이 진실을 :) 알고 있다면 당신은 놀랄 것이라고 생각
BЈовић

3
@Zeychin 절대 오류는 관련이 없습니다. 중요한 것은 상대 오차입니다. 수백 분의 1 라디안이 0.001 %이면 누가 신경 쓰나요?
BЈовић 2011-07-14

3
필자는이 책을 정말 추천합니다 : "모든 컴퓨터 과학자가 부동 소수점에 대해 알아야하는 것" perso.ens-lyon.fr/jean-michel.muller/goldberg.pdf
Mohammad Alaggan

답변:


108

본능은 기본적으로 옳습니다. 오름차순 (크기)으로 정렬하면 일반적으로 상황이 다소 개선됩니다. 단 정밀도 (32 비트) 부동 소수점을 추가하고 1 / (10 억)에 해당하는 10 억 개의 값과 1에 해당하는 1 개의 값이있는 경우를 생각해보십시오. 1이 먼저 오면 합계가 나옵니다. 정밀도 손실로 인해 1 + (1/10 억)이 1이므로 1로 설정됩니다. 각 추가는 합계에 전혀 영향을주지 않습니다.

작은 값이 먼저 나오면 적어도 어떤 값이 합산 될 것입니다. 그래도 2 ^ 30 개가있는 반면 2 ^ 25 정도 후에는 각각이 개별적으로 총계에 영향을주지 않는 상황으로 돌아 왔습니다. 더 이상. 그래서 나는 여전히 더 많은 트릭이 필요할 것입니다.

이는 극단적 인 경우이지만 일반적으로 비슷한 크기의 두 값을 추가하는 것이 크기가 매우 다른 두 값을 추가하는 것보다 더 정확합니다. 그렇게하면 더 작은 값에서 더 적은 정밀도 비트를 "삭제"하기 때문입니다. 숫자를 정렬하여 비슷한 크기의 값을 함께 그룹화하고 오름차순으로 추가하면 작은 값이 누적 적으로 큰 숫자의 크기에 도달 할 "가능성"을 부여합니다.

그래도 음수가 관련되면이 접근 방식을 "앞으로"하기 쉽습니다. 합할 세 값을 고려하십시오 {1, -1, 1 billionth}. 산술적으로 정확한 합계는 1 billionth이지만 첫 번째 추가에 작은 값이 포함되면 최종 합계는 0이됩니다. 가능한 주문 6 개 중 2 개만 "올바른"- {1, -1, 1 billionth}{-1, 1, 1 billionth}. 6 개 차수는 모두 입력에서 가장 큰 크기 값 (0.0000001 % 출력)에서 정확한 결과를 제공하지만 그 중 4 개에 대해 실제 솔루션 (100 % 출력)에서는 결과가 부정확합니다. 해결하려는 특정 문제는 전자가 충분히 좋은지 여부를 알려줍니다.

사실, 정렬 된 순서로 추가하는 것보다 훨씬 더 많은 트릭을 사용할 수 있습니다. 매우 작은 값이 많고 중간 값이 많고 큰 값이 적은 경우 먼저 작은 값을 모두 더한 다음 중간 값을 따로 합하고이 두 합계를 더하는 것이 가장 정확할 수 있습니다. 함께 큰 것을 추가하십시오. 부동 소수점 추가의 가장 정확한 조합을 찾는 것은 결코 사소한 일이 아니지만, 정말 나쁜 경우에 대처하기 위해 전체 누적 합계 배열을 다른 크기로 유지하고 해당 크기와 가장 일치하는 합계에 각각의 새 값을 추가 할 수 있습니다. 누적 합계가 크기에 비해 너무 커지기 시작하면 다음 합계에 추가하고 새 합계를 시작합니다. 논리적 인 극단으로 볼 때이 프로세스는 임의 정밀도 유형으로 합계를 수행하는 것과 동일합니다. d). 그러나 오름차순 또는 내림차순으로 추가하는 단순한 선택을 고려할 때 오름차순이 더 나은 방법입니다.

실제 프로그래밍과 약간의 관련이 있습니다. 왜냐하면 각각의 값이 너무 작아서 개별적으로 영향을주기에는 너무 작은 값으로 구성된 "무거운"꼬리를 실수로 잘라 내면 계산이 매우 잘못 될 수있는 경우가 있기 때문입니다. 합계 또는 합계의 마지막 몇 비트에만 개별적으로 영향을 미치는 많은 작은 값에서 너무 많은 정밀도를 버리는 경우. 어쨌든 꼬리가 무시할만한 경우에는 아마도 신경 쓰지 않을 것입니다. 예를 들어, 처음에 적은 수의 값만 더하고 합의 유효 숫자 만 사용하는 경우입니다.


8
설명은 +1. 덧셈은 일반적으로 (빼기와 나눗셈과는 달리) 수치 적으로 안정적이기 때문에 다소 직관적이지 않습니다.
Konrad Rudolph

2
@Konrad, 수치 적으로 안정적 일 수 있지만 피연산자의 크기가 다르기 때문에 정확하지는 않습니다. :)
MSN

3
@ 6502 : 크기 순으로 정렬되어 있으므로 -1이 끝에옵니다. 총계의 실제 값이 크기 1이면 괜찮습니다. 1/10 억, 1, -1의 세 가지 값을 더하면 0이됩니다.이 시점에서 흥미로운 실제 질문에 답해야합니다. 진정한 합계입니까, 아니면 가장 큰 값의 척도로 정확한 답만 필요합니까? 일부 실용적인 응용 프로그램의 경우 후자가 충분하지만 그렇지 않은 경우 더 정교한 접근 방식이 필요합니다. 양자 물리학은 재 정규화를 사용합니다.
Steve Jessop 2011

8
이 간단한 계획을 고수하려면 항상 가장 낮은 크기의 두 숫자를 더하고 합계를 다시 삽입합니다. (음, 아마도 병합 정렬이 여기에서 가장 잘 작동 할 것입니다. 이전에 합산 된 숫자를 포함하는 배열 부분을 부분 합의 작업 영역으로 사용할 수 있습니다.)
Neil

2
@Kevin Panko : 간단한 버전은 단 정밀도 부동 소수점에 24 개의 이진수가 있으며 그 중 가장 큰 숫자는 숫자에서 가장 큰 세트 비트입니다. 따라서 크기가 2 ^ 24보다 큰 두 개의 숫자를 더하면 더 작은 값의 총 손실이 발생하고 크기가 더 작게 차이가 나면 더 작은 정확도의 비트 수를 잃게됩니다. 번호.
Steve Jessop 2011

88

Kahan Summation 이라는 이러한 종류의 누적 연산을 위해 설계된 알고리즘도 있습니다.

Wikipedia에 따르면

Kahan 합계 알고리즘 (라고도 보상 합산 ) 상당히 명백 접근법에 비해 제한된 정밀도 부동 소수점 숫자의 시퀀스를 가산 한 합계 수치 에러를 감소시킨다. 이는 별도의 실행 보상 (작은 오류를 누적하는 변수)을 유지하여 수행됩니다.

의사 코드에서 알고리즘은 다음과 같습니다.

function kahanSum(input)
 var sum = input[1]
 var c = 0.0          //A running compensation for lost low-order bits.
 for i = 2 to input.length
  y = input[i] - c    //So far, so good: c is zero.
  t = sum + y         //Alas, sum is big, y small, so low-order digits of y are lost.
  c = (t - sum) - y   //(t - sum) recovers the high-order part of y; subtracting y recovers -(low part of y)
  sum = t             //Algebraically, c should always be zero. Beware eagerly optimising compilers!
 next i               //Next time around, the lost low part will be added to y in a fresh attempt.
return sum

3
이 스레드에 +1 멋진 추가. 이러한 명령문을 "열심히 최적화"하는 컴파일러는 금지되어야합니다.
Chris A.

1
두 개의 합산 변수 sumc다른 크기 를 사용하여 정밀도를 거의 두 배로 늘리는 간단한 방법 입니다. N 개의 변수로 간단하게 확장 할 수 있습니다.
MSalters

2
@ChrisA. 잘 계산하는 모든 컴파일러에서 이것을 명시 적으로 제어 할 수 있습니다 (예 : -ffast-mathGCC 를 통해 ).
Konrad Rudolph

6
@Konrad Rudolph는 이것이 가능한 최적화라는 점을 지적 해 주셔서 감사합니다 -ffast-math. 이 토론 과이 링크 에서 배운 것은 수치 정확도에 관심이 있다면 아마 사용을 피해야 -ffast-math하지만 CPU에 묶여있을 수 있지만 정확한 수치 계산에는 신경 쓰지 않는 많은 애플리케이션에서 사용하는 것입니다 (예 : 게임 프로그래밍 ), -ffast-math사용하기에 합리적입니다. 따라서 저는 "금지"라는 강하게 표현 된 코멘트를 수정하고 싶습니다.
Chris A.

배정 밀도 변수를 사용 sum, c, t, y하면 도움이됩니다. sum -= c전에 에 추가해야합니다 return sum.
G. Cohen

34

Steve Jessop이 제공 한 답변에서 극단적 인 예를 시도했습니다.

#include <iostream>
#include <iomanip>
#include <cmath>

int main()
{
    long billion = 1000000000;
    double big = 1.0;
    double small = 1e-9;
    double expected = 2.0;

    double sum = big;
    for (long i = 0; i < billion; ++i)
        sum += small;
    std::cout << std::scientific << std::setprecision(1) << big << " + " << billion << " * " << small << " = " <<
        std::fixed << std::setprecision(15) << sum <<
        "    (difference = " << std::fabs(expected - sum) << ")" << std::endl;

    sum = 0;
    for (long i = 0; i < billion; ++i)
        sum += small;
    sum += big;
    std::cout  << std::scientific << std::setprecision(1) << billion << " * " << small << " + " << big << " = " <<
        std::fixed << std::setprecision(15) << sum <<
        "    (difference = " << std::fabs(expected - sum) << ")" << std::endl;

    return 0;
}

다음과 같은 결과를 얻었습니다.

1.0e+00 + 1000000000 * 1.0e-09 = 2.000000082740371    (difference = 0.000000082740371)
1000000000 * 1.0e-09 + 1.0e+00 = 1.999999992539933    (difference = 0.000000007460067)

첫 번째 줄의 오류는 두 번째 줄의 10 배 이상 더 큽니다.

위 코드에서 doubles를 floats로 변경하면 다음과 같은 결과가 나타납니다.

1.0e+00 + 1000000000 * 1.0e-09 = 1.000000000000000    (difference = 1.000000000000000)
1000000000 * 1.0e-09 + 1.0e+00 = 1.031250000000000    (difference = 0.968750000000000)

두 답변 모두 2.0에 가깝지는 않지만 두 번째 답변은 약간 더 가깝습니다.

doubleDaniel Pryden이 설명한대로 Kahan 합계 ( s 포함) 사용 :

#include <iostream>
#include <iomanip>
#include <cmath>

int main()
{
    long billion = 1000000000;
    double big = 1.0;
    double small = 1e-9;
    double expected = 2.0;

    double sum = big;
    double c = 0.0;
    for (long i = 0; i < billion; ++i) {
        double y = small - c;
        double t = sum + y;
        c = (t - sum) - y;
        sum = t;
    }

    std::cout << "Kahan sum  = " << std::fixed << std::setprecision(15) << sum <<
        "    (difference = " << std::fabs(expected - sum) << ")" << std::endl;

    return 0;
}

정확히 2.0 :

Kahan sum  = 2.000000000000000    (difference = 0.000000000000000)

위 코드에서 doubles를 floats로 변경해도 다음과 같은 결과가 나타납니다 .

Kahan sum  = 2.000000000000000    (difference = 0.000000000000000)

Kahan이 갈 길인 것 같습니다!


내 "큰"값은 1e9가 아니라 1입니다. 증가하는 크기 순서로 추가 된 두 번째 답변은 수학적으로 정확합니다 (10 억에 10 억분의 1을 더한 값은 10 억과 1입니다). 운이 좋게도 방법의 일반적인 건전성은 더 많지만 :-) double나쁘지 않습니다. 10 억분의 1을 더할 때 정밀도가 떨어 float집니다.
Steve Jessop 2011

@Steve, 내 오류, 사과드립니다. 의도 한대로 예제 코드를 업데이트했습니다.
Andrew Stein

4
Kahan은 여전히 ​​정밀도가 제한되어 있지만 킬러 케이스를 구성 c하려면 다음 합계 보다 훨씬 큰 값을 포함하기 위해 주 합계와 오류 누적 기가 모두 필요합니다 . 이것은 합계가 주 합계보다 훨씬 더 작다는 것을 의미합니다. 그래서 많은 것을 더하기 위해 그것들이 엄청나게 많아야 할 것입니다. 특히 double산술에서.
Steve Jessop 2011-07-15

14

데이터를 정렬하거나 재정렬 할 필요없이이 정확한 문제를 해결하는 알고리즘 클래스가 있습니다 .

즉, 데이터를 한 번에 합산 할 수 있습니다. 이는 또한 데이터 세트가 미리 알려지지 않은 상황 (예 : 데이터가 실시간으로 도착하고 누적 합계를 유지해야하는 경우)에서 이러한 알고리즘을 적용 할 수있게합니다.

다음은 최근 논문의 요약입니다.

우리는 부동 소수점 숫자 스트림의 정확한 합계를위한 새로운 온라인 알고리즘을 제시합니다. "온라인"이란 알고리즘이 한 번에 하나의 입력 만 볼 필요가 있고 이러한 입력의 임의 길이 입력 스트림을 가져 오면서 일정한 메모리 만 요구할 수 있음을 의미합니다. "정확함"이란 알고리즘의 내부 배열의 합이 모든 입력의 합과 정확히 같고 반환 된 결과가 올바로 반올림 된 합임을 의미합니다. 정확성 증명은 모든 입력 (정규화되지 않은 숫자 포함하지만 모듈로 중간 오버플로 포함)에 대해 유효하며 합계의 수 또는 합계의 조건 번호와 무관합니다. 알고리즘은 점근 적으로 summand 당 5 개의 FLOP 만 필요하며 명령 수준 병렬 처리로 인해 명백한 것보다 약 2-3 배 느리게 실행됩니다. summand 수가 10,000보다 클 때 빠르고 멍청한 "보통 재귀 합산"루프. 따라서 우리가 아는 한, 알려진 알고리즘 중에서 가장 빠르고 정확하며 메모리 효율성이 가장 높습니다. 실제로 하드웨어 개선없이 더 빠른 알고리즘이나 훨씬 적은 FLOP이 필요한 알고리즘이 어떻게 존재할 수 있는지 확인하기가 어렵습니다. 다수의 요약에 대한 응용 프로그램이 제공됩니다.

출처 : 알고리즘 908 : 부동 소수점 스트림의 온라인 정확한 합계 .


1
@Inverse : 주변에 여전히 벽돌과 박격포 라이브러리가 있습니다. 또는 PDF 온라인 구매 비용은 $ 5- $ 15입니다 (ACM 회원인지 여부에 따라 다름). 마지막으로, DeepDyve는 24 시간 동안 $ 2.99 (DeepDyve를 처음 사용하는 경우 무료 평가판의 일부로 무료로받을 수도 있음)에 논문을 빌려줄 것을 제안하는 것 같습니다. deepdyve.com/lp/acm /…
NPE 2011

2

먼저 숫자를 오름차순으로 정렬하는 Steve의 답변을 바탕으로 두 가지 아이디어를 더 소개합니다.

  1. 너무 많은 정밀도를 잃을 것이라고 결정할 수있는 두 숫자의 지수 차이를 결정하십시오.

  2. 그런 다음 누산기의 지수가 다음 숫자에 비해 너무 클 때까지 숫자를 더한 다음 누산기를 임시 대기열에 넣고 다음 숫자로 누산기를 시작합니다. 원래 목록을 모두 사용할 때까지 계속하십시오.

임시 큐 (정렬 된) 및 지수 차이가 더 클 수있는 프로세스를 반복합니다.

항상 지수를 계산해야한다면 상당히 느릴 것이라고 생각합니다.

프로그램을 빠르게 진행했고 결과는 1.99903이었습니다.


2

누적하는 과정에서 누적 기가 점점 더 커지기 때문에 누적하기 전에 숫자를 정렬하는 것보다 더 잘할 수 있다고 생각합니다. 비슷한 숫자가 많으면 정확도가 빨리 떨어지기 시작합니다. 대신 제안 할 내용은 다음과 같습니다.

while the list has multiple elements
    remove the two smallest elements from the list
    add them and put the result back in
the single element in the list is the result

물론이 알고리즘은 목록 대신 우선 순위 대기열을 사용하면 가장 효율적입니다. C ++ 코드 :

template <typename Queue>
void reduce(Queue& queue)
{
    typedef typename Queue::value_type vt;
    while (queue.size() > 1)
    {
        vt x = queue.top();
        queue.pop();
        vt y = queue.top();
        queue.pop();
        queue.push(x + y);
    }
}

운전사:

#include <iterator>
#include <queue>

template <typename Iterator>
typename std::iterator_traits<Iterator>::value_type
reduce(Iterator begin, Iterator end)
{
    typedef typename std::iterator_traits<Iterator>::value_type vt;
    std::priority_queue<vt> positive_queue;
    positive_queue.push(0);
    std::priority_queue<vt> negative_queue;
    negative_queue.push(0);
    for (; begin != end; ++begin)
    {
        vt x = *begin;
        if (x < 0)
        {
            negative_queue.push(x);
        }
        else
        {
            positive_queue.push(-x);
        }
    }
    reduce(positive_queue);
    reduce(negative_queue);
    return negative_queue.top() - positive_queue.top();
}

큐의 숫자 top가장 큰 숫자를 산출 하기 때문에 음수 이지만 가장 작은 . 대기열에 더 많은 템플릿 인수를 제공 할 수 있었지만이 방법은 더 간단 해 보입니다.


2

이것은 귀하의 질문에 대한 답은 아니지만, 한 번은 반올림 모드 " 반올림 "으로 한 번은 " 반올림 "으로 합계를 두 번 실행하는 것 입니다. 두 답변을 비교하면 결과가 / how / 부정확하다는 것을 알고 있으므로 더 똑똑한 합계 전략을 사용해야하는 경우. 안타깝게도 대부분의 언어는 부동 소수점 반올림 모드를 변경하기가 쉽지 않습니다. 사람들은 그것이 일상적인 계산에 실제로 유용하다는 사실을 모르기 때문입니다.

이와 같은 모든 수학을 수행하면서 가장 높은 값과 가장 낮은 값을 유지하는 간격 산술을 살펴보십시오 . 흥미로운 결과와 최적화로 이어집니다.


0

정확도를 향상시키는 가장 간단한 정렬 은 오름차순 절대 값을 기준으로 정렬하는 것입니다. 따라서 정밀도 손실을 유발할 수있는 더 큰 크기 값과 상호 작용하기 전에 가장 작은 크기 값이 누적되거나 취소 될 수 있습니다.

즉, 겹치지 않는 여러 부분 합계를 추적하면 더 잘할 수 있습니다. 다음은이 기술을 설명하고 정확성 증명을 제시하는 문서입니다. www-2.cs.cmu.edu/afs/cs/project/quake/public/papers/robust-arithmetic.ps

이 알고리즘과 정확한 부동 소수점 합산에 대한 다른 접근 방식은 http://code.activestate.com/recipes/393090/ 에서 간단한 Python으로 구현됩니다 . 이 중 적어도 두 개는 간단하게 C ++로 변환 할 수 있습니다.


0

IEEE 754 단 정밀도 또는 배정 밀도 또는 알려진 형식 숫자의 경우 또 다른 대안은 지수로 인덱싱 된 숫자 배열 (호출자 또는 C ++의 클래스에서 전달됨)을 사용하는 것입니다. 배열에 숫자를 추가 할 때 지수가 동일한 숫자 만 추가됩니다 (빈 슬롯이 발견되고 숫자가 저장 될 때까지). 합계가 호출되면 배열이 가장 작은 것부터 가장 큰 것까지 합산되어 잘림을 최소화합니다. 단 정밀도 예 :

/* clear array */
void clearsum(float asum[256])
{
size_t i;
    for(i = 0; i < 256; i++)
        asum[i] = 0.f;
}

/* add a number into array */
void addtosum(float f, float asum[256])
{
size_t i;
    while(1){
        /* i = exponent of f */
        i = ((size_t)((*(unsigned int *)&f)>>23))&0xff;
        if(i == 0xff){          /* max exponent, could be overflow */
            asum[i] += f;
            return;
        }
        if(asum[i] == 0.f){     /* if empty slot store f */
            asum[i] = f;
            return;
        }
        f += asum[i];           /* else add slot to f, clear slot */
        asum[i] = 0.f;          /* and continue until empty slot */
    }
}

/* return sum from array */
float returnsum(float asum[256])
{
float sum = 0.f;
size_t i;
    for(i = 0; i < 256; i++)
        sum += asum[i];
    return sum;
}

배정 밀도 예 :

/* clear array */
void clearsum(double asum[2048])
{
size_t i;
    for(i = 0; i < 2048; i++)
        asum[i] = 0.;
}

/* add a number into array */
void addtosum(double d, double asum[2048])
{
size_t i;
    while(1){
        /* i = exponent of d */
        i = ((size_t)((*(unsigned long long *)&d)>>52))&0x7ff;
        if(i == 0x7ff){         /* max exponent, could be overflow */
            asum[i] += d;
            return;
        }
        if(asum[i] == 0.){      /* if empty slot store d */
            asum[i] = d;
            return;
        }
        d += asum[i];           /* else add slot to d, clear slot */
        asum[i] = 0.;           /* and continue until empty slot */
    }
}

/* return sum from array */
double returnsum(double asum[2048])
{
double sum = 0.;
size_t i;
    for(i = 0; i < 2048; i++)
        sum += asum[i];
    return sum;
}

이것은 Malcolm 1971 의 방법 또는 Demmel과 Hida 의 지수를 사용하는 변형 ( "알고리즘 3") 다소 비슷합니다 . 당신과 같은 캐리 기반 루프를 수행하는 또 다른 알고리즘이 있지만 지금은 찾을 수 없습니다.
ZachB

@ZachB-개념은 연결된 목록에 대한 상향 병합 정렬 과 유사 합니다 . 이는 또한 작은 배열을 사용합니다. 여기서 array [i]는 2 ^ i 노드가있는 목록을 가리 킵니다. 이게 얼마나 거슬러 올라가는 지 모르겠어요. 제 경우에는 1970 년대의 자아 발견이었습니다.
rcgldr

-1

부동 소수점은 배정 밀도로 추가되어야합니다. 이는 다른 어떤 기술보다 더 많은 정밀도를 제공합니다. 좀 더 정확하고 훨씬 더 빠른 속도를 위해 4 개의 합계를 만들고 끝에 합산 할 수 있습니다.

배정 밀도 숫자를 추가하는 경우 합계에 long double을 사용합니다. 그러나 이것은 long double이 실제로 double보다 정밀도가 높은 구현에서만 긍정적 인 영향을 미칩니다 (일반적으로 컴파일러 설정에 따라 x86, PowerPC).


1
"그렇게하면 다른 어떤 기술보다 더 많은 정밀도를 얻을 수 있습니다."정확한 합계를 사용하는 방법을 설명하는 늦은 답변이 1 년 이상 지난 후 답변이 나온다는 것을 알고 있습니까?
파스칼 Cuoq

"long double"유형은 끔찍하며 사용해서는 안됩니다.
제프

-1

정렬과 관련하여 취소를 예상하면 숫자가 오름차순이 아닌 내림차순 으로 추가되어야한다고 생각 합니다. 예를 들면 :

((-1 + 1) + 1e-20)은 1e-20을 제공합니다.

그러나

((1e-20 + 1)-1) 0을 제공합니다

첫 번째 방정식에서는 두 개의 큰 숫자가 취소되는 반면 두 번째 방정식에서는 1에 추가 할 때 1e-20 항이 손실됩니다.

또한 쌍별 합계 는 많은 수를 합산하는 데 매우 적합합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.