如何可靠地将数字中的小数部分和浮动部分分开?

问题描述 投票:0回答:5

这不是this的重复,我将在这里解释。

考虑

x = 1.2
。我想把它分成
1
0.2
。我已经尝试了链接问题中概述的所有这些方法:

In [370]: x = 1.2

In [371]: divmod(x, 1)
Out[371]: (1.0, 0.19999999999999996)

In [372]: math.modf(x)
Out[372]: (0.19999999999999996, 1.0)

In [373]: x - int(x)
Out[373]: 0.19999999999999996

In [374]: x - int(str(x).split('.')[0])
Out[374]: 0.19999999999999996

我尝试的任何事情都没有给我带来确切的

1
0.2

有没有什么方法可以可靠地将浮点数转换为其十进制和浮点等值,并且不受浮点表示形式限制的阻碍?

我知道这可能是由于号码本身存储方式的限制,因此我愿意接受任何克服此问题的建议(例如软件包或其他方式)。

编辑:更喜欢一种不涉及字符串操作的方法,如果可能的话

python floating-point ieee-754 python-internals
5个回答
7
投票

解决方案

这可能看起来像一个黑客,但你可以分离字符串形式(实际上是repr)并将其转换回整数和浮点数:

In [1]: x = 1.2

In [2]: s = repr(x)

In [3]: p, q = s.split('.')

In [4]: int(p)
Out[4]: 1

In [5]: float('.' + q)
Out[5]: 0.2

如何运作

以这种方式处理它的原因是用于显示 1.2

内部算法
非常复杂(David Gay 算法的快速变体)。它努力展示无法精确表示的数字的最短可能表示形式。通过拆分 repr 形式,您可以利用该算法。

在内部,输入为

1.2
的值存储为二进制分数
5404319552844595 / 4503599627370496
,实际上等于
1.1999999999999999555910790149937383830547332763671875
。 Gay 算法用于将其显示为字符串
1.2
。然后,split 可靠地提取整数部分。

In [6]: from decimal import Decimal

In [7]: Decimal(1.2)
Out[7]: Decimal('1.1999999999999999555910790149937383830547332763671875')

In [8]: (1.2).as_integer_ratio()
Out[8]: (5404319552844595, 4503599627370496)

原理与问题分析

如上所述,您的问题大致可以翻译为“我想按照视觉上显示的方式拆分数字的整数部分和小数部分,而不是根据实际存储方式来拆分”。

以这种方式构建,很明显解决方案涉及解析它的视觉显示方式。虽然它感觉像是黑客攻击,但这是利用非常复杂的显示算法并实际匹配您所看到的内容的最直接方法。

这种方式可能是匹配您所看到内容的唯一可靠方式,除非您手动重现内部显示算法。

替代方案的失败

如果您想留在整数领域,您可以尝试舍入和减法,但这会给您的浮点部分带来意想不到的值:

In [9]: round(x)
Out[9]: 1.0

In [10]: x - round(x)
Out[10]: 0.19999999999999996

1
投票

这是一个无需字符串操作的解决方案(

frac_digits
是小数位数,您可以保证数字的小数部分适合):

>>> def integer_and_fraction(x, frac_digits=3):
...     i = int(x)
...     c = 10**frac_digits
...     f = round(x*c-i*c)/c
...     return (i, f)
... 
>>> integer_and_fraction(1.2)
(1, 0.2)
>>> integer_and_fraction(1.2, 1)
(1, 0.2)
>>> integer_and_fraction(1.2, 2)
(1, 0.2)
>>> integer_and_fraction(1.2, 5)
(1, 0.2)
>>> 

0
投票

您可以尝试将 1.2 转换为字符串,并在“.”上拆分然后将两个字符串(“1”和“2”)转换回您想要的格式。

另外用“0”填充第二部分。会给你一个很好的格式。


0
投票

所以我只是在 python 终端中执行了以下操作,它似乎工作正常......

x=1.2
s=str(x).split('.')
i=int(s[0])
d=int(s[1])/10

0
投票

你不能只减去整数吗?

number = float(input("Please type in a number: "))
integer = int(number)
decimal = number - integer
print("Integer part: ",integer)
print("Decimal part: ",decimal)
© www.soinside.com 2019 - 2024. All rights reserved.