在 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)
我有很多存储为浮点双精度的财务数据,我试图找到最低有效数字,以便我可以将数据转换为带指数的整数。
所有数据都是有限的,例如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)