#python #python-3.x #math
#python #python-3.x #математика
Вопрос:
У меня есть число с плавающей запятой 7.999999985666533
, которое ближе всего к 8, и я использовал его, используя math.isclose
math.isclose(a, b)
но для значений с плавающей запятой, таких как 1.5999999991220535
ближайшее целое число равно 2, но если я умножу его на 10 (10 ** 1)
, я получу 16 как ближайшее целое число, которое также является результатом на isclose
Другой пример:
1.2799999997163347
должно дать 128 после его умножения на 100 (10 ** 2)
Есть ли способ сделать это?
Комментарии:
1. Почему бы просто не
round
? Вероятно, есть несколько крайних случаев, кто-то более педантичный укажет вам на них.2. почему вы удивлены результатами?
round
(илиisclose
) и умножение на что-то просто не могут быть взаимозаменяемы (операции не коммутируют)… ах, ваш настоящий вопрос в названии, верно?3. @главный герой Хиро Да. Чтобы очистить 1.279999 при использовании round, даст 1, но isclose из 1 и 1.279999 будет иметь значение False
4. «ближайшее целое число», что вы подразумеваете под ближайшим, каков ваш допуск к ближайшему?
isclose
, допуск по умолчанию равен 1e-09, что гарантирует совпадение двух значений примерно с точностью до 9 десятичных разрядов5. Ваш вопрос мне непонятен. Что именно является входным сигналом? Это число с плавающей запятой и показатель степени 10, или это просто число с плавающей запятой? (В последнем случае подпрограмме нужно было бы найти соответствующую степень десяти.)
Ответ №1:
Непрерывные дроби довольно мощные. Может быть, здесь это небольшой перебор, но это работает.
import numpy as np
def get_cont_fraction(x, depth=0, maxdepth=10, precision=1e-6):
if depth > maxdepth:
out = []
else:
assert x >= 0
out=[]
if not depth:
out = [ int(x) ] get_cont_fraction( x - int( x ), depth=depth 1, maxdepth=maxdepth, precision=precision)
elif x < precision :
out=[]
else:
out = [ int(1./ x) ] get_cont_fraction(1. / x - int( 1. / x ), depth=depth 1, maxdepth=maxdepth, precision=precision)
return out
def get_fraction(inList):
num = inList[-1]
den = 1
testList = inList[:-1:]
testList = testList[::-1]
for a in testList:
num , den = a * num den, num
return ( num, den )
if __name__ == "__main__":
a = get_fraction( get_cont_fraction( 1.5999999991220535 ) )
print a
print a[0]*1./a[1]
a = get_fraction( get_cont_fraction( 1.2799999997163347 ) )
print a
print a[0]*1./a[1]
предоставление:
>> (8, 5)
>> 1.6
>> (32, 25)
>> 1.28
Комментарии:
1. Работает отлично, хотя замена
print(a[0] * 1. / a[1])
наprint(str(a[0] * 1. / a[1]).replace('.', ''))
дает результат, который я искал.2. @gc7__ ok.nice. но если вы хотите избежать манипулирования строками, вы могли бы использовать
print int( a[0] * 1. / a[1] * 10**( 1 int( np.log10( a[1] ) ) ) )
3. @gc7__ но если вы согласны со строковыми решениями, позвольте мне попробовать другое.
Ответ №2:
Поскольку решения, использующие строковые операции, кажутся приемлемыми, вот хороший короткий:
def nearest( x, Max9 = 2 ):
s = str(x).replace('.','')
splitter = Max9 * '9'
sOut = s.split( splitter )[0]
return int( sOut ) 1
a = 7.999999985666533
b = 1.5999999991220535
c = 1.2799999997163347
print nearest( a )
print nearest( b )
print nearest( c )
просто предоставление:
>> 8
>> 16
>> 128
Редактировать
Как правильно указано @gc7__ приведенное выше решение игнорирует случаи немного больших значений. Это немного усложняет код, но все еще вполне нормально.
import re
def nearest( x, Max09 = 2, digits=25 ):
s = ('{val:.{dig}f}'.format( dig=digits, val=x ) ).split('.')
rnd = 0
if len(s) < 2 or s[1] == '0':## input is integer xyz or float of type xyz.
out = int( x )
else:
s0, s9 = Max09*'0', Max09*'9'
splitter = '{}|{}'.format( s0, s9)
body = s[0]
p0, p9 = s[1].find(s0), s[1].find(s9) ### returns -1 if nothing is found
tail = re.split( splitter, s[1] )[0]
out = int( body tail )
if p9 > -1 and ( p9 < p0 or p0 < 0 ):
rnd = 1
return out rnd
a = 7.999998560066533
b = 1.5999999991220535
c = 1.2799999997163347
d = 1233
e = 19935
f = 1.6000000000123
g = 10006.6000000000123
h = 500001.0
print nearest( a )
print nearest( b )
print nearest( c )
print nearest( d )
print nearest( e )
print nearest( f )
print nearest( g )
print nearest( h )
предоставление:
>> 8
>> 16
>> 128
>> 1233
>> 19935
>> 16
>> 100066
>> 500001
Комментарии:
1. но обратите внимание: в этой версии
19935
это дало бы2
2. Также
1.6000000000123
будет16
другой угловой случай, но это можно сделать с помощью continuous0s
. Спасибо3. Обратите внимание, что при проверке
p9 < p0
вы можете использовать значение rnd, чтобы решить, следует ли разделять на0
s или9
s. Следовательно, импортre
может быть опущен.
Ответ №3:
math.isclose
сообщает вам, близки ли два floats
значения с учетом параметров rel_tol
и abs_tol
. настройки по умолчанию
rel_tol=1e-09, abs_tol=0.0
round
просто перейдет к следующему целому числу, которое может быть далеко за пределами этих допусков.
установка abs_tol
на что-то <0.5
сделает isclose
True
для чего-то, что вы использовали round
на:
from math import isclose
f = 1.5999999991220535
r = round(f)
print(r) # 2
print(isclose(f, r)) # False
print(isclose(f, r, abs_tol=0.5-0.00001)) # True