【问题标题】:c# vs python float rounding differencesc# vs python float 舍入差异
【发布时间】:2019-01-03 18:42:13
【问题描述】:

我正在用python开发一个应用程序,其中一些部分是用c#编写的(为了加快速度),我很困惑为什么在使用“round”函数和字符串浮点时,c#浮点舍入的行为与python“相反”格式化函数,这里是一个例子:

Python (2.7)

>>> round(6.25, 1)
6.3
>>> "%.1f"%6.25
6.2

C#

>>> Math.Round(6.25,1)
6.2
>>> (6.25).ToString("F1")
6.3

有人理解为什么 Python 与 c# 之间的行为看似“相反”吗?有没有办法将“双”浮点值四舍五入为 N 个十进制数字,以在 Python 和 C# 之间产生有保证的相同字符串输出?

【问题讨论】:

    标签: c# python floating-point rounding


    【解决方案1】:

    这是由于您调用的两个方法的中点分辨率。

    Python 的round(number[, ndigits])

    返回四舍五入到小数点后ndigits 位的浮点值数字。如果省略ndigits,则默认为零。结果是一个浮点数。值四舍五入到最接近的 10 的幂减去ndigits 的倍数;如果两个倍数同样接近,则从 0 开始舍入(例如,round(0.5)1.0round(-0.5)-1.0)。

    C#的Math.Round(double, int)

    将双精度浮点值四舍五入为指定的小数位数,并将中点值四舍五入为最接近的偶数。

    换句话说:

    • Python 从零开始舍入(6.25 变为 6.3,因为 6.3 距离 06.2 更远)
    • C# 舍入到最接近的偶数,因此 6.25 变为 6.2,因为 6.2 是最接近的偶数。

    您可以通过使用Math.Round 的重载之一来解决此问题,该重载采用MidpointRounding enum value,例如Round(double, int, MidpointRounding) ,例如:

    Math.Round(6.25, 1,  MidpointRounding.AwayFromZero);
    

    这将做与 Python 舍入相同的事情。

    【讨论】:

      【解决方案2】:

      参考Banker's Rounding
      这是一个有意的实现细节。 如果您希望保留“始终向上舍入 0.5”的方法或您希望的任何其他舍入方式,您可以通过执行以下操作来实现:

      import decimal
      #The rounding you are looking for
      decimal.Decimal('3.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_UP)
      >>> Decimal('4')
      decimal.Decimal('2.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_UP)
      >>> Decimal('3')
      
      
      #Other kinds of rounding
      decimal.Decimal('2.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_EVEN)
      >>> Decimal('2')
      
      decimal.Decimal('3.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_DOWN)
      >>> Decimal('3')
      

      【讨论】:

      • 感谢有关 python2 与 python3 差异的链接,我没有意识到它们实现 round() 的方式不同,我的问题仅适用于 2.7。看起来 python3 round() 和 c# 一样。
      • @glexey 不客气。我想我不妨为您提供有关此主题所需的所有文档,因为它是一个相当具体的实现细节
      【解决方案3】:

      Math.Round 默认使用庄家四舍五入,四舍五入到最接近的偶数值(例如,Math.Round(6.25,1) -> 6.2,如您所见,Math.Round(6.35,1) -> 6.4)。要更改此设置,请使用指定 MidpointRounding 值,例如 Math.Round(6.25, 1, MidpointRounding.AwayFromZero)

      至于其他问题,double.ToString() 会导致舍入。有关此问题的解决方案,请参阅C# Double - ToString() formatting with two decimal places but no rounding

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-13
        • 1970-01-01
        • 2017-03-04
        • 1970-01-01
        • 1970-01-01
        • 2015-03-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多