在 Python 中查找双精度数中的最低有效数字

Find least significant digit in a double in Python

我有很多存储为浮点双精度的财务数据,我试图找到最低有效数字,以便我可以将数据转换为带指数的整数。

所有数据都是有限的,例如1234.23 或 0.0001234 但因为它以双精度存储,所以它可以是 123.23000000001 或 0.00012339999999 等

有没有简单或正确的方法来解决这个问题,还是我只能搞砸它?

你有几个选择,

首先,最好使用标准库 Decimal,而不是内置 float

这修复了大多数与浮点数相关的错误,但没有修复臭名昭著的 0.1 + 0.2 = 0.3...4

from decimal import Demical

print(0.1 + 0.2)  # 0.30000000000000004
print(Decimal(0.1) + Decimal(0.2))  # 0.3000000000000000166533453694

如果不可能的话,另一个选择是设置小数点后重复位数的容差。

例如:

import re

repeated_digit_tolerance = 8  # Change to an appropriate value for your dataset
repeated_digit_pattern = re.compile(r"(.){2,}")

def longest_repeated_digit_re(s: str):
    match = repeated_digit_pattern.search(s)

    string = match.string
    span = match.span()
    substr_len = span[1] - span[0]

    return substr_len, string

def fix_rounding(num: float) -> float:
    num_str = str(num)
    pre_dp = num_str[:num_str.index(".")]
    post_dp = num_str[num_str.index(".") + 1:]

    repetition_length, string = longest_repeated_digit_re(post_dp)

    if repetition_length > repeated_digit_tolerance:
        shortened_string = string[:repeated_digit_tolerance-1]

    return float(".".join([pre_dp, shortened_string]))

print(0.1 + 0.2) # 0.30000000000000004
print(0.2 + 0.4) # 0.6000000000000001

print(fix_rounding(0.1 + 0.2))  # 0.3
print(fix_rounding(0.2 + 0.4))  # 0.6

它是完美运行的代码,但 Decimal 实际上总是两者中更好的选择,即使它不会 0.1 + 0.2 正确。

这是我使用字符串的拙劣做法。目前它可以满足我的需要,但我还没有完全测试它。

print (int_sci_notation(0.1+0.2)) 将 return 一个元组 (3,-1)

def int_sci_notation(decimal_value):
    #decimal value is finite value stored in double precision
    #convert to scientific string (cannot prevent E notation so force all numbers to E notation)
    tostr = format(decimal_value, ".14E")
    #get exponent from string
    if tostr[-3] == '-':
        exp = -int(tostr[-2:])
    else:
        exp = int(tostr[-2:])
    #get significant figures as an integer
    frac = tostr[1:-4].strip('0')
    sf = tostr[0]+frac[1:]
    #return the integer 'mantissa' and the exponent
    return int(sf), -int(len(sf)-1-exp)