문제

나는 더블을 사용할지 소수를 사용할지 결정하기 위해 끊임없이 싸우는 금융 애플리케이션을 작성합니다.

내 모든 수학은 소수점 이하 5자리 이하의 숫자에 대해 작동하며 최대 100,000보다 크지 않습니다.어쨌든 반올림 오류 없이 이 모든 것이 복식으로 표현될 수 있다는 느낌이 들지만 확신할 수는 없습니다.

확실한 속도 이점을 위해 십진수에서 두 배로 전환하겠습니다. 단, 하루가 끝날 때에도 여전히 ToString 메서드를 사용하여 가격을 거래소로 전송하고 항상 I 숫자가 출력되는지 확인해야 합니다. 예상하다.(89.99000000001 대신 89.99)

질문:

  1. 순진한 테스트에서 제안한 것만큼 속도 이점이 정말 큰가요?(~100회)
  2. ToString의 출력이 내가 원하는 대로 되도록 보장하는 방법이 있습니까?내 번호가 항상 표현 가능하다는 사실이 이를 보장합니까?

업데이트:내 앱이 실행되려면 약 100억 개의 가격 업데이트를 처리해야 하며, 명백한 보호상의 이유로 지금은 소수점으로 구현했지만, 켜는 데만 ~3시간이 걸리고, 두 배로 늘리면 켜는 시간이 극적으로 단축됩니다.복식으로 안전하게 할 수 있는 방법이 있나요?

도움이 되었습니까?

해결책

  1. 플로팅 포인트 산술은 하드웨어에서 직접 지원되기 때문에 거의 항상 훨씬 빠릅니다. 지금까지 널리 사용되는 하드웨어는 소수점 산술을 지원하지 않습니다 (이것은 변경되지만 주석을 참조하십시오).
  2. 재무 신청이 있어야합니다 언제나 Fecimal Numbers, Financial Applications에서 Float Point를 사용하여 발생하는 공포 이야기의 수는 끝이 없으므로 Google 검색에서 그러한 많은 예를 찾을 수 있어야합니다.
  3. 소수의 산술은 부동 소수점 산술보다 상당히 느리게 느릴 수 있지만, 소수점 데이터를 상당한 시간 처리하지 않는 한 프로그램에 미치는 영향은 무시할 수 있습니다. 항상 그렇듯이 차이에 대해 걱정하기 전에 적절한 프로파일 링을 수행하십시오.

다른 팁

여기에는 두 가지 분리 가능한 문제가 있습니다. 하나는 더블이 필요한 모든 비트를 유지하기에 충분한 정밀도를 가지고 있는지, 다른 하나는 정확히 숫자를 나타낼 수있는 곳입니다.

정확한 표현에 관해서는, 당신은 1/10과 같은 정확한 소수점 분획에는 정확한 이진에 대응하지 않기 때문에 조심해야합니다. 그러나 5 자리 숫자의 정밀도 만 필요하다는 것을 알고 있다면 사용할 수 있습니다. 스케일링 숫자에서 작동하는 산술에 10^5를 곱합니다. 예를 들어 23.7205를 정확하게 대표하려면 2372050으로 표현합니다.

충분한 정밀도가 있는지 봅시다 : 이중 정밀도는 53 비트의 정밀도를 제공합니다. 이것은 정밀도의 15 숫자와 동일합니다. 따라서 소수점 이후 5 자리와 10 자리 숫자가 10 자리 숫자가 허용되며, 이는 응용 프로그램에 충분한 것으로 보입니다.

이 c 코드를 .h 파일에 넣을 것입니다.

typedef double scaled_int;

#define SCALE_FACTOR 1.0e5  /* number of digits needed after decimal point */

static inline scaled_int adds(scaled_int x, scaled_int y) { return x + y; }
static inline scaled_int muls(scaled_int x, scaled_int y) { return x * y / SCALE_FACTOR; }

static inline scaled_int scaled_of_int(int x) { return (scaled_int) x * SCALE_FACTOR; }
static inline int intpart_of_scaled(scaled_int x) { return floor(x / SCALE_FACTOR); }
static inline int fraction_of_scaled(scaled_int x) { return x - SCALE_FACTOR * intpart_of_scaled(x); }

void fprint_scaled(FILE *out, scaled_int x) {
  fprintf(out, "%d.%05d", intpart_of_scaled(x), fraction_of_scaled(x));
}

아마도 몇 가지 거친 지점이 있지만 시작하기에 충분해야합니다.

추가에 대한 오버 헤드, 곱하기 또는 분할 비용이 두 배가됩니다.

C99에 액세스 할 수있는 경우 int64_t 64 비트 정수 유형. 더 빠른 하드웨어 플랫폼에 따라 다릅니다.

재무 계산에 항상 10 진수를 사용하거나 1 센트 반올림 오류를 영원히 쫓아갑니다.

  1. 예;소프트웨어 연산은 실제로 하드웨어보다 100배 느립니다.아니면 적어도 훨씬 더 느리고, 100배 정도의 크기를 주거나 취하는 것이 거의 맞습니다.모든 80386에 80387 부동 소수점 보조 프로세서가 있다고 가정할 수 없었던 옛날에는 이진 부동 소수점에 대한 소프트웨어 시뮬레이션도 있었지만 속도가 느렸습니다.
  2. 아니요;순수한 이진 부동 소수점이 모든 십진수를 정확하게 나타낼 수 있다고 생각한다면 당신은 환상의 나라에 살고 있는 것입니다.이진수는 이분의 일, 사분의 일, 팔분의 일 등을 결합할 수 있지만, 0.01의 정확한 소수는 1/5의 두 인수와 1/4의 한 인수가 필요하기 때문에 (1/100 = (1/4)*(1/5)*(1 /5)) 그리고 5분의 1은 이진수로 정확하게 표현되지 않기 때문에 모든 십진수 값을 이진수 값으로 정확하게 표현할 수는 없습니다(0.01은 정확하게 표현할 수 없는 반례이지만 다음과 같은 거대한 종류의 십진수를 대표하기 때문입니다). 정확하게 표현할 수 없습니다.)

따라서 ToString()을 호출하기 전에 반올림을 처리할 수 있는지 또는 결과가 문자열로 변환될 때 반올림을 처리하는 다른 메커니즘을 찾아야 하는지 여부를 결정해야 합니다.또는 소수점 산술은 정확성을 유지하므로 계속해서 사용할 수 있으며 하드웨어에서 새로운 IEEE 754 십진수 산술을 지원하는 시스템이 출시되면 속도가 더 빨라질 것입니다.

필수 상호 참조: 모든 컴퓨터 과학자가 부동 소수점 산술에 대해 알아야 할 사항.이는 가능한 많은 URL 중 하나입니다.

여기에서 소수 연산 및 새로운 IEEE 754:2008 표준에 대한 정보를 확인하세요. 스펠레오트로브 대지.

길고 10의 전력을 곱하십시오. 완료된 후에는 동일한 힘 10으로 나눕니다.

소수성은 항상 재무 계산에 사용해야합니다. 숫자의 크기는 중요하지 않습니다.

내가 설명하는 가장 쉬운 방법은 일부 C# 코드를 통한 것입니다.

double one = 3.05;
double two = 0.05;

System.Console.WriteLine((one + two) == 3.1);

해당 코드가 인쇄됩니다 거짓 3.1은 3.1과 같지만 ...

똑같은 ... 그러나 소수점 사용 :

decimal one = 3.05m;
decimal two = 0.05m;

System.Console.WriteLine((one + two) == 3.1m);

이제 인쇄됩니다 진실!

이런 종류의 문제를 피하려면 소수를 고수하는 것이 좋습니다.

나는 당신을 내 대답을 추천합니다 이 질문.

길이를 사용하고 추적 해야하는 가장 작은 양을 저장하고 그에 따라 값을 표시하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top