【问题标题】:Tips for making a fraction calculator code more optimized (faster and using less memory)使分数计算器代码更优化的技巧(更快,使用更少的内存)
【发布时间】:2010-06-06 20:30:49
【问题描述】:

基本上,我需要程序做的是为单行输入充当简单的分数计算器(用于加法,减法,乘法和除法),例如:
-输入: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 之外的任何库。

【问题讨论】:

  • 是的。请注意,我不需要完整的解决方案。我正在寻找的是可能适用于这种情况的一般提示。
  • 通过多次调用euclid(a*d,b*c),您可能使其比将结果存储在变量中的版本慢
  • +1 承认这是家庭作业,而不仅仅是找人为你做。 :)
  • 在旁注中,你的变量名是怎么回事?是使用不同的语言还是它们只是非常神秘的缩写? wyjscie?
  • @musicfreak,也许是波兰语

标签: python performance optimization


【解决方案1】:

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

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

【讨论】:

  • 如果不是因为我不能使用除 sys 之外的任何库这一事实(我忘了提 - 对不起!),那可能会完成工作。
【解决方案2】:

我将创建一个包含numeratordenominator 字段(均为整数)并实现__add____sub____mul____div__ 方法的类。然后你可以简单地使用普通的数学函数来组合实例。

对于您的目的而言,这可能有点矫枉过正,但代码会更简洁。

事实上,基于类的方法正是fractions 模块的实现方式。通常我会建议检查分数模块的源代码以查看它是如何编写的,但由于这是家庭作业,我不确定是否允许这样做。可能值得在分配结束后检查一下,看看如何实现一个成熟的小数类型。

【讨论】:

  • +1 我认为阅读别人写得好的代码可能是学习如何写好代码的最好方法之一。您绝对应该在某个时候查看fractions 模块的源代码,因为它可能写得非常好。
  • 好点!我一定会尝试了解它是如何在分数模块中完成的。正如丹尼尔所说,这可能有点矫枉过正,但肯定不是浪费。谢谢。
【解决方案3】:

您可以从单独的“+”、“-”等中提取出将分数减少到最低项的代码。这应该会使代码更简洁、更紧凑和可读。

【讨论】:

    【解决方案4】:

    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】:

      您可以在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("/"))
      

      【讨论】:

      • Euclid 的算法需要 O(log n) 步,所以记住它不会有太大帮助。此外,许多输入可能永远不会重复,因此程序运行的时间越长,记忆只会慢慢泄漏内存。
      • 您可以随时尝试记忆和非记忆,看看哪个更快。我想使用 timeit 模块 (docs.python.org/library/timeit.html) 是可以接受的,尽管有禁止使用库的规则。
      【解决方案6】:

      您还可以优化 euclid 函数。您可以使用Binary GCD,而不是使用欧几里得算法。

      实现算法的两种方法可以在here 找到,不幸的是代码是用 C 语言编写的。不过我认为如果你把它翻译成 python 并不难。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-06-30
        • 1970-01-01
        • 2012-08-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多