【问题标题】:Printing float variable with precision set by another variable以另一个变量设置的精度打印浮点变量
【发布时间】:2019-11-07 08:44:30
【问题描述】:

使用 python,我想打印两个变量(浮点数)的值。打印两个变量的精度应取决于变量值本身。事实上,我将打印一个值和相关的错误。我事先不知道“Value”和“Error”会有多少个相关数字。

下面是一些例子:

Value: 15236.265, Error = 0.059 --> printed value 15236.27 +- 0.06
Value: 15236.265, Error = 3.738 --> printed value 15236 +- 4
Value: 15236.265, Error = 275.658 --> printed value 15200 +- 300

理想情况下,我想确定打印语句中使用的精度,如下所示。

print(Value is {???} and error is {:.1g}).format(value, error)

你有什么建议吗?我确信解决方案相当简单,但我找不到它。

【问题讨论】:

    标签: python rounding string-formatting precision


    【解决方案1】:

    如果您使用格式字符串,这会容易得多,因为您甚至可以替换其中的格式参数。这将让您以编程方式控制所有属性:

    value = 15236.265
    error = 3.738
    p1    = 10
    p2    = 3
    print(f"Value is {value:.{p1}g} and error is {error:.{p2}g}")
    
    # 'Value is 15236.265 and error is 3.74'
    

    编辑

    我从您的评论中看到,这不是格式问题,而是四舍五入问题。您希望对错误的尾数进行四舍五入,并对值本身应用相同的舍入。

    这里有一个函数可以为你做到这一点:

    from math import log
    def roundError(N,E):
        p=-round(log(E,10)-0.5)
        return round(N,p),round(E,p)
    
    roundError(15236.265,0.059)   # --> (15236.26, 0.06)
    roundError(15236.265,3.738)   # --> (15236, 4)
    roundError(15236.265,275.658) # --> (15200, 300)  
    

    然后您可以打印这些数字而无需任何特殊格式。

    这对您来说可能不是问题,但我想指出,这种值/误差调整会稍微抵消误差范围内的可能值范围。

    例如:

    15236.265 +/- 275.658 ==> 14960.607 ... 15511.923
    15200     +/- 300     ==> 14900     ... 15500  (extra 60 low and missing 12 high)
    

    为了谨慎起见,可能需要四舍五入的值范围为 14950 ... 15550,因此为 15250 +/- 300。换句话说,将值四舍五入为错误round(2*N,p)/2 的一半考虑应用于值范围的舍入。

    【讨论】:

    • 这并不能完全解决问题,因为我不知道,先验,这两个值会有多少位数。此外,p2 应该始终为 1,p1 应该是错误格式的函数。
    • 我会说它仍然是一种格式而不是四舍五入,因为我不需要创建任何新变量,只需根据特定格式打印它们。虽然我同意差异是微妙的。实际上,您展示的函数几乎可以很好地工作,只是该函数可能返回诸如 (15236.0000001, 4) 之类的值。
    • 这是由于二进制浮点表示。我将函数更改为直接舍入值而不是相乘(但我不确定它是否会涵盖所有情况,因为某些分数根本不可能以二进制浮点数表示)。这将问题带回到格式化:)。我怀疑您可能可以使用函数中计算的p 的值来找出可行的格式规范(请注意 p 可以是负数或正数)
    【解决方案2】:

    我认为我们可以以某种方式使用decimal 包来实现这一点。我正在玩它并想出了以下解决方案。与 Alain 给出的 solution 相比,它相当冗长,但可能还可以进一步改进:

    from decimal import Decimal
    
    
    def error_format(value: float, 
                     error: float, 
                     significant_digits: int = 1):
        def remove_exponent(d):
            return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
    
        value = Decimal(str(value))
        error = Decimal(str(error))
        error_exp = error.logb()
        ndigits = -int(error_exp) + significant_digits - 1
        rounded_value = round(value, ndigits)
        rounded_error = round(error, ndigits)
        return remove_exponent(rounded_value), remove_exponent(rounded_error)
    

    以及用法示例:

    values = [15236.265] * 3
    errors = [0.059, 3.738, 275.658]
    
    for value, error in zip(values, errors):
        print('Value is {} and error is {}'.format(*error_format(value, error)))
    
    for value, error in zip(values, errors):
        print('Value is {} and error is {}'.format(*error_format(value, error, significant_digits=3)))
    

    给予:

    Value is 15236.26 and error is 0.06
    Value is 15236 and error is 4
    Value is 15200 and error is 300
    Value is 15236.265 and error is 0.059
    Value is 15236.26 and error is 3.74
    Value is 15236 and error is 276
    

    【讨论】:

      猜你喜欢
      • 2021-07-25
      • 2022-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-09
      • 2021-10-27
      • 2015-06-29
      相关资源
      最近更新 更多