Python请不要弄乱我的号码

时间:2017-09-01 18:04:30

标签: python json floating-point precision

我正在python中编写一个下载REST数据的测试工具,通过json.loads()返回返回值,然后将DB返回的值与预期值进行比较。不幸的是,尝试打印出该值或比较该值失败。尽管JSON / Rest数据的漂亮打印是正确的并且具有完整的价值。所以像下面的例子一样简单,打印精度较低

示例:

print 1.414213562373095
1.41421356237

请注意精度降低。运行相同的比较也不起作用。在这两种情况下,我都将值强制转换为字符串,因为比较两个数字(例如1.13337和1.133333333333337)的比较是相同的数字。虽然技术上正确,但我们希望确保DB的输出符合承诺的精度。我会很感激任何解决方案。提前谢谢。

4 个答案:

答案 0 :(得分:2)

首先,你实际上并没有失去你认为自己在你的榜样中的精确度。 print只是比你在Python 2上预期的更严重地截断。比较应该在这个数字上正常工作,只要你不会在其他地方失去更多精度。

如果您有实际的精度限制问题 - 例如,带有20位数字的JSON - 您可以解决这个问题。 json.loads默认将数字解析为float s,浮点数的精度有限。如果您不想这样,请更改json.loads解析数字的方式:

>>> import json
>>> x = '{"a": 1.2345678901234567890}'
>>> json.loads(x, parse_float=str, parse_int=str, parse_constant=str)
{u'a': '1.2345678901234567890'}
>>> from decimal import Decimal
>>> json.loads(x, parse_float=Decimal, parse_int=Decimal, parse_constant=Decimal)
{u'a': Decimal('1.2345678901234567890')}

答案 1 :(得分:0)

我会像user2357112建议的那样做。 没有足够的信息来准确说明您与数据库进行比较的过程,但为了将来参考,您可以使用以下格式:

<div style="height: 150px; border: 1px solid red;box-sizing:border-box">
  <span class="fixIssue" style="display:flex; justify-content:flex-start;flex-wrap:nowrap;height:100px; border:1px dotted green;">
    <span style="flex:0 0 auto; margin-right:10px;">      
      <span class="imgSpan">
      	<img src="https://dummyimage.com/68x68/d612e8/" class="thumbnail" />
      </span>
    </span>
    <span style="flex:0 1 auto; margin-right:10px; overflow: hidden">
      <span class="textSpanInner">
        <a href="" class="linkStyle">Big Name HereBig Name HereBig Name HereBig Name Here</a>
      </span>
    </span>
  </span>
</div>

编辑:看起来Zinki打败了我。

答案 2 :(得分:0)

Python(以及许多其他编程语言)本质上存在将十进制数表示为浮点数和浮点算术(包括比较浮点数)的问题。有关原因的详细说明,请参阅这些页面:Floating Point Arithmetic: Issues and LimitationsWhat Every Computer Scientist Should Know About Floating Point Arithmetic

如果在Python中需要高级别的精度,使用Decimal类可以提供帮助。从Python文档:“十进制模块提供对快速正确舍入的十进制浮点运算的支持”。有关详细信息,请参阅Decimal fixed point and floating point arithmetic

以下是一个示例(来自Python文档),显示了用户可更改的精度级别:

>>> from decimal import *
>>> getcontext().prec = 6
>>> Decimal(1) / Decimal(7)
Decimal('0.142857')
>>> getcontext().prec = 28
>>> Decimal(1) / Decimal(7)
Decimal('0.1428571428571428571428571429')

编辑: 根据评论中的讨论,我正在进一步研究浮点比较,如果您希望与特定精度进行比较,则可以在Python中使用math.isclose。有关详细信息,请参阅What is the best way to compare floats for almost-equality in Python?。 有关浮点比较的分析,请参阅:Comparing Floating Point Numbers

答案 3 :(得分:0)

这是完整的编码答案,可以正确打印任意大的十进制数。不幸的是,您必须使用DecimalEncoder类将值作为字符串返回。当我独自运行这个代码时,我得到了我想要的东西。 (记住这是用于测试,我想确保python不会以某种方式改变值)。因此,当我从数据库中获取值时,我可以正确地比较值,而无需python舍入或剪切值。

在我的测试环境中,由于某种原因,此解决方案将最后一位数字舍入但不再剪切为11位精度。交换json.loads调用将显示原始问题。

不幸的是,这会将数据类型更改为字符串,我仍然需要弄清楚为什么我的代码将比较值进行舍入,但我可以在周末看出来:)。谢谢大家的帮助!!

import json
import decimal  # use decimal to tell python to leave my numbers alone

class DecimalEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, decimal.Decimal):
            return str(o)
        return super(DecimalEncoder, self).default(o)

class JSONUtils:
    def __init__( self, response ):
        self.response = response
        self.jsonData = None
        self.LoadData( )

        print 'jsonData: ' + json.dumps( self.jsonData, cls=DecimalEncoder, indent=2 )

    def LoadData ( self ):
        if ( self.jsonData == None ):
            if ( type( self.response ) == str or type( self.response ) == unicode ):
#               self.jsonData = json.loads(self.response )
                self.jsonData = json.loads(self.response, parse_float=decimal.Decimal )

    def GetJSONChunk( self, path ):
        returnValue = ''
        curPath     = ''
        try:
            if ( type( path ) == str ):
                returnValue = self.jsonData[path]
            elif (type( path ) == list):
                temp = ''
                firstTime = True
                for curPath in path:
                    if firstTime == True:
                        temp = self.jsonData[curPath]
                        firstTime = False
                    else:
                        temp = temp[curPath]
                returnValue = temp
            else:
                print 'Unknown type in GetJSONChunk: ' + unicode( type( path ))
        except KeyError as err:
            ti.DBG_OUT( 'JSON chunk doesn\'t have value: ' + unicode( path ))
            returnValue = self.kNoNode
        except IndexError as err:
            ti.DBG_OUT( 'Index does not exist: ' + unicode( curPath ))
            returnValue = self.kInvalidIndex

        return returnValue

myJSON = JSONUtils( '{ "fldName":4.9497474683058327445566778899001122334455667788990011 }' )
value =  str( myJSON.GetJSONChunk ( 'fldName' ))
print str( type( value ))
print value

输出:

<type 'str'>
4.9497474683058327445566778899001122334455667788990011