我在Python中有一个包含浮点数的变量(例如num = 24654.123
),我想确定数字的精度和比例值(在Oracle意义上),所以123.45678应该给我(8 ,5),12.76应该给我(4,2)等。
我第一次考虑使用字符串表示(通过str
或repr
),但那些大数字失败(虽然我现在明白浮点表示的局限性是这里的问题) :
>>> num = 1234567890.0987654321
>>> str(num) = 1234567890.1
>>> repr(num) = 1234567890.0987654
修改
下面的好点。我应该澄清一下。该数字已经是一个浮点数,并通过cx_Oracle被推送到数据库。我正在努力尽我所能在Python中处理对于相应数据库类型来说太大而不执行INSERT和处理Oracle错误的浮点数(因为我想处理数字一个字段,而不是记录,在一段时间)。我猜map(len, repr(num).split('.'))
是最接近浮点数的精度和比例的吗?
答案 0 :(得分:14)
获取小数点左侧的位数很容易:
int(log10(x))+1
由于浮点值固有的不准确性,小数点右边的位数比较棘手。我还需要几分钟的时间来确定那一个。
编辑:根据这一原则,这是完整的代码。
import math
def precision_and_scale(x):
max_digits = 14
int_part = int(abs(x))
magnitude = 1 if int_part == 0 else int(math.log10(int_part)) + 1
if magnitude >= max_digits:
return (magnitude, 0)
frac_part = abs(x) - int_part
multiplier = 10 ** (max_digits - magnitude)
frac_digits = multiplier + int(multiplier * frac_part + 0.5)
while frac_digits % 10 == 0:
frac_digits /= 10
scale = int(math.log10(frac_digits))
return (magnitude + scale, scale)
答案 1 :(得分:4)
浮点变量不可能。例如,输入
>>> 10.2345
给出:
10.234500000000001
因此,要获得6,4,您必须找到一种方法来区分输入10.2345
和10.234500000000001
的用户,这是不可能使用浮点数。这与存储浮点数的方式有关。使用decimal
。
import decimal
a = decimal.Decimal('10.234539048538495')
>>> str(a)
'10.234539048538495'
>>> (len(str(a))-1, len(str(a).split('.')[1]))
(17,15)
答案 2 :(得分:3)
我认为您应该考虑使用decimal类型而不是float
。 float
类型将给出舍入错误,因为数字在内部以二进制表示,但许多十进制数字没有精确的二进制表示。
答案 3 :(得分:3)
似乎str
是比repr
更好的选择:
>>> r=10.2345678
>>> r
10.234567800000001
>>> repr(r)
'10.234567800000001'
>>> str(r)
'10.2345678'
答案 4 :(得分:2)
(0)请确认或否认:您将获得使用浮点数,这是不可避免的,您无法将数据作为十进制数据,Oracle数据类型包括基于十进制的类型,并且这种基本不匹配是不可避免的。请解释任何完全或部分拒绝。
(1)你的“大数字失败”评论是误导/无关/错误 - 你说你的起点是浮点数,但是1234567890.0987654321不能表示为浮点数,如repr的结果所示()。
(2)也许你可以使用NEW repr(Python 2.7和3.1),它提供仍然满足float(repr(x)) == x
E.g。 old repr(1.1)生成“1.1000000000000001”,new repr(1.1)生成“1.1”
关于“我猜map(len,repr(num).split('。'))是我最接近浮点数的精度和比例?”:你需要一个策略来处理(a)负数和零数(b)数字如1.1e20
如果你需要使用Python 2.6或更早版本,挖掘Objects / floatobject.c应该为浮动对象的新repr()打开C代码。
(3)也许如果您告诉我们相关Oracle数据类型的规范,我们可以帮助您设计检查以选择哪个类型可以包含给定的浮点值。
答案 5 :(得分:1)
Basically, you can't with floating point numbers.使用十进制类型会有所帮助,如果你想要非常大的精度,可以考虑使用gmpy
,GNU Multiple Precision库的Python端口。
答案 6 :(得分:0)
我发现了另一个似乎更简单的解决方案,但是我不确定它是否适用于所有情况。
import math
x = 1.2345678
def flip(string):
result = ""
for ch in string:
result = ch + result
return result
prec = int(math.log10(float(flip(str(x)))) + 1 # precision as int
答案 7 :(得分:0)
如果需要检查精度,可以尝试:
def prec_check(a,b)
a = str(a)
b = str(b)
do = bool(True)
n = 0
while do == True:
if a and b and a[n] == a[b]:
n += 1
else:
do = false
return n
答案 8 :(得分:0)
如果您需要检查(a和b)的对应位数
def prec_check(a, b):
a = str(a)
b = str(b)
do = bool(True)
n = 0
while do == True:
if a and b and a[n] == a[b]:
n += 1
else:
do = false
return n
请注意,这不适用于“十进制”模块。