在 Python 中确定特定数字的精度和小数位数
问题描述
我在 Python 中有一个包含浮点数的变量(例如 num = 24654.123
),我想确定数字的精度和比例值(在 Oracle 意义上),所以 123.45678应该给我 (8,5),12.76 应该给我 (4,2),等等.
I have a variable in Python containing a floating point number (e.g. num = 24654.123
), and I'd like to determine the number's precision and scale values (in the Oracle sense), so 123.45678 should give me (8,5), 12.76 should give me (4,2), etc.
我首先考虑使用字符串表示(通过 str
或 repr
),但是对于大数来说这些都失败了(虽然我现在明白这是浮点的限制表示这是这里的问题):
I was first thinking about using the string representation (via str
or repr
), but those fail for large numbers (although I understand now it's the limitations of floating point representation that's the issue here):
>>> num = 1234567890.0987654321
>>> str(num) = 1234567890.1
>>> repr(num) = 1234567890.0987654
下面的好点.我应该澄清一下.该数字已经是一个浮点数,并且正在通过 cx_Oracle 推送到数据库.我试图在 Python 中尽我所能来处理对于相应数据库类型来说太大的浮点数,而不是执行 INSERT 和处理 Oracle 错误(因为我想处理字段中的数字,而不是记录,在一次).我猜 map(len, repr(num).split('.'))
是最接近浮点数的精度和比例的?
Good points below. I should clarify. The number is already a float and is being pushed to a database via cx_Oracle. I'm trying to do the best I can in Python to handle floats that are too large for the corresponding database type short of executing the INSERT and handling Oracle errors (because I want to deal with the numbers a field, not a record, at a time). I guess map(len, repr(num).split('.'))
is the closest I'll get to the precision and scale of the float?
解决方案
获取小数点左边的位数很简单:
Getting the number of digits to the left of the decimal point is easy:
int(log10(x))+1
小数点右边的位数比较棘手,因为浮点值固有的不准确性.我还需要几分钟才能弄清楚这一点.
The number of digits to the right of the decimal point is trickier, because of the inherent inaccuracy of floating point values. I'll need a few more minutes to figure that one out.
基于这个原则,这里是完整的代码.
Based on that principle, here's the complete code.
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)
相关文章