문제
나는 더블을 사용할지 소수를 사용할지 결정하기 위해 끊임없이 싸우는 금융 애플리케이션을 작성합니다.
내 모든 수학은 소수점 이하 5자리 이하의 숫자에 대해 작동하며 최대 100,000보다 크지 않습니다.어쨌든 반올림 오류 없이 이 모든 것이 복식으로 표현될 수 있다는 느낌이 들지만 확신할 수는 없습니다.
확실한 속도 이점을 위해 십진수에서 두 배로 전환하겠습니다. 단, 하루가 끝날 때에도 여전히 ToString 메서드를 사용하여 가격을 거래소로 전송하고 항상 I 숫자가 출력되는지 확인해야 합니다. 예상하다.(89.99000000001 대신 89.99)
질문:
- 순진한 테스트에서 제안한 것만큼 속도 이점이 정말 큰가요?(~100회)
- ToString의 출력이 내가 원하는 대로 되도록 보장하는 방법이 있습니까?내 번호가 항상 표현 가능하다는 사실이 이를 보장합니까?
업데이트:내 앱이 실행되려면 약 100억 개의 가격 업데이트를 처리해야 하며, 명백한 보호상의 이유로 지금은 소수점으로 구현했지만, 켜는 데만 ~3시간이 걸리고, 두 배로 늘리면 켜는 시간이 극적으로 단축됩니다.복식으로 안전하게 할 수 있는 방법이 있나요?
해결책
- 플로팅 포인트 산술은 하드웨어에서 직접 지원되기 때문에 거의 항상 훨씬 빠릅니다. 지금까지 널리 사용되는 하드웨어는 소수점 산술을 지원하지 않습니다 (이것은 변경되지만 주석을 참조하십시오).
- 재무 신청이 있어야합니다 언제나 Fecimal Numbers, Financial Applications에서 Float Point를 사용하여 발생하는 공포 이야기의 수는 끝이 없으므로 Google 검색에서 그러한 많은 예를 찾을 수 있어야합니다.
- 소수의 산술은 부동 소수점 산술보다 상당히 느리게 느릴 수 있지만, 소수점 데이터를 상당한 시간 처리하지 않는 한 프로그램에 미치는 영향은 무시할 수 있습니다. 항상 그렇듯이 차이에 대해 걱정하기 전에 적절한 프로파일 링을 수행하십시오.
다른 팁
여기에는 두 가지 분리 가능한 문제가 있습니다. 하나는 더블이 필요한 모든 비트를 유지하기에 충분한 정밀도를 가지고 있는지, 다른 하나는 정확히 숫자를 나타낼 수있는 곳입니다.
정확한 표현에 관해서는, 당신은 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 센트 반올림 오류를 영원히 쫓아갑니다.
- 예;소프트웨어 연산은 실제로 하드웨어보다 100배 느립니다.아니면 적어도 훨씬 더 느리고, 100배 정도의 크기를 주거나 취하는 것이 거의 맞습니다.모든 80386에 80387 부동 소수점 보조 프로세서가 있다고 가정할 수 없었던 옛날에는 이진 부동 소수점에 대한 소프트웨어 시뮬레이션도 있었지만 속도가 느렸습니다.
- 아니요;순수한 이진 부동 소수점이 모든 십진수를 정확하게 나타낼 수 있다고 생각한다면 당신은 환상의 나라에 살고 있는 것입니다.이진수는 이분의 일, 사분의 일, 팔분의 일 등을 결합할 수 있지만, 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);
이제 인쇄됩니다 진실!
이런 종류의 문제를 피하려면 소수를 고수하는 것이 좋습니다.
나는 당신을 내 대답을 추천합니다 이 질문.
길이를 사용하고 추적 해야하는 가장 작은 양을 저장하고 그에 따라 값을 표시하십시오.