Извлечение десятичных чисел из числа в Python - PullRequest
1 голос
/ 25 октября 2009

Я пишу функцию для извлечения десятичных чисел из числа. Проигнорируйте исключение и его синтаксис, я работаю над 2.5.2 (версия по умолчанию Leopard). Моя функция еще не обрабатывает 0. Моя проблема в том, что функция выдает случайные ошибки с определенными числами, и я не понимаю причину. Я опубликую сообщение об ошибке после кода.


Функция:

def extractDecimals(num):
    try:
        if(num > int(num)):
            decimals = num - int(num)
            while(decimals > int(decimals)):
                print 'decimal: ' + str(decimals)
                print 'int: ' + str(int(decimals))
                decimals *= 10
            decimals = int(decimals)
            return decimals
        else:
            raise DecimalError(num)
    except DecimalError, e:
        e.printErrorMessage()


Класс исключения:

class DecimalError(Exception):
    def __init__(self, value):
        self.value = value

    def printErrorMessage(self):
        print 'The number, ' + str(self.value) + ', is not a decimal.'


Вот вывод ошибки при вводе числа 1.988:
decimal: 0.988<br> int: 0<br> decimal: 9.88<br> int: 9<br> decimal: 98.8<br> int: 98<br> decimal: 988.0<br> int: 987<br> decimal: 9880.0<br> int: 9879<br> decimal: 98800.0<br> int: 98799<br> decimal: 988000.0<br> int: 987999<br> decimal: 9880000.0<br> int: 9879999<br> decimal: 98800000.0<br> int: 98799999<br> decimal: 988000000.0<br> int: 987999999<br> decimal: 9880000000.0<br> int: 9879999999<br> decimal: 98800000000.0<br> int: 98799999999<br> decimal: 988000000000.0<br> int: 987999999999<br> decimal: 9.88e+12<br> int: 9879999999999<br> decimal: 9.88e+13<br> int: 98799999999999<br> decimal: 9.88e+14<br> int: 987999999999999<br> 9879999999999998



Я не знаю, почему эта ошибка появляется. Надеюсь, вы, ребята, сможете мне помочь.

Ответы [ 5 ]

5 голосов
/ 25 октября 2009

Проблема в том, что (двоичные) числа с плавающей точкой не могут быть точно представлены в виде десятичных дробей. См. Почему десятичные числа не могут быть представлены точно в двоичном формате? для получения дополнительной информации.

1 голос
/ 25 октября 2009

Как уже было сказано, числа с плавающей запятой не совсем равны десятичным числам. Вы можете увидеть это с помощью оператора модуля следующим образом:

>>> 0.988 % 1
0.98799999999999999
>>> 9.88 % 1
0.88000000000000078
>>> 98.8 % 1
0.79999999999999716

Это дает остаток от деления на 1 или десятичное число.

1 голос
/ 25 октября 2009

Как уже отмечали другие, проблема, которую вы видите, связана с неточным представлением чисел с плавающей запятой

Попробуйте вашу программу с Python's Decimal

from decimal import Decimal
extractDecimals(Decimal("0.988"))
1 голос
/ 25 октября 2009

Как сказал Нед Батчелдер, не все десятичные числа точно представлены в виде чисел с плавающей точкой. Число с плавающей запятой представлено определенным количеством двоичных цифр, которые используются для максимально возможного приближения десятичной дроби. Вы никогда не можете предположить, что число с плавающей точкой точно равно десятичному.

In [49]: num
Out[49]: 1.988

In [50]: decimals=num - int(num)

In [51]: decimals
Out[51]: 0.98799999999999999

In [52]: print decimals   # Notice that print rounds the result, masking the inaccuracy.
0.988

См. http://en.wikipedia.org/wiki/Floating_point для получения дополнительной информации о двоичном представлении чисел с плавающей точкой.

Есть и другие способы достижения вашей цели. Вот один из способов использования строковых операций:

def extractDecimals(num):
    try:
        numstr=str(num)
        return int(numstr[numstr.find('.')+1:])
    except ValueError, e:
        print 'The number, %s is not a decimal.'%num
0 голосов
/ 25 октября 2009

Как уже говорили другие в своих ответах, арифметика с плавающей точкой не всегда приводит к тому, что вы ожидаете из-за ошибок округления. В этом случае, возможно, лучше преобразовать float в строку и обратно?

In [1]: num = 1.988

In [2]: num_str = str(num)

In [3]: decimal = num_str.split('.')[1]

In [4]: decimal = int(decimal)

In [5]: decimal
Out[5]: 988
...