У меня есть много финансовых данных, хранящихся как удвоения с плавающей запятой, и я пытаюсь найти наименее значащую цифру, чтобы преобразовать данные в целые числа с показателем степени.
Все данные конечны, например. 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"(.)\1{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)) вернет кортеж (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)
Я не думаю, что проблема четко определена, потому что может быть несколько чисел, которые заканчиваются одними и теми же удвоениями, поэтому информация уже потеряна. Финансовые данные никогда не должны храниться в формате с плавающей запятой.