确定Python中特定数字的精度和比例

确定Python中特定数字的精度和比例,python,string,floating-point,scale,precision,Python,String,Floating Point,Scale,Precision,我在Python中有一个包含浮点数的变量(例如,num=24654.123),我想确定这个数字的精度和刻度值(在Oracle意义上),所以123.45678应该给我(8,5),12.76应该给我(4,2),等等 我最初考虑使用字符串表示法(通过str或repr),但对于大数来说,这些表示法是失败的(尽管我现在明白了,这里的问题是浮点表示法的局限性): 编辑: 下面是好的观点。我应该澄清一下。该数字已经是一个浮点数,正在通过cx_Oracle推送到数据库中。在Python中,除了执行INSERT和

我在Python中有一个包含浮点数的变量(例如,
num=24654.123
),我想确定这个数字的精度和刻度值(在Oracle意义上),所以123.45678应该给我(8,5),12.76应该给我(4,2),等等

我最初考虑使用字符串表示法(通过
str
repr
),但对于大数来说,这些表示法是失败的(尽管我现在明白了,这里的问题是浮点表示法的局限性):

编辑:


下面是好的观点。我应该澄清一下。该数字已经是一个浮点数,正在通过cx_Oracle推送到数据库中。在Python中,除了执行INSERT和处理Oracle错误之外,我正在尽力处理对于相应数据库类型来说太大的浮动(因为我希望一次处理字段中的数字,而不是记录)。我猜<>代码> map(LeN,RePR(num).Seal'('.'))是我最接近浮点的精度和规模的地方。

< P>我认为你应该考虑使用类型而不是<代码>浮点。“代码>浮点< /代码>类型将给出舍入错误,因为数字是用二进制表示的,但许多十进制数没有精确的二进制表示形式。

使用十进制类型将有帮助,如果您想要很大的精度,请考虑使用,GNU多精度库到Python的端口。

获取小数点左侧的位数很容易:

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)
(0)请确认或拒绝:您被赋予了可使用的浮动,这是不可避免的,您无法将数据作为十进制数据获取,Oracle数据类型包括基于十进制的类型,并且这种基本不匹配是不可避免的。请解释任何完全或部分否认

(1) 您的“大数失败”评论具有误导性/不相关/错误——您说您的起点是一个浮点,但1234567890.0987654321不能表示为浮点,如repr()的结果所示

(2) 也许您可以使用新的repr(python2.7和3.1),它提供了repr(x)的最小可能精度,仍然满足
float(repr(x))==x

例如,旧repr(1.1)产生“1.10000000000001”,新repr(1.1)产生“1.1”

关于“我想map(len,repr(num).split('.')是最接近浮点的精度和比例?”:您需要一种策略来处理(a)负数和零数(b)像
1.1e20

如果需要使用Python2.6或更早版本,则在Objects/floatobject.c中挖掘应该为float对象的新repr()打开c代码


(3) 如果您告诉我们相关Oracle数据类型的规格,我们可能会帮助您设计检查,以选择哪种类型可以包含给定的浮点值。

浮点变量不可能。例如,打字

>>> 10.2345
给出:

10.234500000000001
因此,要从中获得6,4,您必须找到一种方法来区分用户输入的
10.2345
10.23450000000001
,这是不可能使用浮动的。这与浮点数的存储方式有关。使用
十进制

import decimal
a = decimal.Decimal('10.234539048538495')
>>> str(a)
'10.234539048538495'
>>>  (len(str(a))-1, len(str(a).split('.')[1]))
(17,15)

似乎
str
是比
repr
更好的选择:

>>> r=10.2345678
>>> r
10.234567800000001
>>> repr(r)
'10.234567800000001'
>>> str(r)
'10.2345678'

我找到了另一个似乎更简单的解决方案,但我不确定它是否适用于所有情况

   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

如果需要检查精度,可以尝试:

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

如果需要检查(a和b的)相应位数


请注意,这不适用于“十进制”模块。

适用于浮点数;看看我的答案,我的答案也行。关键是将位数限制在已知的浮点类型精度范围内,并对结果进行四舍五入。0。基本上是肯定的。一切都设置为使用浮点,我不相信cx_Oracle会处理十进制类型,至少我已经设置好了。1.编辑以更正。2.有趣,不幸的是我落后于2.7。3.我正在尝试编写动态工作的代码,即使Oracle列类型在精度或规模上发生变化。(哎哟,抱歉格式不好)出于好奇,14号是从哪里来的?它是否独立于平台?它依赖于平台,但大多数平台将使用IEEE-754。我可能会把它改为15,但我想保守一点,确保我的舍入工作正常。如果没有14个硬编码,是否可以从Python发行版获得?@aaragon可能,我不知道。因为我知道的每一个Python版本都是基于IEEE-754的,所以我没有动力去寻找.Lambda函数,它用于查找小数点右边的位数
Lambda x:len(str(x).split('.')[-1]),如果len(str(x).split('.')>1,如果我们想为100.0输入Lambda x:len返回0(str(x).split('.)[-1]),如果int(x)1其他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
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