부동 소수점 함정을 피하기 위해 프로그래밍 언어로 무엇을 할 수 있습니까?


28

부동 소수점 산술과 그 단점에 대한 오해는 프로그래밍에서 놀라움과 혼란의 주요 원인입니다 ( "정확하게 추가되지 않는 숫자"와 관련된 스택 오버플로에 대한 질문 수를 고려하십시오). 많은 프로그래머가 아직 그 의미를 이해하지 못하고 있다는 점을 고려하면 미묘한 버그 (특히 금융 소프트웨어)를 도입 할 가능성이 있습니다. 정확도 것과 중요하지 않은 경우 여전히 속도를 제공하면서 어떤 프로그래밍 언어는 개념에 익숙하지 않은 것들에 대한 함정을 피하기 위해 할 수있는 개념을 이해?


26
부동 소수점 처리의 함정을 피하기 위해 프로그래밍 언어가 할 수있는 것은 언어를 금지하는 것입니다. 여기에는 10 진수 부동 소수점도 포함되며, 이는 재무 응용 프로그램이 사전에 적용되는 것을 제외하고는 일반적으로 부정확합니다.
David Thornley

4
이것이 바로 "수치 해석 (Numerical Analysis)"입니다. 부동 소수점 함정이라고도하는 정밀 손실을 최소화하는 방법에 대해 알아보십시오.

부동 소수점 문제의 좋은 예 : stackoverflow.com/questions/10303762/0-0-0-0-0
Austin Henley

답변:


47

당신은 "특히 금융 소프트웨어를 위해"라고 말하는데, 이것은 나의 애완 동물 친구 중 하나를 불러옵니다 : 돈은 부유물이 아니며, int 입니다.

물론 플로트처럼 보입니다. 거기에 소수점이 있습니다. 그러나 그것은 당신이 문제를 혼란스럽게하는 단위에 익숙하기 때문입니다. 돈은 항상 정수 수량으로 제공됩니다. 미국에서는 센트입니다. (일부 상황에서는 그것이 mills 있다고 생각 하지만 지금은 무시하십시오.)

1.23 달러라고하면 실제로는 123 센트입니다. 항상, 항상, 항상 그런 식으로 수학을하면 괜찮을 것입니다. 자세한 내용은 다음을 참조하십시오.

질문에 직접 대답하면 프로그래밍 언어는 Money 유형을 합리적인 기본 형식으로 포함해야합니다.

최신 정보

네, "항상"이라고 세 번이 아니라 두 번만 말했을 것입니다. 돈은 항상 정수입니다. 그렇지 않다고 생각하는 사람들은 저에게 0.3 센트를 보내서 은행 계좌 명세서에 결과를 보여주십시오. 그러나 주석가가 지적했듯이 돈 같은 숫자에 대해 부동 소수점 수학을 수행 해야하는 경우는 거의 없습니다. 예를 들어, 특정 종류의 가격 또는이자 계산. 그럼에도 불구하고 그것들은 예외처럼 취급되어야합니다. 돈은 정수로 들어오고 나옵니다. 따라서 시스템이 그것에 가깝게 밀착 될수록 더 건강해집니다.


20
@JoelFan : 플랫폼 별 구현 개념을 착각하고 있습니다.
whatsisname

12
그렇게 간단하지 않습니다. 이자 계산은 무엇보다도 분수 센트를 생성하며 특정 방법에 따라 특정 시점에서 반올림해야합니다.
kevin cline 23.16에

24
Fictional -1, downvote에 대한 담당자가 없기 때문에 :) ... 이것은 지갑에 무엇이든지 맞을 수 있지만 10 분의 1 센트 또는 더 작은 분수를 처리 할 수있는 많은 회계 상황이 있습니다. Decimal이 문제를 다루는 유일한 제정신 시스템이며, "지금무시 하십시오 "라는 의견 은 모든 곳의 프로그래머에게 운명의 선구자입니다. : P
detly

9
@kevin cline : 계산에는 소수의 센트가 있지만 처리 방법에 대한 규칙이 있습니다. 재무 계산의 목표는 수학적 정확성이 아니라 계산기를 사용하는 은행가와 정확히 동일한 결과를 얻는 것입니다.
David Thornley

6
"정수"라는 단어를 "합리적"으로 바꾸면 모든 것이 완벽 해집니다. –
Emilio Garavaglia

15

Decimal 유형에 대한 지원을 제공하면 많은 경우에 도움이됩니다. 많은 언어는 10 진수 유형이지만 사용률이 낮습니다.

실수를 표현할 때 발생하는 근사를 이해하는 것이 중요합니다. 소수점과 부동 소수점 유형을 모두 사용 9 * (1/9) != 1하는 것이 올바른 문장입니다. 상수 일 때 옵티마이 저는 계산이 정확하도록 최적화 할 수 있습니다.

근사 연산자를 제공하면 도움이됩니다. 그러나 이러한 비교는 문제가있다. .9999 조 달러는 대략 1 조 달러와 같습니다. 은행 계좌에 차액을 입금 해 주시겠습니까?


2
0.9999...1 조 달러는 실제로 정확히 1 조 달러와 같습니다.
저의 정확한 의견 그냥

5
@JUST : 그렇습니다. 그러나 레지스터가있는 컴퓨터를 발견하지 못했습니다 0.99999.... 그들은 모두 어느 시점에서 자르고 불평등을 초래합니다. 0.9999엔지니어링을 위해 충분히 동일합니다. 재정적 목적으로는 그렇지 않습니다.
BillThor

2
그러나 어떤 시스템이 1 달러 대신 1 조 달러를 기본 단위로 사용 했습니까?
Brad

@ 브래드 계산기에서 (1 Trillion / 3) * 3을 계산해보십시오. 어떤 가치를 얻습니까?
BillThor

8

대학에 갔을 때 컴퓨터 과학 1 학년 (2 학년) 강의에서 무엇을해야하는지에 대해 들었습니다. (이 과정은 대부분의 과학 과정의 전제 조건이었습니다)

강사는 "부동 소수점 수는 근사치입니다. 정수형을 사용하십시오. 정확한 계산을 위해 FORTRAN 또는 다른 언어를 BCD 번호와 함께 사용하십시오." (그리고 그는 이진 부동 소수점으로 정확하게 표현할 수없는 0.2의 고전적인 예를 사용하여 근사치를 지적했습니다). 이것은 또한 실험실 운동에서 그 주에 나타났습니다.

같은 강의 : "부동 소수점에서 정확도를 높이려면 용어를 정렬하십시오. 큰 숫자가 아닌 작은 숫자를 더하십시오." 그것은 내 마음에 갇혔다.

몇 년 전에 저는 매우 정확하고 여전히 빠른 구형 형상이 필요했습니다. PC의 80 비트 더블은 그것을 자르지 않았으므로 나는 정류 연산을 수행하기 전에 용어를 정렬하는 프로그램에 일부 유형을 추가했습니다. 문제 해결됨.

기타의 음질에 대해 불평하기 전에 연주를 배우십시오.

나는 4 년 전에 JPL에서 일했던 동료를 가졌습니다. 그는 우리가 FORTRAN을 사용했다는 불신을 표현했습니다. "오프라인에서 계산 된 매우 정확한 수치 시뮬레이션이 필요했습니다." "우리는 모든 FORTRAN을 C ++로 교체했습니다."라고 자랑스럽게 말했습니다. 나는 그들이 왜 행성을 그리워했는지 궁금해했습니다.


2
올바른 작업에 적합한 도구 +1 실제로 FORTRAN을 사용하지는 않지만. 고맙게도 나는 직장에서 우리의 금융 시스템에서 일하지 않습니다.
James Khoury

"부동 소수점에서 정확도를 높이려면 용어를 정렬하십시오. 큰 숫자가 아닌 작은 숫자를 더하십시오." 이것에 대한 샘플?
mamcx

@mamcx 단 한 자리의 정밀도를 가진 10 진수 부동 소수점 숫자를 상상해보십시오. 모든 중간 결과가 반올림되면 계산 1.0 + 0.1 + ... + 0.1(10 회 반복)이 반환 1.0됩니다. 그것을 다른 방식으로 라운드를하는, 당신의 중간 결과를 얻을 0.2, 0.3..., 1.0그리고 마지막으로 2.0. 이것은 극단적 인 예이지만 사실적인 부동 소수점 수에서도 비슷한 문제가 발생합니다. 기본 아이디어는 크기가 비슷한 숫자를 추가하면 가장 작은 오류가 발생한다는 것입니다. 합계가 클수록 가장 작은 숫자부터 시작하여 더 큰 숫자에 더 적합합니다.
maaartinus

Fortran과 C ++의 부동 소수점은 거의 동일합니다. 둘 다 정확하고 오프라인 상태이며, Fortran에 기본 BCD 영역이 없다고 확신합니다.
Mark

8

경고 : 부동 소수점 유형 System.Double 은 직접 동등성 테스트의 정밀도가 부족합니다.

double x = CalculateX();
if (x == 0.1)
{
    // ............
}

언어 수준에서 할 수 있거나해야 할 일은 없다고 생각합니다.


1
플로트 또는 더블을 오랫동안 사용하지 않았으므로 궁금합니다. 실제로 존재하는 컴파일러 경고입니까, 아니면보고 싶은 경고입니까?
Karl Bielefeldt

1
@Karl-개인적으로 나는 그것을 보지 못하거나 필요로했지만 헌신적이지만 녹색 개발자에게 유용 할 수 있다고 생각합니다.
ChaosPandion

1
이진 부동 소수점 유형은 Decimal평등 테스트에 비해 질적으로 나쁘지 않습니다 . 의 차이 1.0m/7.0m*7.0m와는 1.0m덜 사이의 차이보다 크기의 많은 주문 될 수있다 1.0/7.0*7.0,하지만 제로 아니다.
supercat

1
@ 패트릭-당신이 무엇을 받고 있는지 잘 모르겠습니다. 어떤 경우에는 진실한 것과 모든 경우에 진실한 것에는 큰 차이가 있습니다.
ChaosPandion

1
@ChaosPandion이 포스트의 예제와 관련된 문제는 평등 비교가 아니라 부동 소수점 리터럴입니다. 정확한 값이 1.0 / 10 인 부동 소수점이 없습니다. 가수에 맞는 정수로 계산할 때 부동 소수점 수학으로 100 % 정확한 결과를 얻을 수 있습니다.
Patrick

7

기본적으로 언어는 정수가 아닌 숫자에 대해 임의 정밀도 합리성을 사용해야합니다.

최적화가 필요한 사람들은 항상 수레를 요청할 수 있습니다. 이를 C 및 기타 시스템 프로그래밍 언어에서는 기본값으로 사용했지만 오늘날 대부분의 언어에서는 그렇지 않습니다.


1
그러면 비이성적 인 숫자를 어떻게 처리합니까?
dsimcha

3
float과 같은 방식으로 근사화를 수행합니다.
Waquo

1
나는 이것이 많은 의미가 있다고 생각해야합니다. 정확한 숫자를 필요로하는 대부분의 사람들은 비이성적이 아닌 합리적인 것을 필요로합니다 (과학과 공학은 비이성적을 사용할 수 있지만 다시 대략적인 영역으로 돌아 가거나 꽤 전문화 된 순수한 수학을하고 있습니다)
jk.

1
임의 정밀도 합리성을 갖는 계산은 종종 하드웨어 지원을 사용한 계산보다 수십 배 느립니다 (아마도 수십 배 느리다) double. 계산이 백만 분의 일까지 정확해야하는 경우, 2 초 계산을 절대적으로 정확하게 사용하는 것보다 수십억 분의 일 이내에 마이크로 초 계산을하는 것이 좋습니다.
supercat

5
@ supercat : 당신이 제안하는 것은 조기 최적화의 포스터 아이 일뿐입니다. 현재 상황은 대다수의 프로그래머가 빠른 수학을 할 필요가 없으며 부동 소수점 (미스) 동작을 이해하기가 어려워서 빠른 수학이 필요한 비교적 적은 수의 프로그래머가 필요하지 않습니다. 하나의 추가 문자를 입력합니다. 이것은 70 년대에 의미가 있었지만 이제는 말도 안됩니다. 기본값은 안전해야합니다. 빨리 필요한 사람들은 그것을 요구해야합니다.
Waquo

4

부동 소수점 숫자와 관련된 두 가지 가장 큰 문제는 다음과 같습니다.

  • 일치하지 않는 단위가 계산에 적용됨 (이는 동일한 방식으로 정수 산술에도 영향을 미침)
  • FP 번호가 근사치 이며 반올림을 지능적으로 처리하는 방법 을 이해하지 못합니다 .

첫 번째 유형의 실패는 값 및 단위 정보를 포함하는 복합 유형을 제공해야만 해결할 수 있습니다. 예를 들어, 단위를 포함하는 a length또는 area값 (각 미터 또는 평방 미터 또는 피트 및 평방 피트). 그렇지 않으면 항상 한 유형의 측정 단위로 작업하고 인간과 답변을 공유 할 때만 다른 유형의 측정 단위로 변환하는 데 부지런해야합니다.

두 번째 유형의 실패는 개념적 실패입니다. 사람들이 절대 숫자 로 생각할 때 실패가 나타납니다 . 등식 연산, 누적 반올림 오류 등에 영향을줍니다. 예를 들어, 한 시스템에 대해 특정 오차 한계 내에서 두 측정 값이 동일한 것이 정확할 수 있습니다. 즉, .999 및 1.001은 +/- .1보다 작은 차이를 신경 쓰지 않을 때 1.0과 거의 같습니다. 그러나 모든 시스템이 관대하지는 않습니다.

필요한 언어 수준의 시설이 있다면 평등 정밀도 라고 부릅니다 . NUnit, JUnit 및 유사하게 구성된 테스트 프레임 워크에서 올바른 것으로 간주되는 정밀도를 제어 할 수 있습니다. 예를 들면 다음과 같습니다.

Assert.That(.999, Is.EqualTo(1.001).Within(10).Percent);
// -- or --
Assert.That(.999, Is.EqualTo(1.001).Within(.1));

예를 들어, C # 또는 Java가 정밀 연산자를 포함하도록 변경된 경우 다음과 같이 보일 수 있습니다.

if(.999 == 1.001 within .1) { /* do something */ }

그러나 이와 같은 기능을 제공하는 경우 +/-면이 같지 않으면 평등이 좋은 경우도 고려해야합니다. 예를 들어, + 1 / -10은 두 숫자 중 하나가 1보다 많거나 첫 번째 숫자보다 10보다 작 으면 두 숫자가 동등한 것으로 간주합니다. 이 경우를 처리하려면 range키워드도 추가해야합니다 .

if(.999 == 1.001 within range(.001, -.1)) { /* do something */ }

2
주문을 바꾸겠습니다. 개념적 문제는 광범위합니다. 비교하면 단위 변환 문제는 상대적으로 적습니다.
S.Lott

나는 정밀 연산자의 개념을 좋아하지만 더 자세히 언급 할 때 분명히 숙고해야합니다. 개인적으로 나는 그것을 그것의 완전한 구문 구조로 보는 경향이 있습니다.
ChaosPandion

라이브러리에서도 매우 쉽게 수행 할 수 있습니다.
Michael K

1
@ dan04 : "모든 계산은 1 % 이내로 정확합니다"등의 관점에서 더 많이 생각하고있었습니다. 측정 단위 처리 단위 인 타르 핏을 보았고 멀리 떨어져 있습니다.
TMN

1
약 25 년 전, 수량에 대한 최대 값과 최소값을 나타내는 한 쌍의 부동 소수점 숫자로 구성된 유형을 갖춘 숫자 패키지를 보았습니다. 숫자가 계산을 통과하면 최대 값과 최소값의 차이가 커집니다. 효과적으로, 이것은 계산 된 값에 얼마나 많은 실제 정밀도가 있는지를 알 수있는 수단을 제공했습니다.
supercat

3

프로그래밍 언어는 무엇을 할 수 있습니까? 프로그래머 / 인터프리터가 프로그래머를 대신하여 자신의 삶을 편하게하기 위해 수행하는 모든 작업은 일반적으로 성능, 선명도 및 가독성에 대해 작동하기 때문에 해당 질문에 대한 답변이 하나라도 있는지 모릅니다. 나는 C ++ 방식 (필요한 것에 대해서만 지불)과 Perl 방식 (최소한 놀람의 원칙)이 모두 유효하지만 응용 프로그램에 달려 있다고 생각합니다.

프로그래머는 여전히 언어로 작업하고 부동 소수점을 처리하는 방법을 이해해야합니다. 그렇지 않은 경우 가정을하고 언젠가는 허용 된 동작이 가정과 일치하지 않기 때문입니다.

프로그래머가 알아야 할 사항에 대한 나의 견해 :

  • 시스템과 언어에서 사용 가능한 부동 소수점 유형
  • 필요한 유형
  • 코드에서 필요한 유형의 의도를 표현하는 방법
  • 정확성을 유지하면서 선명도와 효율성의 균형을 유지하기 위해 자동 유형 승격을 올바르게 활용하는 방법

3

[부동 소수점] 함정을 피하기 위해 프로그래밍 언어는 무엇을 할 수 있습니까?

기본적으로 Decmials 지원과 같은 합리적인 기본값을 사용하십시오.

Groovy는 약간의 노력만으로도 부동 소수점 부정확도를 도입하는 코드를 작성할 수 있지만이 작업은 매우 훌륭하게 수행합니다.


3

언어 수준에서는 할 일이 없다는 데 동의합니다. 프로그래머는 컴퓨터가 개별적이고 제한적이며 컴퓨터에 표현 된 많은 수학적 개념은 근사치에 불과하다는 것을 이해해야합니다.

부동 소수점을 신경 쓰지 마십시오. 비트 패턴의 절반이 음수에 사용되고 2 ^ 64는 정수 산술의 일반적인 문제를 피하기 위해 실제로 매우 작다는 것을 이해해야합니다.


대부분의 언어는 현재와 유리수 또는 소수에 대한 충분한 지원 (? 이유도 수레에 대해 정의 ==입니다) 이진 부동 소수점 유형에 대한 너무 많은 지원을 제공 동의
JK.

@ jk : 계산 결과가 다른 계산 결과와 동일하게 보장되지 않더라도 동일한 값이 두 변수에 할당되는 경우 평등 비교는 여전히 유용합니다 (일반적으로 구현되는 평등 규칙은 아마도 x== y는 계산을 x수행해도 동일한 계산을 수행하는 것과 동일한 결과를 생성 한다는 것을 의미하지 않기 때문에 너무 느슨 y합니다.
supercat

@supercat 여전히 비교가 필요하지만 언어가 각 부동 소수점 비교에 대한 공차를 지정하도록 요구 했으므로 공차 = 0을 선택하여 평등으로 돌아갈 수는 있지만 적어도 강제로 작성해야합니다. 선택
jk.

3

언어가 할 수있는 일 중 하나는 NAN 값과 직접 비교하는 것 이외의 부동 소수점 유형에서 등식 비교를 제거하는 것입니다.

평등 테스트는 두 값과 델타를 사용하는 함수 호출 또는 유형이 다른 값과 델타를 취하는 EqualsTo 메서드를 가질 수 있도록하는 C #과 같은 언어에 대해서만 존재합니다.


3

나는 아무도 Lisp 가족의 합리적인 수법을 지적하지 않은 것이 이상하다고 생각합니다.

진심으로, sbcl을 열고 이렇게하십시오 : (+ 1 3)그리고 당신은 4 *( 3 2)를 얻습니다. 당신이 6을 얻었 으면 이제 시도 (/ 5 3)하고 5/3, 5/3을 얻습니다.

어떤 상황에서는 다소 도움이되어야합니까?


결과가 1/3로 표현되어야하는지 아니면 정확한 10 진수가 될 수 있는지 궁금하다면 궁금합니다.
mamcx

좋은 제안
Peter Porfy

3

내가보고 싶은 한 가지는 것으로 인식 될 double수있는 float반면, 확대 변환으로 간주되어야 floatdouble(*) 축소된다. 반 직관적 인 것처럼 보일 수 있지만 실제로 유형의 의미를 고려하십시오.

  • 0.1f는 "13,421,773.5 / 134,217,728, 플러스 또는 마이너스 1 / 268,435,456 정도"를 의미합니다.
  • 0.1은 실제로 3,602,879,701,896,397 / 36,028,797,018,963,968을 의미합니다.

double수량이 "10 분의 1"로 가장 잘 표현 된 값 을 가지고이를로 변환 float하면 결과는 "13,421,773.5 / 134,217,728, 플러스 또는 마이너스 1 / 268,435,456 정도"가되며 이는 값에 대한 정확한 설명입니다.

반대로, float"10 분의 1"을 가장 잘 나타내는 것을 가지고 그것을로 변환하면 double, 결과는 "13,421,773.5 / 134,217,728, 더하기 또는 빼기 1 / 72,057,594,037,927,936 정도"-암시 적 정확도 수준이됩니다 이는 5 천 5 백만 이상의 요인으로 잘못되었습니다.

비록 IEEE-744 표준이 모든 부동 소수점 숫자가 그 범위의 중심에서 정확한 수치 수량을 나타내는 것처럼 부동 소수점 수학을 수행하도록 요구 하지만 , 부동 소수점 값이 실제로 정확한 것을 나타내는 것을 암시해서는 안됩니다 수량. 오히려, 값이 그 범위의 중심에 있다고 가정하는 요구는 세 가지 사실에서 비롯됩니다. (1) 피연산자가 특정한 정확한 값을 갖는 것처럼 계산을 수행해야합니다. (2) 일관성 있고 문서화 된 가정은 일관성이 없거나 문서화되지 않은 가정보다 더 유용합니다. (3) 일관된 가정을 할 경우, 수량이 그 범위의 중심을 나타낸다고 가정하는 것보다 다른 일관된 가정이 더 나을 것 같지는 않습니다.

우연히도, 25 년 정도 전에 누군가 누군가가 한 쌍의 128 비트 부동 소수점으로 구성된 "범위 유형"을 사용하는 C 용 숫자 패키지를 생각해 냈습니다. 모든 계산은 각 결과에 대해 가능한 최소값과 최대 값을 계산하는 방식으로 수행됩니다. 큰 반복 계산을 수행하고 [12.53401391134 12.53902812673]의 값을 얻었을 경우 많은 자릿수의 반올림 오류가 발생하더라도 결과는 여전히 12.54로 합리적으로 표현 될 수 있습니다. t 실제로 12.9 또는 53.2). 주류 언어에서 이러한 유형에 대한 지원을 보지 못한 것에 놀랐습니다. 특히 여러 값에서 병렬로 작동 할 수있는 수학 단위에 적합하기 때문입니다.

(*) 실제로 단 정밀도 숫자로 작업 할 때 중간 정밀도 계산을 유지하기 위해 배정 밀도 값을 사용하는 것이 도움이되므로 이러한 모든 작업에 대해 유형 캐스트를 사용해야하는 것은 성 가실 수 있습니다. 언어는 "퍼지 더블"유형을 사용하여 도움을 줄 수 있는데,이 유형은 계산을 두 배로 수행 할 수 있으며 싱글과 자유롭게 캐스트 할 수 있습니다. 이것은 타입 double과 리턴의 매개 변수를 취하는 함수를 double표시하여 대신 "퍼지 더블"을 받아들이고 리턴하는 과부하를 자동으로 생성 할 수있는 경우에 특히 유용합니다 .


2

더 많은 프로그래밍 언어가 데이터베이스에서 페이지를 가져 와서 개발자가 숫자 데이터 유형의 길이와 정밀도를 지정할 수있게하면 부동 소수점 관련 오류의 가능성을 크게 줄일 수 있습니다. 언어가 개발자가 변수를 Float (2)로 선언하여 소수점 두 자리의 부동 소수점 숫자가 필요하다는 것을 나타내면 수학 연산을 훨씬 안전하게 수행 할 수 있습니다. 변수를 내부적으로 정수로 표시하고 값을 노출하기 전에 100으로 나누면 그렇게 빠른 정수 산술 경로를 사용하여 속도를 향상시킬 수 있습니다. Float (2)의 의미는 개발자가 데이터를 출력하기 전에 데이터를 반올림해야하는 지속적인 필요성을 피할 수있게합니다. Float (2)는 본질적으로 데이터를 소수점 두 자리로 반올림하기 때문입니다.

물론 개발자가 정밀도를 요구할 때 개발자가 최대 정밀도 부동 소수점 값을 요구할 수 있도록해야합니다. 그리고 개발자가 변수에 충분한 정밀도를 가지고 있지 않을 때 중간 반올림 연산으로 인해 동일한 수학 연산의 약간 다른 표현식이 잠재적으로 다른 결과를 생성하는 문제가 발생합니다. 그러나 적어도 데이터베이스 세계에서는 그렇게 큰 일이 아닌 것 같습니다. 대부분의 사람들은 중간 결과에서 많은 정밀도를 요구하는 일종의 과학적 계산을 수행하지 않습니다.


길이와 정밀도를 지정하면 거의 도움이되지 않습니다. 고정 소수점 기반 10을 갖는 것은 재무 처리에 유용하며, 이는 부동 소수점에서 사람들이 얻는 놀라움을 상당 부분 제거합니다.
David Thornley

@David-아마도 뭔가 빠졌지 만 고정 소수점 기본 10 데이터 유형이 여기에서 제안하는 것과 어떻게 다릅니 까? 필자의 예제에서 Float (2)는 고정 소수점 2 자리를 가지며 가장 가까운 100 분의 1로 자동 반올림되어 간단한 재무 계산에 사용됩니다. 더 복잡한 계산을 위해서는 개발자가 더 많은 수의 10 진수를 할당해야합니다.
Justin Cave

1
당신이 주장하는 것은 프로그래머가 지정한 정밀도를 가진 고정 소수점 기본 10 데이터 유형입니다. 프로그래머가 지정한 정밀도는 대부분 의미가 없으며 COBOL 프로그램에서 발생하는 일종의 오류로 이어질 것입니다. (예를 들어, 변수의 정밀도를 변경하면 값이 통과하는 변수 하나를 놓치기가 쉽습니다. 다른 변수의 경우 중간 결과 크기에 대해 생각하는 것보다 더 많은 생각이 필요합니다.)
David Thornley

4
Float(2)당신 같은이 호출 할 수 없습니다 제안 Float여기에 떠 아무것도 확실하지 "소수점"가 없기 때문에.
Paŭlo Ebermann

1
  • 언어는 십진수 형식을 지원합니다. 물론 이것은 실제로 문제를 해결하지는 못하지만, 예를 들어 정확하고 유한 한 표현은 없습니다.
  • 일부 DB 및 프레임 워크는 Money 유형을 지원하며 기본적으로 센트 수를 정수로 저장합니다.
  • 유리수 지원을위한 라이브러리가 있습니다. 그것은 of의 문제를 해결하지만 예를 들어 √2의 문제를 해결하지는 못한다.

위의 내용은 일부 경우에 적용 가능하지만 실제로 부동 소수점 값을 처리하는 일반적인 솔루션은 아닙니다. 실제 해결책은 문제를 이해하고 처리하는 방법을 배우는 것입니다. 부동 소수점 계산을 사용하는 경우 알고리즘이 수치 적으로 안정적 인지 항상 확인해야합니다 . 문제와 관련된 수학 / 컴퓨터 과학의 거대한 분야가 있습니다. 이를 Numerical Analysis 라고 합니다.


1

다른 답변에서 언급했듯이 금융 소프트웨어에서 부동 소수점 함정을 피하는 유일한 방법은 그것을 사용하지 않는 것입니다. 재무 수학 전용으로 잘 설계된 라이브러리를 제공하는 경우 실제로 실현 가능할 수 있습니다 .

부동 소수점 추정값을 가져 오도록 설계된 함수에는 명확하게 레이블을 지정하고 해당 작업에 적합한 매개 변수를 제공해야합니다. 예 :

Finance.importEstimate(float value, Finance roundingStep)

일반적으로 부동 소수점 함정을 피하는 유일한 방법은 교육입니다. 프로그래머는 모든 프로그래머가 부동 소수점 산술에 대해 알아야 할 내용 을 읽고 이해해야합니다 .

그래도 도움이 될만한 몇 가지 사항 :

  • "왜 부동 소수점에 대한 정확한 평등 테스트는 합법적인가?"
  • 대신 isNear()함수를 사용하십시오 .
  • 부동 소수점 누산기 객체 (일반 부동 소수점 변수에 단순히 모든 부동 소수점 값을 추가하는 것보다 부동 소수점 값 시퀀스를 추가)를 제공하고 권장합니다.

-1

대부분의 프로그래머들은 COBOL이 그 점을 잘 알고 있다는 사실에 놀라게 될 것입니다 ... 첫 번째 버전의 COBOL에는 부동 소수점이 없었으며 소수 만 있었으며 COBOL의 전통은 오늘날까지 계속해서 숫자를 선언 할 때 생각하는 것이 십진수입니다. .. 부동 소수점은 실제로 필요한 경우에만 사용됩니다. C가 어떤 이유로 든 원시 소수 유형이 없었기 때문에 내 의견으로는 모든 문제가 시작되었습니다.


1
C는 기본이 아니기 때문에 10 진수 유형이 없었으며, 하드웨어 10 진수 명령이있는 컴퓨터는 거의 없습니다. BASIC과 Pascal에 왜 금속이 없는지 묻지 않은 이유를 물을 수 있습니다. COBOL과 PL / I는 내가 알고있는 유일한 언어입니다.
David Thornley

3
@JoelFan : COBOL에서 ⅓을 어떻게 쓰나요? 10 진법으로도 문제가 해결되지 않습니다. 10 진법은 2 진법만큼 부정확합니다.
vartec

2
십진법은 "비즈니스 지향"언어에 유용한 달러와 센트를 정확하게 표현하는 문제를 해결합니다. 그러나 그렇지 않으면 십진수는 쓸모가 없습니다. 훨씬 느리지 만 같은 종류의 오류 (예 : 1 / 3 * 3 = 0.99999999)가 있습니다. 그렇기 때문에 회계 용으로 특별히 설계되지 않은 언어 에서는 이것이 기본값이 아닙니다.
dan04

1
그리고 C보다 10 년 이상 앞서간 FORTRAN은 표준 10 진수 지원도 없습니다.
dan04

1
@JoelFan : 분기 별 가치가 있고 월별 가치가 필요한 경우 무엇을 곱해야하는지 추측 해보십시오. 아니요, 0.33이 아니라 ⅓입니다.
vartec
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.