Как использовать целочисленную арифметику для преобразования дробей в числа с плавающей запятой в python?

Что мне нужно сделать, так это использовать целочисленную арифметику для преобразования дробей в числа с плавающей запятой. Необходимое количество знаков после запятой указывается в виде переменной DECIMALS. Каждая дробь содержится в кортеже целых чисел, например (1, 3). Первый элемент — числитель, второй — знаменатель. Кортежи содержатся в списке под названием fractions.

Это мой код до сих пор:

fractions = [(1,7), (2,3), (22,7), (7001,7), (9,3), (611951,611953), (1,11), (1,7689585)]

DECIMALS = 10**40 # 40 decimal places

for fraction in fractions:  
     x =  DECIMALS*fraction[0]/fraction[1]
     print x

Когда я запускаю код, это то, что я получаю:

1428571428571428571428571428571428571428
6666666666666666666666666666666666666666
31428571428571428571428571428571428571428   
10001428571428571428571428571428571428571428
30000000000000000000000000000000000000000
9999967317751526669531810449495304377950
909090909090909090909090909090909090909
1300460297922449651053990559958697

Проблема в том, что мне нужно отформатировать это в правильный десятичный формат. То, что я пробовал, было

print "0.%.40d" % (x)

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


person 321    schedule 11.06.2012    source источник
comment
Очень сложно понять, в чем здесь вопрос. Может ли docs.python.org/library/decimal.html сделать то, что вы хотите?   -  person msw    schedule 11.06.2012
comment
Что именно ты пытаешься сделать?   -  person Joel Cornett    schedule 11.06.2012
comment
Хорошо, я отредактировал его, и, надеюсь, вы, ребята, поймете вопрос на этот раз.   -  person 321    schedule 11.06.2012


Ответы (3)


Если это строгое форматирование, как следует из вашего вопроса, вы, конечно, можете сделать это только с целыми числами и строками:

def intF(n, d, l=40):
    s=str(n*10**l / d)
    if len(s) < l:
        return '0.{:0>{width}}'.format(s,width=l)
    if len(s) > l:
        return s[0:len(s)-l]+'.'+s[len(s)-l:] 

    return '0.'+s


for f in [(1,7), (2,3), (22,7), (7001,7), (9,3), 
          (611951,611953), (1,11),(1,7689585)]:
    print intF(*f)
    print float(f[0]) / f[1]
    print 

Выход:

0.1428571428571428571428571428571428571428
0.142857142857

0.6666666666666666666666666666666666666666
0.666666666667

3.1428571428571428571428571428571428571428
3.14285714286

1000.1428571428571428571428571428571428571428
1000.14285714

3.0000000000000000000000000000000000000000
3.0

0.9999967317751526669531810449495304377950
0.999996731775

0.0909090909090909090909090909090909090909
0.0909090909091

0.0000001300460297922449651053990559958697
1.30046029792e-07

Последняя цифра не будет правильно округлена, и она не будет правильно обрабатывать крайние случаи («inf», «NaN», деление на ноль и т. д.).

Работает в крайнем случае, я полагаю.

Почему бы не использовать входящие в комплект батарейки, такие как Decimal или Fraction?

person Community    schedule 12.06.2012
comment
Я не уверен, что понимаю, что происходит ни в функции, ни в этой части: print intF(*f). не могли бы вы объяснить плз? а что за аккумулятор? Я на самом деле новичок в python и программировании, поэтому я не знаю, что это такое. - person 321; 13.06.2012
comment
на самом деле вам больше не нужно объяснять печать intF(*f). я понимаю эту часть, но я все равно был бы признателен, если бы вы могли объяснить функцию и, более конкретно, что происходит в циклах i. спасибо - person 321; 13.06.2012
comment
@ 321 Я думаю, что «батареи», о которых он говорил, — это множество модулей Python (таких как Decimal и Fraction), которые выполняют специализированные задачи. Говорят, что батарейки включены, поскольку в Python так много высококачественных модулей для выполнения специализированных задач. В рамках изучения языка изучите эти модули. Если вы не действительно хороши, вы должны задаться вопросом, почему вы делаете что-то не так, как в одном из модулей дистрибутива. Функция не имеет цикла. Он форматирует только строку, полученную в результате предложенной вами математики. Единственный цикл здесь - это цикл по вашему списку по кортежу - person dawg; 14.06.2012

Вы имеете в виду что-то вроде этого:

from fractions import Fraction
import decimal

decimal.getcontext().prec = 50

fractions = [(1,7), (2,3), (22,7), (7001,7), (9,3), (611951,611953), (1,11),(1,7689585)]

su=Fraction(0)
for i, t in enumerate(fractions,1):
    f=Fraction(*t)
    su+=Fraction(*t)
    d=decimal.Decimal(f.numerator) / decimal.Decimal(f.denominator)
    print '{} becomes {}'.format(t,f)
    print '\tfloat of that is: {}'.format(float(f))
    print '\tDecimal: {}'.format(d)
    print '\t{} elements cum sum of the list: {}\n'.format(i,su)

Отпечатки:

(1, 7) becomes 1/7
    float of that is: 0.142857142857
    Decimal: 0.14285714285714285714285714285714285714285714285714
    1 elements cum sum of the list: 1/7

(2, 3) becomes 2/3
    float of that is: 0.666666666667
    Decimal: 0.66666666666666666666666666666666666666666666666667
    2 elements cum sum of the list: 17/21

(22, 7) becomes 22/7
    float of that is: 3.14285714286
    Decimal: 3.1428571428571428571428571428571428571428571428571
    3 elements cum sum of the list: 83/21

(7001, 7) becomes 7001/7
    float of that is: 1000.14285714
    Decimal: 1000.1428571428571428571428571428571428571428571429
    4 elements cum sum of the list: 21086/21

(9, 3) becomes 3
    float of that is: 3.0
    Decimal: 3
    5 elements cum sum of the list: 21149/21

(611951, 611953) becomes 611951/611953
    float of that is: 0.999996731775
    Decimal: 0.99999673177515266695318104494953043779505942449829
    6 elements cum sum of the list: 12955044968/12851013

(1, 11) becomes 1/11
    float of that is: 0.0909090909091
    Decimal: 0.090909090909090909090909090909090909090909090909091
    7 elements cum sum of the list: 142518345661/141361143

(1, 7689585) becomes 1/7689585
    float of that is: 1.30046029792e-07
    Decimal: 1.3004602979224496510539905599586973809379829990825E-7
    8 elements cum sum of the list: 121767437017889092/120778724977295

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

Как это:

>>> Fraction(1,3) + Fraction(3,4)
Fraction(13, 12)
>>> Fraction(1,3) + Fraction(1,6)
Fraction(1, 2)
>>> Fraction(1,2).numerator
1
>>> Fraction(1,2).denominator
2

Модуль Fraction является частью стандартного дистрибутива Python (начиная с версии 2.6).

Чтобы преобразовать это в число с плавающей запятой, выполните, например, float(Fraction(17,18)) или используйте Fraction.numerator и Fraction().denominator в переменной класса Decimal для произвольного преобразования точности.

Вот так:

>>> decimal.Decimal(su.numerator) / decimal.Decimal(su.denominator)
Decimal('1008.186144047968368606384293')

or:

>>> float(su.numerator) / su.denominator
1008.1861440479684
person the wolf    schedule 11.06.2012
comment
извините, я не могу сделать поплавок (#). мне нужно использовать чистую целочисленную арифметику. как то, что я сделал в вопросе. - person 321; 11.06.2012

Прежде всего избегайте чисел с плавающей запятой.

>>> decimal.getcontext().prec = 50
>>> [str((decimal.Decimal(x) / decimal.Decimal(y)).quantize(decimal.Decimal(10) ** -40)) for (x, y) in FRACTIONS]
['0.1428571428571428571428571428571428571429', '0.6666666666666666666666666666666666666667', '3.1428571428571428571428571428571428571429', '1000.1428571428571428571428571428571428571429', '3.0000000000000000000000000000000000000000', '0.9999967317751526669531810449495304377951', '0.0909090909090909090909090909090909090909', '1.300460297922449651053990559958697E-7']
person Ignacio Vazquez-Abrams    schedule 11.06.2012