Python 打印精度由另一个变量设置的浮点变量

Python 打印精度由另一个变量设置的浮点变量,python,rounding,string-formatting,precision,Python,Rounding,String Formatting,Precision,使用python,我想打印两个变量(浮点)的值。打印两个变量的精度应取决于变量值本身。事实上,我将打印一个值和相关的错误。我事先不知道“值”和“错误”会有多少相关数字 以下是一些例子: 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

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

以下是一些例子:

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语句中使用的精度,如下所示

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

你有什么建议吗?我相信解决办法很简单,但我找不到

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

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。换句话说,将值四舍五入到误差的一半,即四舍五入(2*N,p)/2,以解释应用于值范围的四舍五入。

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

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。换言之,将值舍入误差的一半
舍入(2*N,p)/2
,以解释应用于值范围的舍入。

我认为我们可以以某种方式使用包来实现这一点。我在玩弄它,并提出了以下解决方案。与阿兰给出的相比,它相当冗长,但可能需要进一步改进:

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)))
给出:

值为15236.26,误差为0.06
值为15236,误差为4
值为15200,误差为300
数值为15236.265,误差为0.059
数值为15236.26,误差为3.74
值为15236,误差为276

我想我们可以用这个软件包来实现这一点。我在玩弄它,并提出了以下解决方案。与阿兰给出的相比,它相当冗长,但可能需要进一步改进:

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)))
给出:

值为15236.26,误差为0.06
值为15236,误差为4
值为15200,误差为300
数值为15236.265,误差为0.059
数值为15236.26,误差为3.74
值为15236,误差为276

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