파이썬에서 왜 1 // 0.01 == 99입니까?


31

나는 이것이 고전적인 부동 소수점 정밀도 질문이라고 생각하지만, 1//0.01파이썬 3.7.5 수율로 실행 하면서이 결과를 머리로 감싸려고합니다.99 .

나는 그것이 예상되는 결과라고 생각하지만, int(1/f)오히려 사용 하기보다 안전한시기를 결정할 수있는 방법 이 1//f있습니까?


4
예, 항상 더 안전합니다 int (1 / f). //가 FLOOR 부서이기 때문에 간단히 ROUND로 생각합니다.
Perdi Estaquel


2
중복되지 않습니다. 항상 round()및 전혀 또는를 사용 하지 //않으면 99.99 %의 예상대로 작동 할 수 있습니다 int(). 연결된 질문은 부동 소수점 비교가 잘림과 관련이 없으며 쉽게 해결할 수 없다는 것입니다.
MAXY

답변:


23

이것이 1//0.01실수로 0.01나누면 정확히 100입니다. 부동 소수점 근사값 은 1/100보다 약간 크므로 몫이 100보다 약간 작다는 의미입니다.이 값은 99입니다. ~ 99


3
이것은 "안전한시기를 결정하는 방법이 있습니까"부분을 다루지 않습니다.
Scott Hunter

10
"안전"은 잘 정의되어 있지 않습니다.
chepner

1
그것을 완전히 무시하기에 충분합니다. OP가 부동 소수점 문제를 알고있는 경우
Scott Hunter

3
@chepner 만약 "safer"가 잘 정의되지 않았다면 아마도 다음과 같이 설명을 요청하는 것이 좋습니다 : /

2
"safer"는 "저렴한 포켓 계산기보다 나쁘지 않은 오류"를 의미한다는 것이 분명합니다.
maxy

9

이 결과의 이유는 사용자가 말한 것과 같으며 부동 소수점 수학이 손상 되었습니까?에 설명되어 있습니다 . 그리고 다른 많은 유사한 Q & A.

분자와 분모의 소수점 이하 자릿수를 알면 더 신뢰할 수있는 방법은 먼저 그 숫자를 곱하여 정수로 처리 한 다음 정수 나누기를 수행하는 것입니다.

따라서 귀하의 경우 1//0.01먼저 1*100//(0.01*100)100 으로 변환해야합니다 .

더 극단적 인 경우에도 "예기치 않은"결과를 얻을 수 있습니다. round정수 나누기를 수행하기 전에 분자와 분모에 대한 호출 을 추가해야 할 수도 있습니다 .

1 * 100000000000 // round(0.00000000001 * 100000000000)

그러나,이 고정 소수점 (돈, 센트) 작업에 대한 경우, 다음과 같은 센트 작업을 고려 단위 그래서 모든 연산이 정수 연산으로 수행 할 수 있음을, 그리고 에만 수행 할 때 주요 통화 단위 (달러)에서 /로 변환 I / O

또는 다음과 같이 소수 자릿수에 라이브러리를 사용하십시오 .

... 올바른 반올림 십진 부동 소수점 산술을 지원합니다.

from decimal import Decimal
cent = Decimal(1) / Decimal(100) # Contrary to floating point, this is exactly 0.01
print (Decimal(1) // cent) # 100

3
"분명히 100입니다." 반드시 그런 것은 아닙니다. 0.01이 정확하지 않으면 .01 * 100도 정확하지 않습니다. 수동으로 "조정"해야합니다.
glglgl

8

당신이 고려해야 할 것은 즉 //는 IS floor연산자와 당신이 99에서 100으로 하락하는 동일한 확률을 가지고있는 것처럼 같은 당신이 먼저 (*) (작업이되기 때문에 생각해야 100 ± epsilon으로epsilon>0 제공되는 정확히 100.00을 얻을 수있는 기회 ..0은 매우 낮습니다.)

실제로 마이너스 부호로 똑같이 볼 수 있습니다.

>>> 1//.01
99.0
>>> -1//.01
-100.0

그리고 당신은 (놀랍지 않은) 사람이어야합니다.

반면에 int(-1/.01)먼저 나누기를 수행 한 다음 바닥이 아니라 0쪽으로int()립니다 . 그런 경우에

>>> 1/.01
100.0
>>> -1/.01
-100.0

그 후,

>>> int(1/.01)
100
>>> int(-1/.01)
-100

반올림하면이 연산자에 대한 예상 결과가 다시 나타납니다.

(*) 나는 확률이 같다고 말하는 것이 아니라, 당신이 얻는 것을 추정하는 부동 산술로 그러한 계산을 수행 할 때 선험적으로 말하는 것입니다.


7

부동 소수점 숫자는 대부분의 10 진수를 정확하게 표현할 수 없으므로 부동 소수점 리터럴을 입력하면 실제로 해당 리터럴의 근사값을 얻습니다. 근사값은 입력 한 숫자보다 크거나 작을 수 있습니다.

부동 소수점 숫자를 10 진수 또는 분수로 캐스트하여 정확한 값을 볼 수 있습니다.

>>> from decimal import Decimal
>>> Decimal(0.01)
Decimal('0.01000000000000000020816681711721685132943093776702880859375')
>>> from fractions import Fractio
>>> Fraction(0.01)
Fraction(5764607523034235, 576460752303423488) 

분수 유형을 사용하여 부정확 한 리터럴로 인한 오류를 찾을 수 있습니다.

>>> float((Fraction(1)/Fraction(0.01)) - 100)
-2.0816681711721685e-15

우리는 또한 numpy에서 nextafter를 사용하여 100 정도의 세부 배정도 부동 소수점 숫자가 얼마나되는지 알아낼 수 있습니다.

>>> from numpy import nextafter
>>> nextafter(100,0)-100
-1.4210854715202004e-14

이것으로부터 우리는 가장 가까운 부동 소수점 숫자 1/0.01000000000000000020816681711721685132943093776702880859375가 실제로 100이라는 것을 추측 할 수 있습니다 .

차이 1//0.01int(1/0.01)반올림된다. 1 // 0.01은 정확한 결과를 한 번에 다음 정수로 내림합니다. 결과는 99입니다.

반면에 int (1 / 0.01)은 두 단계로 반올림됩니다. 먼저 결과를 가장 가까운 배정 밀도 부동 소수점 숫자 (정확히 100 임)로 반올림 한 다음 부동 소수점 숫자를 다음 정수로 반올림합니다. 다시 정확히 100).


반올림을 호출하는 것은 잘못된 것입니다. 그것은 중 하나를 호출 할 필요가 절단 또는 0에 가까워 반올림 : int(0.9) == 0int(-0.9) == 0
MAXY

그것은이다 바이너리 여기에 대해 얘기하는 부동 소수점 형식. (소수점 부동 소수점 유형도 있습니다.)
Stephen C

3

다음을 실행하면

from decimal import *

num = Decimal(1) / Decimal(0.01)
print(num)

출력은 다음과 같습니다.

99.99999999999999791833182883

이 아래로 반올림 있도록 내부적으로, 표현 어떻게입니다 //줄 것이다99


2
이 경우 오류를 표시 할만큼 정확하지만 "소수"산술도 정확하지 않습니다.
plugwash

으로 Decimal(0.01)당신이 너무 늦게, 오류가 이미 호출하기 전에 성행하고 Decimal. 이것이 어떻게 질문에 대한 답인지 잘 모르겠습니다 ... 먼저 Decimal(1) / Decimal(100)내 대답에 표시된 것처럼 정확한 0.01을 계산해야합니다 .
trincot

@trincot 내 대답은 "왜 1 // 0.01 == 99"라는 제목의 질문에 대한 것입니다. 저는 부동 숫자가 내부적으로 처리되는 방법을 OP에 표시하려고했습니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.