当前位置: 首页 > 面试题库 >

Python和一般情况下的浮点相等

夏何平
2023-03-14
问题内容

我有一段代码的行为会有所不同,具体取决于我是通过字典获取转换因子还是直接使用它们。

以下代码将打印 1.0 == 1.0 -> False

但是,如果你更换factors[units_from]10.0,并factors[units_to ]1.0 / 2.54它将打印1.0 == 1.0 -> True

#!/usr/bin/env python

base = 'cm'
factors = {
    'cm'        : 1.0,
    'mm'        : 10.0,
    'm'         : 0.01,
    'km'        : 1.0e-5,
    'in'        : 1.0 / 2.54,
    'ft'        : 1.0 / 2.54 / 12.0,
    'yd'        : 1.0 / 2.54 / 12.0 / 3.0,
    'mile'      : 1.0 / 2.54 / 12.0 / 5280,
    'lightyear' : 1.0 / 2.54 / 12.0 / 5280 / 5.87849981e12,
}

# convert 25.4 mm to inches
val = 25.4
units_from = 'mm'
units_to = 'in'

base_value = val / factors[units_from]
ret = base_value * factors[units_to  ]
print ret, '==', 1.0, '->', ret == 1.0

首先让我说我很确定这里发生了什么。我以前在C中看到过它,但是在Python中却从未见过,但是自从Python在C中实现以来,我们已经看到了它。

我知道浮点数将更改从CPU寄存器到缓存以及返回的值。我知道比较两个相等的变量应该返回false,如果其中一个被调出页面,而另一个留在寄存器中。

问题

  • 避免此类问题的最佳方法是什么?…使用Python或一般而言。
  • 我做错什么了吗?

边注

这显然是精简示例的一部分,但是我想做的是带有长度,体积等类,它们可以与相同类但具有不同单位的其他html" target="_blank">对象进行比较。

修辞问题

  • 如果这是一个潜在的危险问题,因为它使程序的行为变得不确定,那么编译器在检测到您正在检查浮点是否相等时应发出警告或错误
  • 编译器是否应支持使用“足够接近”功能替换所有浮点相等性检查的选项?
  • 编译器已经做到了吗,我只是找不到信息。

问题答案:

感谢您的回复。大多数人都很好,并提供了良好的链接,所以我就这样说,回答我自己的问题。

Caspin发布了此链接。

他还提到Google Tests使用ULP比较,当我查看google代码时,我发现它们提到了与cygnus软件相同的确切链接。

我结束了在C中将某些算法实现为Python扩展,然后发现我也可以在纯Python中实现它。该代码发布在下面。

最后,我可能只会在我的技巧包中添加ULP差异。

有趣的是,在两个永远不会离开内存的相等数字之间应该有多少个浮点数。我读过的一篇文章或Google代码说4是个不错的数字…但是在这里我能达到10。

>>> f1 = 25.4
>>> f2 = f1
>>> 
>>> for i in xrange(1, 11):
...     f2 /= 10.0          # to cm
...     f2 *= (1.0 / 2.54)  # to in
...     f2 *= 25.4          # back to mm
...     print 'after %2d loops there are %2d doubles between them' % (i, dulpdiff(f1, f2))
... 
after  1 loops there are  1 doubles between them
after  2 loops there are  2 doubles between them
after  3 loops there are  3 doubles between them
after  4 loops there are  4 doubles between them
after  5 loops there are  6 doubles between them
after  6 loops there are  7 doubles between them
after  7 loops there are  8 doubles between them
after  8 loops there are 10 doubles between them
after  9 loops there are 10 doubles between them
after 10 loops there are 10 doubles between them

同样有趣的是,当其中一个作为字符串写出并读回时,相等的数字之间有多少个浮点。

>>> # 0 degrees Fahrenheit is -32 / 1.8 degrees Celsius
... f = -32 / 1.8
>>> s = str(f)
>>> s
'-17.7777777778'
>>> # floats between them...
... fulpdiff(f, float(s))
0
>>> # doubles between them...
... dulpdiff(f, float(s))
6255L
import struct
from functools import partial

# (c) 2010 Eric L. Frederich
#
# Python implementation of algorithms detailed here...
# from http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm

def c_mem_cast(x, f=None, t=None):
    '''
    do a c-style memory cast

    In Python...

    x = 12.34
    y = c_mem_cast(x, 'd', 'l')

    ... should be equivilent to the following in c...

    double x = 12.34;
    long   y = *(long*)&x;
    '''
    return struct.unpack(t, struct.pack(f, x))[0]

dbl_to_lng = partial(c_mem_cast, f='d', t='l')
lng_to_dbl = partial(c_mem_cast, f='l', t='d')
flt_to_int = partial(c_mem_cast, f='f', t='i')
int_to_flt = partial(c_mem_cast, f='i', t='f')

def ulp_diff_maker(converter, negative_zero):
    '''
    Getting the ulp difference of floats and doubles is similar.
    Only difference if the offset and converter.
    '''
    def the_diff(a, b):

        # Make a integer lexicographically ordered as a twos-complement int
        ai = converter(a)
        if ai < 0:
            ai = negative_zero - ai

        # Make b integer lexicographically ordered as a twos-complement int
        bi = converter(b)
        if bi < 0:
            bi = negative_zero - bi

        return abs(ai - bi)

    return the_diff

# double ULP difference
dulpdiff = ulp_diff_maker(dbl_to_lng, 0x8000000000000000)
# float  ULP difference
fulpdiff = ulp_diff_maker(flt_to_int, 0x80000000        )

# default to double ULP difference
ulpdiff = dulpdiff
ulpdiff.__doc__ = '''
Get the number of doubles between two doubles.
'''


 类似资料:
  • 在javaFx中,对于每个带有FXID的控件,我们可以在每个生成的控制器类的initialize方法中看到以下语句。 我可以理解,该语句是为了确保在加载这个fxml时,带有这个fx:id的控件出现在fxml布局文件中,如果该控件不存在,它将抛出异常并退出fxml加载过程。 null

  • 本文向大家介绍请问运行时的异常与一般情况下出现的异常有什么相同点和不同点?相关面试题,主要包含被问及请问运行时的异常与一般情况下出现的异常有什么相同点和不同点?时的应答技巧和注意事项,需要的朋友参考一下 考察点:异常 异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求

  • 问题内容: 有时,当我看到自己的日志记录代码时,我想知道自己是否做对了。可能没有确切的答案,但是我有以下担忧: 图书馆课 我有几个库类可能记录一些消息。致命错误被报告为例外。当前,我的类中有一个静态记录器实例,其类名称为记录名称。(Log4j的:) 这是正确的方法吗?也许该库类的用户不需要我的实现中的任何消息,或者想要将它们重定向到应用程序特定的日志。我是否应该允许用户从“外部世界”设置记录器?您

  • 众所周知,在比较浮点值时必须小心。通常,我们不使用,而是使用一些基于epsilon或ULP的相等性测试。 然而,我想知道,当使用时,是否存在任何情况? 看看这个简单的片段,哪些案例可以保证成功? 注意:我已经检查了这个和这个,但是它们不包括我的(所有)病例。 注2:似乎我必须添加一些附加信息,因此答案在实践中可能很有用:我想知道: C标准的内容 这是我在当前标准草案中发现的唯一相关声明: 浮点类型

  • 问题内容: 在我目前的工作中,我经常使用Numpy和列表理解,并且为了获得最佳性能,我有以下问题: 如果我按如下方式创建一个Numpy数组,在幕后实际上会发生什么?: 我的猜测是python首先创建一个包含值的普通列表,然后使用列表大小分配一个numpy数组,然后将值复制到此新数组中。这是正确的,还是解释器足够聪明,可以意识到列表只是中间的,而是直接复制值? 同样,如果我希望使用numpy.fro

  • Hi StackOverFlow成员 reports=表名。 数据库 这是数据库表: 我想 当我运行这段代码时.. 它返回AllTotal