문제

I've stumbled onto a very strange bug. Read the comments in the code to see what the bug is exactly, but essentially a variable modulo 1 is returning 1 (but it doesn't equal 1!). I'm assuming there is a display problem where the float is extremely close to one but not exactly. However, it should be moduloing to zero. I can't test for this case easily because (last % 1) != 1.0 ! When I try plugging the same numbers into another python terminal, everything behaves correctly. What's going on?

def r(k,i,p):
    first = i*p
    last = first + p

    steps = int((i+1)*p) - int(i*p)
    if steps < 1:
        return p
    elif steps >= 1:
        if k == 0:
            return 1 - (first % 1)
        elif k == steps:
            if i == 189:
                print last, 1, type(last), last % 1, last - int(last)
                # Prints: 73.0 1 <type 'float'> 1.0 1.0
                print last % 1 == 1 # Returns False
            if last % 1 == 1.0:
                return 0
            return (last % 1)
        else:
            return 1
도움이 되었습니까?

해결책

Welcome to IEEE754, enjoy your stay.

다른 팁

Print doesn't show the full precision of the number as stored, you can use repr() to do that

>>> last=72.99999999999999
>>> print last, 1, type(last), last % 1, last - int(last)
73.0 1 <type 'float'> 1.0 1.0
>>> print last % 1 == 1
False
>>> print repr(last), 1, type(last), repr(last%1), repr(last - int(last))
72.999999999999986 1 <type 'float'> 0.99999999999998579 0.99999999999998579
>>> 

You should use math.fmod(x, y). Here's an excerpt from http://docs.python.org/library/math.html:

"Note that the Python expression x % y may not return the same result. The intent of the C standard is that fmod(x, y) be exactly (mathematically; to infinite precision) equal to x - n*y for some integer n such that the result has the same sign as x and magnitude less than abs(y). Python’s x % y returns a result with the sign of y instead, and may not be exactly computable for float arguments. For example, fmod(-1e-100, 1e100) is -1e-100, but the result of Python’s -1e-100 % 1e100 is 1e100-1e-100, which cannot be represented exactly as a float, and rounds to the surprising 1e100. For this reason, function fmod() is generally preferred when working with floats, while Python’s x % y is preferred when working with integers."

You could try the math.fmod function instead of last % 1, maybe it is better suited for you problem. Or you could reformulate you problem in integer space.

Anyway, it is not good practice to compare float values using equality == operator, due to imprecise results even from seemigly trivial operations like 0.1 + 0.2 == 0.3

If you need arbitrary precision, there are some projects out there that do just that. gmpy handles multi-precision integers, mpmath which looks quite good and bigfloat which wraps MPFR. What you have might be enough via gnibbler's answer, but, just in case.

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