2014-03-14 10 views
3

저는 1.1의 float 값을 줄 수있는 JSON 데이터 파일을 읽었습니다. 이 값을 Decimal으로 만들면 수레의 이진 표현의 부정확성 때문에 미친 긴 숫자가 나옵니다.Decimal (str (my_float))은 Decimal (my_float)보다 좋을 것 같습니다. 어떻게 된 것입니까?

저는 이진 표현을 이해합니다. 기수 10 부동 소수점에서 쓸 수있는 숫자를 기수 2로 표현할 수는 없다는 생각에 괜찮습니다.

하지만 내가 먼저 float 문자열을 ify 값으로 사용하는 Decimal로 만들면 작은 바이너리 부정확성 델타가없는 Decimal을 얻을 수 있습니다. 여기

는 I의 의미는 다음과 같습니다

Python 2.7.6 (default, Jan 16 2014, 10:55:32) 
>>> from decimal import Decimal 
>>> f = 1.1 
>>> d = Decimal(f) 
>>> f 
1.1 
>>> d 
Decimal('1.100000000000000088817841970012523233890533447265625') 
>>> d = Decimal(str(f)) 
>>> d 
Decimal('1.1') 

문자열-ifying 입력으로 (또는에서 읽을 진수로하기 전에 플로트 것은 가까운 원래베이스 열 수에 나에게 결과를 제공하는 것 JSON 파일).

내 질문은 다음과 같습니다. float을 문자열로 만들 때 긴 자릿수가 보이지 않는 이유는 무엇입니까? Python이 JSON에서 파싱 된 원래 문자열을 자동으로 추적하고 있습니까? 왜 Decimal 생성자는 그 트릭을 사용하지 않습니까?

+1

"왜 Decimal 생성자는이 트릭을 사용하지 않습니까?" 분명히'decimal' 모듈의 설계자는 엄격한 정확도가 더 나은 결과라고 생각했습니다. 모듈의 전체적인 점은 바이너리로 표현할 수없는 십진수로 작업하기 때문에 왜 그렇게 생각할 지 모르겠다. 당신이 보는 숫자는 그때마다 정확합니다. 역이 사실이 아니더라도 이진수는 항상 십진수로 나타낼 수 있습니다. –

답변

4

플로트의 정확한 값은 1.100000000000000088817841970012523233890533447265625입니다. 파이썬은 어떻게 든 원래 문자열을 추적하지 않습니다. 파이썬이 str으로 문자열을 변형하면 12 자리로 자릅니다. 심지어 repr

>>> x = 1.0/9 
>>> print decimal.Decimal(x) # prints exact value 
0.111111111111111104943205418749130330979824066162109375 
>>> print x # truncated 
0.111111111111 

는, 파이썬은 float를 사용한 구문 분석시에 원래의 부동 소수점 반올림됩니다 가장 짧은 문자열을 사용합니다. 당신이 JSON을 구문 분석하고 대신 부동의 진수 인스턴스를 얻고 싶다면

>>> print repr(x) 
0.1111111111111111 

, 당신은 load(s) 함수에 parse_float 인수를 전달할 수 있습니다

>>> json.loads('{"foo": 1.23456789}', parse_float=decimal.Decimal) 
{u'foo': Decimal('1.23456789')} 

위의 호출은 decimal.Decimal 원인이 번호를 구문 분석 호출 할 JSON 문자열에서 중간 float 또는 str 호출로 발생하는 반올림을 건너 뜁니다. JSON에 지정된 번호를 정확히 얻을 수 있습니다.

API는 부동 소수점처럼 보이는 것들, 즉 Infinity, -Infinity 또는 NaN처럼 보이는 것들을 구문 분석하는 데 사용되는 함수를 구분합니다. 3 가지 카테고리를 모두 같은 방식으로 처리하기를 원한다면 약간 불편할 수 있습니다.

>>> json.loads('{"foo": 1.23456789}', 
...   parse_float=decimal.Decimal, 
...   parse_int=decimal.Decimal, 
...   parse_constant=decimal.Decimal) 
{u'foo': Decimal('1.23456789')} 
+0

'parse_float' 레퍼런스를 위해서 또 하나의 +1을 주길 바랄뿐입니다. –

+0

(OP 여기 ..) 예, parse_float와 같이 처리해야합니다. 그것은 과학적인 데이터이기 때문에 숫자를 다루는 데 아주 엄격해야합니다. 내 도구는 데이터 구조 또는 JSON 문자열을 받아 들일 수 있으므로 수레도 처리해야합니다.float 값을 얻는다면'Decimal (repr (the_float)) '을 사용하여 변환 할 것이라고 생각합니다. 이것은 내가 얻을 수있는 원래의 인간 의도와 가깝게 보인다. –