# 如何将 Python 中的数字舍入为有效数字

[英]How to round a number to significant figures in Python

I need to round a float to be displayed in a UI.我需要将浮点数舍入以显示在 UI 中。 eg, to one significant figure:例如，一个有效数字：

``````1234 -> 1000

0.12 -> 0.1

0.012 -> 0.01

0.062 -> 0.06

6253 -> 6000

1999 -> 2000
``````

Is there a nice way to do this using the Python library, or do I have to write it myself?有没有使用 Python 库的好方法，还是我必须自己编写？

You can use negative numbers to round integers:您可以使用负数来舍入整数：

``````>>> round(1234, -3)
1000.0
``````

Thus if you need only most significant digit:因此，如果您只需要最高有效数字：

``````>>> from math import log10, floor
>>> def round_to_1(x):
...   return round(x, -int(floor(log10(abs(x)))))
...
>>> round_to_1(0.0232)
0.02
>>> round_to_1(1234243)
1000000.0
>>> round_to_1(13)
10.0
>>> round_to_1(4)
4.0
>>> round_to_1(19)
20.0
``````

You'll probably have to take care of turning float to integer if it's bigger than 1.如果它大于 1，您可能需要注意将浮点数转换为整数。

%g in string formatting will format a float rounded to some number of significant figures.字符串格式中的 %g 将格式化一个四舍五入到一些有效数字的浮点数。 It will sometimes use 'e' scientific notation, so convert the rounded string back to a float then through %s string formatting.它有时会使用 'e' 科学记数法，因此将四舍五入的字符串转换回浮点数，然后通过 %s 字符串格式。

``````>>> '%s' % float('%.1g' % 1234)
'1000'
>>> '%s' % float('%.1g' % 0.12)
'0.1'
>>> '%s' % float('%.1g' % 0.012)
'0.01'
>>> '%s' % float('%.1g' % 0.062)
'0.06'
>>> '%s' % float('%.1g' % 6253)
'6000.0'
>>> '%s' % float('%.1g' % 1999)
'2000.0'
``````

If you want to have other than 1 significant decimal (otherwise the same as Evgeny):如果您想拥有 1 位以外的有效小数（否则与 Evgeny 相同）：

``````>>> from math import log10, floor
>>> def round_sig(x, sig=2):
...   return round(x, sig-int(floor(log10(abs(x))))-1)
...
>>> round_sig(0.0232)
0.023
>>> round_sig(0.0232, 1)
0.02
>>> round_sig(1234243, 3)
1230000.0
``````
``````f'{float(f"{i:.1g}"):g}'
# Or with Python <3.6,
'{:g}'.format(float('{:.1g}'.format(i)))
``````

This solution is different from all of the others because:此解决方案与所有其他解决方案不同，因为：

1. it exactly solves the OP question正好解决了 OP 问题
2. it does not need any extra package不需要任何额外
3. it does not need any user-defined auxiliary function or mathematical operation不需要任何用户定义的辅助功能数学运算

For an arbitrary number `n` of significant figures, you can use:对于任意数量`n`的有效数字，您可以使用：

``````print('{:g}'.format(float('{:.{p}g}'.format(i, p=n))))
``````

Test:测试：

``````a = [1234, 0.12, 0.012, 0.062, 6253, 1999, -3.14, 0., -48.01, 0.75]
b = ['{:g}'.format(float('{:.1g}'.format(i))) for i in a]
# b == ['1000', '0.1', '0.01', '0.06', '6000', '2000', '-3', '0', '-50', '0.8']
``````

Note : with this solution, it is not possible to adapt the number of significant figures dynamically from the input because there is no standard way to distinguish numbers with different numbers of trailing zeros ( `3.14 == 3.1400` ).注意：使用此解决方案，无法根据输入动态调整有效数字的数量，因为没有标准方法来区分具有不同尾随零数量的数字 ( `3.14 == 3.1400` )。 If you need to do so, then non-standard functions like the ones provided in the to-precision package are needed.如果您需要这样做，则需要像to-precision包中提供的非标准函数。

I have created the package to-precision that does what you want.我已经创建了可以满足您要求的精度包。 It allows you to give your numbers more or less significant figures.它允许您提供或多或少的有效数字。

It also outputs standard, scientific, and engineering notation with a specified number of significant figures.它还输出具有指定数量的有效数字的标准、科学和工程符号。

In the accepted answer there is the line在接受的答案中有一行

``````>>> round_to_1(1234243)
1000000.0
``````

That actually specifies 8 sig figs.这实际上指定了 8 个无花果。 For the number 1234243 my library only displays one significant figure:对于数字 1234243，我的图书馆只显示一位有效数字：

``````>>> from to_precision import to_precision
>>> to_precision(1234243, 1, 'std')
'1000000'
>>> to_precision(1234243, 1, 'sci')
'1e6'
>>> to_precision(1234243, 1, 'eng')
'1e6'
``````

It will also round the last significant figure and can automatically choose what notation to use if a notation isn't specified:如果未指定符号，它还会舍入最后一个有效数字，并可以自动选择要使用的符号：

``````>>> to_precision(599, 2)
'600'
>>> to_precision(1164, 2)
'1.2e3'
``````

To directly answer the question, here's my version using naming from the R function :为了直接回答这个问题，这是我使用R 函数命名的版本：

``````import math

def signif(x, digits=6):
if x == 0 or not math.isfinite(x):
return x
digits -= math.ceil(math.log10(abs(x)))
return round(x, digits)
``````

My main reason for posting this answer are the comments complaining that "0.075" rounds to 0.07 rather than 0.08.我发布此答案的主要原因是评论抱怨“0.075”四舍五入为 0.07 而不是 0.08。 This is due, as pointed out by "Novice C", to a combination of floating point arithmetic having both finite precision and a base-2 representation .正如“C 新手”所指出的那样，这是由于具有有限精度和基数 2 表示的浮点运算的组合。 The nearest number to 0.075 that can actually be represented is slightly smaller, hence rounding comes out differently than you might naively expect.实际可以表示的最接近 0.075 的数字略小，因此四舍五入的结果与您可能天真地预期的不同。

Also note that this applies to any use of non-decimal floating point arithmetic, eg C and Java both have the same issue.另请注意，这适用于任何非十进制浮点运算的使用，例如 C 和 Java 都有相同的问题。

To show in more detail, we ask Python to format the number in "hex" format:为了更详细地显示，我们要求 Python 将数字格式化为“十六进制”格式：

``````0.075.hex()
``````

which gives us: `0x1.3333333333333p-4` .这给了我们： `0x1.3333333333333p-4` The reason for doing this is that the normal decimal representation often involves rounding and hence is not how the computer actually "sees" the number.这样做的原因是正常的十进制表示通常涉及四舍五入，因此不是计算机实际“看到”数字的方式。 If you're not used to this format, a couple of useful references are the Python docs and the C standard .如果您不习惯这种格式，可以参考Python 文档C 标准.

To show how these numbers work a bit, we can get back to our starting point by doing:为了展示这些数字是如何工作的，我们可以通过执行以下操作回到我们的起点：

``````0x13333333333333 / 16**13 * 2**-4
``````

which should should print out `0.075` .应该打印出`0.075` `16**13` is because there are 13 hexadecimal digits after the decimal point, and `2**-4` is because hex exponents are base-2. `16**13`是因为小数点后有 13 个十六进制数字， `2**-4`是因为十六进制指数是以 2 为底的。

Now we have some idea of how floats are represented we can use the `decimal` module to give us some more precision, showing us what's going on:现在我们对浮点数的表示方式有了一些了解，我们可以使用`decimal`模块来提高精度，向我们展示发生了什么：

``````from decimal import Decimal

Decimal(0x13333333333333) / 16**13 / 2**4
``````

giving: `0.07499999999999999722444243844` and hopefully explaining why `round(0.075, 2)` evaluates to `0.07`给出： `0.07499999999999999722444243844`并希望解释为什么`round(0.075, 2)`评估为`0.07`

To round an integer to 1 significant figure the basic idea is to convert it to a floating point with 1 digit before the point and round that, then convert it back to its original integer size.要将整数四舍五入为 1 位有效数字，基本思想是将其转换为在该点前有 1 位数字的浮点数并四舍五入，然后将其转换回其原始整数大小。

To do this we need to know the largest power of 10 less than the integer.为此，我们需要知道小于整数的 10 的最大幂。 We can use floor of the log 10 function for this.为此，我们可以使用 log 10 函数的 floor。

` `from math import log10, floor def round_int(i,places): if i == 0: return 0 isign = i/abs(i) i = abs(i) if i < 1: return 0 max10exp = floor(log10(i)) if max10exp+1 < places: return i sig10pow = 10**(max10exp-places+1) floated = i*1.0/sig10pow defloated = round(floated)*sig10pow return int(defloated*isign)``

I modified indgar's solution to handle negative numbers and small numbers (including zero).我修改了 indgar 的解决方案来处理负数和小数（包括零）。

``````from math import log10, floor
def round_sig(x, sig=6, small_value=1.0e-9):
return round(x, sig - int(floor(log10(max(abs(x), abs(small_value))))) - 1)
``````
``````def round_to_n(x, n):
if not x: return 0
power = -int(math.floor(math.log10(abs(x)))) + (n - 1)
factor = (10 ** power)
return round(x * factor) / factor

round_to_n(0.075, 1)      # 0.08
round_to_n(0, 1)          # 0
round_to_n(-1e15 - 1, 16) # 1000000000000001.0
``````

Hopefully taking the best of all the answers above (minus being able to put it as a one line lambda ;) ).希望能充分利用上述所有答案（减去能够将其作为一行 lambda ;) ）。 Haven't explored yet, feel free to edit this answer:尚未探索，请随时编辑此答案：

``````round_to_n(1e15 + 1, 11)  # 999999999999999.9
``````

I can't think of anything that would be able to handle this out of the box.我想不出有什么可以开箱即用地处理这个问题。 But it's fairly well handled for floating point numbers.但它对于浮点数处理得相当好。

``````>>> round(1.2322, 2)
1.23
``````

Integers are trickier.整数更棘手。 They're not stored as base 10 in memory, so significant places isn't a natural thing to do.它们不是以 10 为基数存储在内存中，因此重要的地方不是很自然的事情。 It's fairly trivial to implement once they're a string though.不过，一旦它们是一个字符串，实现起来就相当简单了。

Or for integers:或者对于整数：

``````>>> def intround(n, sigfigs):
...   n = str(n)
...   return n[:sigfigs] + ('0' * (len(n)-(sigfigs)))

>>> intround(1234, 1)
'1000'
>>> intround(1234, 2)
``````

If you would like to create a function that handles any number, my preference would be to convert them both to strings and look for a decimal place to decide what to do:如果你想创建一个处理任何数字的函数，我的偏好是将它们都转换为字符串并查找小数位来决定做什么：

``````>>> def roundall1(n, sigfigs):
...   n = str(n)
...   try:
...     sigfigs = n.index('.')
...   except ValueError:
...     pass
...   return intround(n, sigfigs)
``````

Another option is to check for type.另一种选择是检查类型。 This will be far less flexible, and will probably not play nicely with other numbers such as `Decimal` objects:这将不那么灵活，并且可能无法很好地与其他数字（例如`Decimal`对象）配合使用：

``````>>> def roundall2(n, sigfigs):
...   if type(n) is int: return intround(n, sigfigs)
...   else: return round(n, sigfigs)
``````

If you want to round without involving strings, the link I found buried in the comments above:如果你想在不涉及字符串的情况下舍入，我在上面的评论中找到的链接：

strikes me as best.给我留下了最好的印象。 Then when you print with any string formatting descriptors, you get a reasonable output, and you can use the numeric representation for other calculation purposes.然后，当您使用任何字符串格式描述符进行打印时，您将获得合理的输出，并且您可以将数字表示用于其他计算目的。

The code at the link is a three liner: def, doc, and return.链接中的代码是三行代码：def、doc 和 return。 It has a bug: you need to check for exploding logarithms.它有一个错误：您需要检查爆炸对数。 That is easy.那很容易。 Compare the input to `sys.float_info.min` .将输入与`sys.float_info.min`进行比较。 The complete solution is:完整的解决方案是：

``````import sys,math

def tidy(x, n):
"""Return 'x' rounded to 'n' significant digits."""
y=abs(x)
if y <= sys.float_info.min: return 0.0
return round( x, int( n-math.ceil(math.log10(y)) ) )
``````

It works for any scalar numeric value, and n can be a `float` if you need to shift the response for some reason.它适用于任何标量数值，如果出于某种原因需要移动响应，n 可以是`float` You can actually push the limit to:您实际上可以将限制推到：

``````sys.float_info.min*sys.float_info.epsilon
``````

without provoking an error, if for some reason you are working with miniscule values.不会引起错误，如果出于某种原因您正在使用微不足道的值。

The posted answer was the best available when given, but it has a number of limitations and does not produce technically correct significant figures.发布的答案在给出时是最好的，但它有许多限制，并且不会产生技术上正确的有效数字。

numpy.format_float_positional supports the desired behaviour directly. numpy.format_float_positional直接支持所需的行为。 The following fragment returns the float `x` formatted to 4 significant figures, with scientific notation suppressed.以下片段返回格式化为 4 位有效数字的浮点数`x` ，科学记数法被抑制。

``````import numpy as np
x=12345.6
np.format_float_positional(x, precision=4, unique=False, fractional=False, trim='k')
> 12340.
``````

The sigfig package/library covers this. sigfig包/库涵盖了这一点。 After installing you can do the following:安装后，您可以执行以下操作：

``````>>> from sigfig import round
>>> round(1234, 1)
1000
>>> round(0.12, 1)
0.1
>>> round(0.012, 1)
0.01
>>> round(0.062, 1)
0.06
>>> round(6253, 1)
6000
>>> round(1999, 1)
2000
``````

Using python 2.6+ new-style formatting (as %-style is deprecated):使用 python 2.6+ 新样式格式（因为 %-style 已弃用）：

``````>>> "{0}".format(float("{0:.1g}".format(1216)))
'1000.0'
>>> "{0}".format(float("{0:.1g}".format(0.00356)))
'0.004'
``````

In python 2.7+ you can omit the leading `0` s.在 python 2.7+ 中，您可以省略前导`0`

I ran into this as well but I needed control over the rounding type.我也遇到了这个问题，但我需要控制舍入类型。 Thus, I wrote a quick function (see code below) that can take value, rounding type, and desired significant digits into account.因此，我编写了一个快速函数（见下面的代码），它可以考虑值、舍入类型和所需的有效数字。

``````import decimal
from math import log10, floor

def myrounding(value , roundstyle='ROUND_HALF_UP',sig = 3):
roundstyles = [ 'ROUND_05UP','ROUND_DOWN','ROUND_HALF_DOWN','ROUND_HALF_UP','ROUND_CEILING','ROUND_FLOOR','ROUND_HALF_EVEN','ROUND_UP']

power =  -1 * floor(log10(abs(value)))
value = '{0:f}'.format(value) #format value to string to prevent float conversion issues
divided = Decimal(value) * (Decimal('10.0')**power)
roundto = Decimal('10.0')**(-sig+1)
if roundstyle not in roundstyles:
print('roundstyle must be in list:', roundstyles) ## Could thrown an exception here if you want.
return_val = decimal.Decimal(divided).quantize(roundto,rounding=roundstyle)*(decimal.Decimal(10.0)**-power)
nozero = ('{0:f}'.format(return_val)).rstrip('0').rstrip('.') # strips out trailing 0 and .
return decimal.Decimal(nozero)

for x in list(map(float, '-1.234 1.2345 0.03 -90.25 90.34543 9123.3 111'.split())):
print (x, 'rounded UP: ',myrounding(x,'ROUND_UP',3))
print (x, 'rounded normal: ',myrounding(x,sig=3))
``````

This function does a normal round if the number is bigger than 10**(-decimal_positions), otherwise adds more decimal until the number of meaningful decimal positions is reached:如果数字大于 10**(-decimal_positions)，则此函数执行正常舍入，否则添加更多小数，直到达到有意义的小数位数：

``````def smart_round(x, decimal_positions):
dp = - int(math.log10(abs(x))) if x != 0.0 else int(0)
return round(float(x), decimal_positions + dp if dp > 0 else decimal_positions)
``````

Hope it helps.希望能帮助到你。

https://stackoverflow.com/users/1391441/gabriel , does the following address your concern about rnd(.075, 1)? https://stackoverflow.com/users/1391441/gabriel ，以下内容是否解决了您对 rnd(.075, 1) 的担忧？ Caveat: returns value as a float警告：以浮点数形式返回值

``````def round_to_n(x, n):
fmt = '{:1.' + str(n) + 'e}'    # gives 1.n figures
p = fmt.format(x).split('e')    # get mantissa and exponent
# round "extra" figure off mantissa
p[0] = str(round(float(p[0]) * 10**(n-1)) / 10**(n-1))
return float(p[0] + 'e' + p[1]) # convert str to float

>>> round_to_n(750, 2)
750.0
>>> round_to_n(750, 1)
800.0
>>> round_to_n(.0750, 2)
0.075
>>> round_to_n(.0750, 1)
0.08
>>> math.pi
3.141592653589793
>>> round_to_n(math.pi, 7)
3.141593
``````

This returns a string, so that results without fractional parts, and small values which would otherwise appear in E notation are shown correctly:这将返回一个字符串，以便正确显示没有小数部分的结果和否则会出现在 E 符号中的小值：

``````def sigfig(x, num_sigfig):
num_decplace = num_sigfig - int(math.floor(math.log10(abs(x)))) - 1
return '%.*f' % (num_decplace, round(x, num_decplace))
``````

This suits my aesthetic a little better, though many of the above are comparable这更适合我的审美，尽管以上许多都具有可比性

``````import numpy as np

number=-456.789
significantFigures=4

roundingFactor=significantFigures - int(np.floor(np.log10(np.abs(number)))) - 1
rounded=np.round(number, roundingFactor)

string=rounded.astype(str)

print(string)
``````

This works for individual numbers and numpy arrays, and should function fine for negative numbers.这适用于单个数字和 numpy 数组，并且对于负数应该可以正常工作。

There's one additional step we might add - np.round() returns a decimal number even if rounded is an integer (ie for significantFigures=2 we might expect to get back -460 but instead we get -460.0).我们可能会添加一个额外的步骤 - 即使四舍五入是一个整数， np.round() 也会返回一个十进制数（即，对于重要数字 = 2，我们可能期望返回 -460，但我们得到 -460.0）。 We can add this step to correct for that:我们可以添加此步骤来纠正：

``````if roundingFactor<=0:
rounded=rounded.astype(int)
``````

Unfortunately, this final step won't work for an array of numbers - I'll leave that to you dear reader to figure out if you need.不幸的是，这最后一步不适用于一组数字 - 我将把它留给亲爱的读者来确定您是否需要。

``````import math

def sig_dig(x, n_sig_dig):
num_of_digits = len(str(x).replace(".", ""))
if n_sig_dig >= num_of_digits:
return x
n = math.floor(math.log10(x) + 1 - n_sig_dig)
result = round(10 ** -n * x) * 10 ** n
return float(str(result)[: n_sig_dig + 1])

>>> sig_dig(1234243, 3)
>>> sig_dig(243.3576, 5)

1230.0
243.36
``````

Most of these answers involve the math, decimal and/or numpy imports or output values as strings.这些答案中的大多数都涉及作为字符串的数学、十进制和/或 numpy 导入或输出值。 Here is a simple solution in base python that handles both large and small numbers and outputs a float:这是基本python中的一个简单解决方案，它可以处理大数和小数并输出一个浮点数：

``````def sig_fig_round(number, digits=3):
power = "{:e}".format(number).split('e')[1]
return round(number, -(int(power) - digits))
``````

A simple variant using the standard decimal library使用标准十进制库的简单变体

``````from decimal import Decimal

def to_significant_figures(v: float, n_figures: int) -> str:
d = Decimal(v)
d = d.quantize(Decimal((0, (), d.adjusted() - n_figures + 1)))
return str(d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize())
``````

Testing it测试它

``````>>> to_significant_figures(1.234567, 3)
'1.23'
>>> to_significant_figures(1234567, 3)
'1230000'
>>> to_significant_figures(1.23, 7)
'1.23'
>>> to_significant_figures(123, 7)
'123'
``````

This function takes both positive and negative numbers and does the proper significant digit rounding.此函数采用正数和负数，并进行适当的有效数字舍入。

``````from math import floor

def significant_arithmetic_rounding(n, d):
# Checking whether the no. is negative or positive. If it is negative we will take the absolute value of it and proceed
neg_flag = 0
if n < 0:
neg_flag = 1
n = abs(n)

n1 = n
# Counting the no. of digits to the left of the decimal point in the no.
ld = 0
while(n1 >= 1):
n1 /= 10
ld += 1

n1 = n
# Counting the no. of zeros to the right of the decimal point and before the first significant digit in the no.
z = 0
if ld == 0:
while(n1 <= 0.1):
n1 *= 10
z += 1

n1 = n
# No. of digits to be considered after decimal for rounding
rd = (d - ld) + z
n1 *= 10 ** rd

# Increase by 0.5 and take the floor value for rounding
n1 = floor(n1+0.5)

# Placing the decimal point at proper position
n1 /= 10 ** rd

# If the original number is negative then make it negative
if neg_flag == 1:
n1 = 0 - n1

return n1
``````

Testing:测试：

``````>>> significant_arithmetic_rounding(1234, 3)
1230.0
>>> significant_arithmetic_rounding(123.4, 3)
123.0
>>> significant_arithmetic_rounding(0.0012345, 3)
0.00123
>>> significant_arithmetic_rounding(-0.12345, 3)
-0.123
>>> significant_arithmetic_rounding(-30.15345, 3)
-30.2
``````

``````def sigfiground(number:float, ndigits=3)->float:
return float(f"{number:.{ndigits}g}")
``````

I use it when I still want a float (I do formatting elsewhere).当我仍然想要一个浮点数时我会使用它（我在其他地方进行格式化）。

Easier to know an answer works for your needs when it includes examples.当包含示例时，更容易知道答案是否适合您的需求。 The following is built on previous solutions, but offers a more general function which can round to 1, 2, 3, 4, or any number of significant digits.以下是基于以前的解决方案构建的，但提供了更通用的 function，它可以四舍五入到 1、2、3、4 或任意数量的有效数字。

``````import math

# Given x as float or decimal, returns as string a number rounded to "sig" significant digts
# Return as string in order to control significant digits, could be a float or decimal
def round_sig(x, sig=2):
r = round(x, sig-int(math.floor(math.log10(abs(x))))-1)
floatsig = "%." + str(sig) + "g"
return "%d"%r if abs(r) >= 10**(sig-1) else '%s'%float(floatsig % r)

>>> a = [1234, 123.4, 12.34, 1.234, 0.1234, 0.01234, 0.25, 1999, -3.14, -48.01, 0.75]
>>> [print(i, "->", round_sig(i,1), round_sig(i), round_sig(i,3), round_sig(i,4)) for i in a]

1234 -> 1000 1200 1230 1234
123.4 -> 100 120 123 123.4
12.34 -> 10 12 12.3 12.34
1.234 -> 1 1.2 1.23 1.234
0.1234 -> 0.1 0.12 0.123 0.1234
0.01234 -> 0.01 0.012 0.0123 0.01234
0.25 -> 0.2 0.25 0.25 0.25
1999 -> 2000 2000 2000 1999
-3.14 -> -3 -3.1 -3.14 -3.14
-48.01 -> -50 -48 -48.0 -48.01
0.75 -> 0.8 0.75 0.75 0.75
``````

in very cases, the number of significant is depend on to the evaluated process, eg error.在很多情况下，重要的数量取决于评估的过程，例如错误。 I wrote the some codes which returns a number according to it's error (or with some desired digits) and also in string form (which doesn't eliminate right side significant zeros)我编写了一些代码，它们根据错误（或一些所需的数字）以及字符串形式（不会消除右侧有效零）返回一个数字

``````import numpy as np

def Sig_Digit(x, *N,):
if abs(x) < 1.0e-15:
return(1)
N = 1 if N ==() else N[0]
k = int(round(abs(N)-1))-int(np.floor(np.log10(abs(x))))
return(k);

def Sig_Format(x, *Error,):
if abs(x) < 1.0e-15:
return('{}')
Error = 1 if Error ==() else abs(Error[0])
k = int(np.floor(np.log10(abs(x))))
z = x/10**k
k = -Sig_Digit(Error, 1)
m = 10**k
y = round(x*m)/m
if k < 0:
k = abs(k)
if z >= 9.5:
FMT = '{:'+'{}'.format(1+k)+'.'+'{}'.format(k-1)+'f}'
else:
FMT = '{:'+'{}'.format(2+k)+'.'+'{}'.format(k)+'f}'
elif k == 0:
if z >= 9.5:
FMT = '{:'+'{}'.format(1+k)+'.0e}'
else:
FMT = '{:'+'{}'.format(2+k)+'.0f}'
else:
FMT = '{:'+'{}'.format(2+k)+'.'+'{}'.format(k)+'e}'
return(FMT)

def Sci_Format(x, *N):
if abs(x) < 1.0e-15:
return('{}')
N = 1 if N ==() else N[0]
N = int(round(abs(N)-1))
y = abs(x)
k = int(np.floor(np.log10(y)))
z = x/10**k
k = k-N
m = 10**k
y = round(x/m)*m
if k < 0:
k = abs(k)
if z >= 9.5:
FMT = '{:'+'{}'.format(1+k)+'.'+'{}'.format(k-1)+'f}'
else:
FMT = '{:'+'{}'.format(2+k)+'.'+'{}'.format(k)+'f}'
elif k == 0:
if z >= 9.5:
FMT = '{:'+'{}'.format(1+k)+'.0e}'
else:
FMT = '{:'+'{}'.format(2+k)+'.0f}'
else:
FMT = '{:'+'{}'.format(2+N)+'.'+'{}'.format(N)+'e}'
return(FMT)

def Significant(x, *Error):
N = 0 if Error ==() else Sig_Digit(abs(Error[0]), 1)
m = 10**N
y = round(x*m)/m
return(y)

def Scientific(x, *N):
m = 10**Sig_Digit(x, *N)
y = round(x*m)/m
return(y)

def Scientific_Str(x, *N,):
FMT = Sci_Format(x, *N)
return(FMT.format(x))

def Significant_Str(x, *Error,):
FMT = Sig_Format(x, *Error)
return(FMT.format(x))
``````

test code:测试代码：

``````X = [19.03345607, 12.075, 360.108321344, 4325.007605343]
Error = [1.245, 0.1245, 0.0563, 0.01245, 0.001563, 0.0004603]
for x in X:
for error in Error:
print(x,'+/-',error, end='   \t==> ')
print(' (',Significant_Str(x, error), '+/-', Scientific_Str(error),')')

``````

print out:打印出：

``````19.03345607 +/- 1.245       ==>  ( 19 +/-  1 )

19.03345607 +/- 0.1245      ==>  ( 19.0 +/- 0.1 )

19.03345607 +/- 0.0563      ==>  ( 19.03 +/- 0.06 )

19.03345607 +/- 0.01245     ==>  ( 19.03 +/- 0.01 )

19.03345607 +/- 0.001563    ==>  ( 19.033 +/- 0.002 )

19.03345607 +/- 0.0004603       ==>  ( 19.0335 +/- 0.0005 )

12.075 +/- 1.245    ==>  ( 12 +/-  1 )

12.075 +/- 0.1245       ==>  ( 12.1 +/- 0.1 )

12.075 +/- 0.0563       ==>  ( 12.07 +/- 0.06 )

12.075 +/- 0.01245      ==>  ( 12.07 +/- 0.01 )

12.075 +/- 0.001563     ==>  ( 12.075 +/- 0.002 )

12.075 +/- 0.0004603    ==>  ( 12.0750 +/- 0.0005 )

360.108321344 +/- 1.245     ==>  ( 360 +/-  1 )

360.108321344 +/- 0.1245    ==>  ( 360.1 +/- 0.1 )

360.108321344 +/- 0.0563    ==>  ( 360.11 +/- 0.06 )

360.108321344 +/- 0.01245       ==>  ( 360.11 +/- 0.01 )

360.108321344 +/- 0.001563      ==>  ( 360.108 +/- 0.002 )

360.108321344 +/- 0.0004603     ==>  ( 360.1083 +/- 0.0005 )

4325.007605343 +/- 1.245    ==>  ( 4325 +/-  1 )

4325.007605343 +/- 0.1245       ==>  ( 4325.0 +/- 0.1 )

4325.007605343 +/- 0.0563       ==>  ( 4325.01 +/- 0.06 )

4325.007605343 +/- 0.01245      ==>  ( 4325.01 +/- 0.01 )

4325.007605343 +/- 0.001563     ==>  ( 4325.008 +/- 0.002 )

4325.007605343 +/- 0.0004603    ==>  ( 4325.0076 +/- 0.0005 )
``````