【问题标题】:Which stage to round at?轮到哪个阶段?
【发布时间】:2018-02-01 17:35:08
【问题描述】:

在Python中,应该在什么阶段使用round?举个例子:10 * math.log(x) + 10如果我想把这个四舍五入,我应该使用哪个?

round(10 * math.log(x) + 5)
round(10 * math.log(x)) + 5
10 * round(math.log(x)) + 5

我的猜测是,早期舍入会运行得最快,因为更多的算术运算发生在整数上,看起来它们应该比浮点数更快。如果后来的一些值发生变化,舍入似乎不太可能中断。

答案会和int()一样吗?

【问题讨论】:

  • 如果math.log(x)的结果是0.5,你希望10 * math.log(x)0还是5
  • 为什么速度在这里永远是一个标准?您使用的域很重要。如果你在大楼的第 100 层,你会因为比乘电梯更快而走出窗户吗?至少这里的结果(有点)相同,你在 1 楼 - aDlEiAvDe
  • 你的表达不一样。准确性而不是微基准测试应该是您的标准。
  • 如果不了解为什么你首先要四舍五入,就不可能回答这个问题。目的是什么?如何使用四舍五入的值? (通常,“何时舍入?”的答案要么是“从不!”,要么是“仅在向用户显示结果时”,在后一种情况下,您希望使用字符串格式,而不是 round 内置函数。)

标签: python rounding


【解决方案1】:

不要过早优化。在许多情况下,不是高度优化的数学函数会减慢程序的速度,而是逻辑结构数据类型 用于计算。

为此,我建议您使用cProfile 来识别瓶颈。请注意,cProfile 本身有开销,因此它主要用于相对比较。

根据@glibdud 的评论,您必须了解舍入将如何影响您的计算。尝试几个示例,或执行测试以查看您的错误在大量输入中的变化情况。

【讨论】:

  • +1 表示不会过早优化。为什么要实施此更改背后的逻辑比您可能看到的非常小的性能增益更为重要。
【解决方案2】:

请注意 Python Math.log() 函数默认是 e 的基础。根据您的问题,不清楚您期望的基数是多少,所以我假设像 Google 一样的对数基数为 10。为了使其等效于所提供的数学函数,代码需要:

import math
#assuming x equals 2
x = 2
function1 = round(10 * math.log(x,10) + 5)
function2 = round(10 * math.log(x,10)) + 5)
function3 = 10 * round(math.log(x,10)) + 5)
function4 = 10*math.log(x,10)+5

print(function1)
print(function2)
print(function3)
print(function4)

现在,假设 x = 2,数学方程的计算结果为 8.01029995664 查看上述代码的打印输出:

8
8
5
8.010299956639813

它清楚地表明函数 1,2 和 4 在数学上大致等效,而函数 3 不正确。这是因为 round 函数使用 Half 和 A​​bove 规则进行四舍五入。 Math.log(2,10) 的结果为 0.3,因此当舍入函数发生时,它会降至零。

至于 int() 和 round() 的等价性,IMCoins 引用的链接非常好。总和是 int() 从数字中删除十进制值,并且回合使用一半及以上规则,因此对于小于 x.5 的任何内容,它都会像 int() 一样。

至于速度问题,如果准确性是不可协商的,最好在完成答案后进行四舍五入,原因与上述函数 3 错误的原因相同。如果您相当确定您可以一步一步安全地四舍五入,那么我同意上面使用 CProfile 并找到瓶颈的答案

希望这会有所帮助。

【讨论】:

  • 我没有看到任何迹象表明 OP 想要日志基数 10 而不是自然对数,因此您使用 math.log(x, 10) 似乎不合理。
  • 没错,这可能是不合理的,因为没有迹象表明他想要什么基地。因为我没有手动计算,所以我使用假设基数为 10 的谷歌验证了答案。因此我改变了它。我将修改措辞以反映这一点
  • 我喜欢这里的答案(我投了赞成票!),因为它通过示例解决问题中的两个部分的方式。这个问题真的很令人困惑,无论你如何四舍五入,你怎么能用这些公式得到10 * math.log(x) + 10 的接近结果......难怪人们会怀疑这个基础。但!看完这个答案,我明白了,哦,问题是问速度:)
【解决方案3】:

这完全取决于您希望如何格式化和解释您的答案。不过,我不会对轮函数的速度感兴趣(除非非常小的性能提升对您的程序至关重要)。我会考虑通过四舍五入来完成什么。如果您的目标是产生一个四舍五入到最接近整数的输出(为简单起见),那么我会将您的整个算术语句包含在 round 函数中。如果您的目标是仅在对数计算中使用舍入整数(可能是因为您不想使用浮点数),那么您应该只舍入 math.log(x) 函数。没有技术原因您会使用其中任何一个,但绝对有一个合乎逻辑的原因,您想要选择您的任何一个选项。

【讨论】:

    【解决方案4】:

    您越早四舍五入,您的结果受此四舍五入的影响就越大。在我看来,这完全取决于您对程序的期望。

    至于difference between int() and round(),本帖完美解答。

    为了更具体地解决您关于性能的问题:round() 函数是一个 python 内置函数,它是用 C 实现的,您不必真正担心性能,因为它会非常,非常可以忽略不计。

    Round function

    【讨论】:

      【解决方案5】:

      我不知道,但让我们看看:)

      import time
      import math
      
      n = 1000000
      x = 5
      
      def timeit(f):
      
          t_0 = time.perf_counter()
      
          for _ in range(n):
              f()
      
          t_1 = time.perf_counter()
      
          print((t_1 - t_0)/ n)        
      
      def fun1():
          round(10 * math.log(x) + 5)
      
      def fun2():
          round(10 * math.log(x)) + 5
      
      def fun3():
          10 * round(math.log(x)) + 5    
      
      [timeit(_) for _ in [fun1, fun2, fun3]] 
      

      在我的电脑上,最后一个比其他的稍快。

      【讨论】:

      • 我无法通过此测试获得一致的结果。每次运行都有不同的表现,每个函数有时都比其他两个表现更好。
      • 取决于列表中的顺序?
      • 什么意思?结果混合在一起,列表中的第一项有时大于其余项,有时小于。我是说这两个功能似乎都没有表现得更好。
      • 任何想法如何以可靠的方式进行测试?
      • 我认为你的测试很好,我的观点是 round() 函数的排序几乎没有区别
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多