在Python中确定特定数字的精度和小数位数
我在 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('.'))
是我能得到的最接近浮点数的精度和规模的?
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.
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
Edit:
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
似乎
str
比repr
(Python 2) 更好:seems like
str
is better choice thanrepr
(Python 2):我认为你应该考虑使用 decimal 类型而不是
float.
float
类型会产生舍入错误,因为数字在内部以二进制表示,但许多十进制数字没有精确的二进制表示形式。I think you should consider using the decimal type instead of a
float
. Thefloat
type will give rounding errors because the numbers are represented internally in binary but many decimal numbers don't have an exact binary representation.基本上,你不能使用浮点数。 使用十进制类型会有所帮助,并且如果您想要非常高的精度,请考虑使用
gmpy
, GNU 多精度库移植到 Python。Basically, you can't with floating point numbers. Using the decimal type would help and if you want really large precision, consider using
gmpy
, the GNU Multiple Precision library's port to Python.(0) 请确认或否认:您可以使用浮点数,这是不可避免的,您无法获取十进制数据,Oracle 数据类型包括基于十进制的类型,这种基本的不匹配是不可避免的。请解释全部或部分否认的情况。
(1)你的“fail for large number”评论是误导性的/不相关的/错误的——你说你的起点是一个浮点数,但是 1234567890.0987654321 不能表示为浮点数,如 repr() 的结果所示。
(2) 也许你可以使用新的 repr (Python 2.7 和 3.1),它提供了 repr(x) 的最小可能精度,但仍然满足
float(repr(x)) == x
例如旧的 repr (1.1) 产生“1.1000000000000001”,new repr(1.1) 产生“1.1”
关于“我猜map(len, repr(num).split('.')) 是我能得到的最接近的精度和规模浮点数?”:你需要一个策略来处理 (a) 负数和零数 (b) 像
1.1e20
这样的数字深入 Objects/floatobject.c 应该会找到新 repr 的 C 代码( ) 的 float 对象,如果您需要使用 Python 2.6 或更早版本。
(3) 也许如果您告诉我们相关 Oracle 数据类型的规范,我们可以帮助您设计检查以选择哪种类型可以包含给定的浮点值。
(0) Please confirm or deny: You are given floats to use, this is unavoidable, you can't get your data as decimal, the Oracle datatypes include decimal-based types, and this fundamental mismatch is unavoidable. Please explain any full or partial denial.
(1) Your "fail for large numbers" remark is misleading/irrelevant/wrong -- you say that your starting point is a float, but 1234567890.0987654321 can't be represented as a float, as shown by the result of repr().
(2) Perhaps you could use the NEW repr (Python 2.7 and 3.1) which provides the minimum possible precision of repr(x) that still satisfies
float(repr(x)) == x
E.g. old repr(1.1) produces "1.1000000000000001", new repr(1.1) produces "1.1"
About "I guess map(len, repr(num).split('.')) is the closest I'll get to the precision and scale of the float?": You need a strategy to handle (a) negative and zero numbers (b) numbers like
1.1e20
Digging in Objects/floatobject.c should turn up the C code for the new repr() of a float object, should you need to use Python 2.6 or earlier.
(3) Perhaps if you told us the specs for the relevant Oracle data types, we could help you devise checks for choosing which type can contain a given float value.
逗号后有多个符号。适用于
int
、float
和Decimal
类型。A number of symbols after comma. Works with
int
,float
andDecimal
types.此答案仅返回小数点后的位数。它不能保证准确,因为浮点数学可以创建 0.99999 或 0.00001。
This answer returns only the number of digits after the decimal place. It will not be guaranteed as accurate because floating point math can create .99999 or .00001 for example.
我找到了另一个似乎更简单的解决方案,但我不确定它是否适用于所有情况。
I found another solution that seems to be simpler, but I'm not sure exactly if it will work for all cases.
如果您需要检查(a和b)对应的位数,
请注意,这不适用于“十进制”模块。
If you need to check the number of corresponding digits (of a and b)
Note that this doesn't work with the "Decimal" module.
如果您需要检查精度,您可以尝试:
If you need to check precision, you can try:
这是另一种
Decimal
方法,至少适用于某些用例。它是否总是有效取决于您正在寻找的。Here's another
Decimal
approach that will work for at least some use cases. Whether it will always work depends on exactly what you're looking for.获取小数点左边的位数很容易:
由于浮点值固有的不准确性,小数点右边的位数则比较棘手。我还需要几分钟才能弄清楚这一点。
编辑:基于该原则,以下是完整的代码。
Getting the number of digits to the left of the decimal point is easy:
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.
Edit: Based on that principle, here's the complete code.
浮点变量不可能。例如,输入
如下:
因此,要从中得到 6,4,您必须找到一种方法来区分输入
10.2345
和10.234500000000001
的用户,即不可能使用浮动。这与浮点数的存储方式有关。使用十进制
。Not possible with floating point variables. For example, typing
gives:
So, to get 6,4 out of this, you will have to find a way to distinguish between a user entering
10.2345
and10.234500000000001
, which is impossible using floats. This has to do with the way floating point numbers are stored. Usedecimal
.