以一致或固定的精度打印数字

printing numbers with consistent or fixed accuracy

这三个数字1.2, 0.0034, 56000都有一个共同点:两位数准确度。假设我想报告几个非常不同的设备的计算带宽,范围从每秒千字节到每秒千兆字节,所有这些变化高达 %10。我的读者快速掌握结果的最简单方法是我将所有内容转换为通用单位(例如 MB/s),将小数点对齐,

    1.2
    0.0034
56000

并避免打印多余的数字;如果我的计算值是 1.193225、0.00344791 和 56188.5622,那么我的读者只需要看到上面的内容——其余的都是噪音。尽管有大量的浮点数格式化选项,Python 似乎没有一种干净的方法来打印具有 固定精度 的数字。执行此操作的最佳方法是什么?

关于给这个问题打分的注意事项:我会选择最好的(即简单、易懂、优雅)答案而不是第一个答案。不用着急。

import math


def round_s(n):
    if not n:
        return n
    e = int(math.floor(math.log10(abs(n)))) - 1
    return round(n, -e)


def fmt(n, size):
    return '{n:{size}f}'.format(size=size, n=n).rstrip('0').rstrip('.')


numbers = [
    1.193225,
    1.0,
    0,
    -1.0,
    0.00344791,
    -0.00344791,
    56188.5622,
    -56188.5622,
]

for n in numbers:
    print '{:12.5f} => {}'.format(n, fmt(round_s(n), 14))

输出:

     1.19322 =>       1.2
     1.00000 =>       1
     0.00000 =>       0
    -1.00000 =>      -1
     0.00345 =>       0.0034
    -0.00345 =>      -0.0034
 56188.56220 =>   56000
-56188.56220 =>  -56000

给你。

我会合并两个堆栈溢出答案(假设每个答案都是执行此任务的两个部分的最佳方式): Round to a specific number of significant figuresalign the numbers using the formatting language

from math import log10, floor
NUM_DIGITS = 2 # Number of significant digits

# An example input
number = 1.193225

# Round the number
rounded = round(number, -int(floor(log10(number))) + (NUM_DIGITS - 1)) 

# Print aligned to the decimal point
print('{part[0]:>3}.{part[1]:<3}'.format(part=str(rounded).split('.')))

您必须将字符串格式化程序中的两个宽度调整为至少与数字的最宽整数和小数部分一样宽。可以在相应的链接页面上找到完整的解释。

如果您想处理任何长度的字符串,您需要知道小数点前的最大位数:

def my_format(numbers):
    mxi = max(len(str(num).split(".")[0]) for num in numbers)
    for num in numbers:
        if isinstance(num, float):
            t = "{}".format(float("{:.2g}".format(num)))
            print(t.rjust((mxi + len(t.split(".")[-1]) + 1), " "))
        else:
            print("{:{mx}}".format(num, mx=mxi)

任何长度都应对齐:

In [10]: numbers = [
    1.193225,
    1.0,
    0,
    -1.0,
    0.00344791,
    -0.00344791,
    56188.5622,
    -56188.5622,
    123456789,
    12,
    123]

In [11]: my_format(numbers)
        1.2
        1.0
        0
       -1.0
        0.0034
       -0.0034
    56000.0
   -56000.0
123456789
       12
      123