在python中舍入到有效数字

hmtdttj4  于 2022-12-21  发布在  Python
关注(0)|答案(6)|浏览(175)

我想像这样四舍五入:42949672 -〉42949700,2147483647 -〉2147480000,4252017622 -〉4252020000等等。
我试着用下面的,但是只对第一个有效。我怎样才能做一个更通用的呢?谢谢

round(42949672, -2)
d4so4syb

d4so4syb1#

可接受的答案有局限性,在一般情况下不会产生技术上正确的有效数字。
numpy.format_float_positional直接支持所需的行为。下面的代码段返回浮点数x,格式为4位有效数字,不使用科学记数法。

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

cnjp1d6j2#

为了扩展Autumn的答案,在一般情况下,可接受的答案失败的原因是round四舍五入到小数位,而不(必须)四舍五入到有效数字.
以下函数处理小数点前后都有有效数字的情况:

import math
def round_to_nsf(number, nsf=6):
    integer_part = math.floor(number)
    return round(number, nsf - len(str(integer_part)))

虽然它 * 没有 * 解决像0.0000012345678这样的数字的情况,四舍五入到6 s.f.应该是0.00000123457。
下面的代码 * 几乎 * 可以工作--但是效率非常低,由于使用递归而有堆栈溢出的风险,并且由于计算机使用二进制算术而不是十进制算术,因此并不总是返回正确的答案:

def round_to_nsf(number, nsf=6):
    integer_part = math.floor(number)
    if integer_part > 0:
        return round(number, nsf - len(str(integer_part)))
    else:
        return round_to_nsf(10 * number, nsf) / 10

但是我认为可以修改else子句,方法是将数字转换为字符串,在一个 * 单一 * 递归步骤中使用main函数,然后从字符串 * 构造 * 输出,以便获得一个非循环小数。

qlvxas9a

qlvxas9a3#

我假设您想四舍五入到6位有效数字。如果您想四舍五入int s,您可以使用

def round_sf(number, significant):
    return round(number, significant - len(str(number)))

print(round_sf(4252017622, 6))

结果:

4252020000
w8f9ii69

w8f9ii694#

要四舍五入到目标数字,只需将数字作为负数放入四舍五入函数,然后将其转换为整数。

digits = 4
num = 2147483647
rounded_num = int(round(num, -digits))

如果你想一直保持6位有效数字,这就是我在你的问题中看到的模式,你会想这样做:

def sf_round(num, sig_fig):
    return int(round(num, -(len(str(num))-sig_fig)))
bbuxkriu

bbuxkriu5#

扩展了@david-joy的函数。实际上,它在else子句中不能正常工作,而且实际上if子句中并没有涵盖所有的情况。下面是我的函数。

def round_to_nsf(value, nsf=2):
    """
    Rounds the number to the provided number of significant figures.
    """

    integer_part = math.floor(value)
    if integer_part > 0:
        integer_part_len = len(str(integer_part))
        return round(value, nsf-integer_part_len)
    else:
        str_value = str(value)
        #if of the form "8e-05"
        if '-' in str_value:
            index = int(str_value[str_value.find('-')+1:]) - 1
        else:
            st = {'1', '2', '3', '4', '5', '6', '7', '8', '9'}
            index = next((i for i, ch in enumerate(str(value)) if ch in st), None) - 2
        return round(value, index+nsf)
yduiuuwa

yduiuuwa6#

这些对我来说都是有效的,对于整型和浮点型,无论是正的还是负的,如果需要的话,可以通过对x应用isinstance()然后返回int()或float()来修改它们以保留原始的int或float类型。
请注意,超过14位数的格式可能会给予意外结果。

# Option 1: use math
import math
def rnd1(x, sigdig=14):
    """Round x to sigdig significant digits"""
    # n = digits to the left of decimal, can be negative
    n = math.floor(math.log10(abs(x))) + 1
    return round(x, sigdig - n)

# Option 2: use format which also rounds
def rnd2(x, sigdig=14):
    """Round x to sigdig significant digits"""
    f = f'{{:.{sigdig - 1}E}}'
    s = f.format(x)
    return float(s)

# Bonus: use format to truncate
def sig(x, sigdig=14):
    """Truncate x to sigdig significant digits"""
    f = f'{{:.{sigdig}E}}'
    s = f.format(x)
    decimal= 1
    minus = 1 if x < 0 else 0
    s = ''.join( (s[:sigdig + minus + decimal], s[s.index('E'):]) )
    return float(s)

# Unexpected format results with large number of significant digits
>>> '{:.20E}'.format(10**-1)
'1.00000000000000005551E-01'

>>> '{:.20E}'.format(10**-10)
'1.00000000000000003643E-10'

>>> '{:.20E}'.format(10**-20)
'9.99999999999999945153E-21'

>>> n = .123456789012345678901234567890
>>> '{:.20E}'.format(n)
'1.23456789012345677370E-01'

相关问题