使分数计算器代码更优化的提示(更快,使用更少的内存)

时间:2010-06-06 20:30:50

标签: python performance optimization

基本上,我需要的程序是为单行输入操作一个简单的分数计算器(加法,减法,乘法和除法),例如:
- 输入:1/7 + 3/5
- 输出:26/35

我的初始代码:

import sys

def euclid(numA, numB):
    while numB != 0:
        numRem = numA % numB
        numA = numB
        numB = numRem
    return numA

for wejscie in sys.stdin:
    wyjscie = wejscie.split(' ')
    a, b = [int(x) for x in wyjscie[0].split("/")]
    c, d = [int(x) for x in wyjscie[2].split("/")]
    if wyjscie[1] == '+':
        licz = a * d + b * c
        mian= b * d
        nwd = euclid(licz, mian)
        konA = licz/nwd
        konB = mian/nwd
        wynik = str(konA) + '/' + str(konB)
        print(wynik)
    elif wyjscie[1] == '-':
        licz= a * d - b * c
        mian= b * d
        nwd = euclid(licz, mian)
        konA = licz/nwd
        konB = mian/nwd
        wynik = str(konA) + '/' + str(konB)
        print(wynik)
    elif wyjscie[1] == '*':
        licz= a * c
        mian= b * d
        nwd = euclid(licz, mian)
        konA = licz/nwd
        konB = mian/nwd
        wynik = str(konA) + '/' + str(konB)
        print(wynik)
    else:
        licz= a * d
        mian= b * c
        nwd = euclid(licz, mian)
        konA = licz/nwd
        konB = mian/nwd
        wynik = str(konA) + '/' + str(konB)
        print(wynik)

我将其缩减为:

import sys

def euclid(numA, numB):
    while numB != 0:
        numRem = numA % numB
        numA = numB
        numB = numRem
    return numA

for wejscie in sys.stdin:
    wyjscie = wejscie.split(' ')
    a, b = [int(x) for x in wyjscie[0].split("/")]
    c, d = [int(x) for x in wyjscie[2].split("/")]
    if wyjscie[1] == '+':
        print("/".join([str((a * d + b * c)/euclid(a * d + b * c, b * d)),str((b * d)/euclid(a * d + b * c, b * d))]))
    elif wyjscie[1] == '-':
        print("/".join([str((a * d - b * c)/euclid(a * d - b * c, b * d)),str((b * d)/euclid(a * d - b * c, b * d))]))
    elif wyjscie[1] == '*':
        print("/".join([str((a * c)/euclid(a * c, b * d)),str((b * d)/euclid(a * c, b * d))]))
    else:
        print("/".join([str((a * d)/euclid(a * d, b * c)),str((b * c)/euclid(a * d, b * c))]))

欢迎任何关于如何改进这一点的建议。

编辑:我还忘了提到的另一件事 - 除了sys之外,代码不能使用任何库。

6 个答案:

答案 0 :(得分:9)

你可以做的最大改进可能是使用Python(2.6)的fractions库:

>>> import fractions
>>> fractions.Fraction(1,7) + fractions.Fraction("3/5")
Fraction(26, 35)

答案 1 :(得分:5)

我创建了一个包含numeratordenominator字段(两个整数)并实现__add____sub____mul__和{{1 }} 方法。然后你可以简单地使用普通的数学函数来组合实例。

对于您的目的而言可能有点过分,但代码会更清晰。

实际上,基于类的方法正是__div__模块的实现方式。通常我建议检查分数模块的源代码,看它是如何写的,但由于这是作业,我不确定是否允许。在任务结束后可能值得检查,只是为了看看如何实现完整的小数字类型。

答案 2 :(得分:1)

你可以将代码从单个'+',' - '等减少到最低项。这应该使代码更清晰,更紧凑和可读。

答案 3 :(得分:1)

您可以在euclid函数上使用memoization,这有助于根据输入数据加快速度。但是这将使用更多的内存

您还可以在euclid

中使用元组分配
def euclid(numA, numB):
    while numB != 0:
        numA, numB = numB, numA % numB
    return numA

这里的地图更快

a, b, c, d = map(int, wyjscie[0].split("/")+wyjscie[2].split("/"))

答案 4 :(得分:1)

euclid分解为辅助函数是一个好主意。我建议尝试进一步将代码分解为更多辅助函数。

一个想法是创建四个函数(加,减,乘,除),如下所示:

def multiply(val1, val2):
    # Unpack the tuples.
    numerator1, denominator1 = val1
    numerator2, denoninator2 = val2

    # Figure out the resulting numerator and denominator here.

    # Return the result as a tuple.
    return numerator, denominator

重构你的代码以使用帮助函数,我认为你的主代码会更清晰。

答案 5 :(得分:0)

您还可以优化euclid功能。您可以使用Binary GCD而不是使用Euclid的算法。

可以找到两种实现算法的方法here,遗憾的是代码在C中。如果你把它翻译成python,我觉得还不是很难。