如何获得浮点序列中的下一个值?

如何解决如何获得浮点序列中的下一个值?

这里有五个(实际上是四个半)解决方案。

解决方案1:使用Python 3.9或更高版本

2020年10月发布的Python 3.9包括一个新的标准库函数math.nextafter,该函数直接提供此功能:用于math.nextafter(x, math.inf)将下一个浮点数向正无穷大。例如:

>>> from math import nextafter, inf
>>> nextafter(100.0, inf)
100.00000000000001

如果查看方法提供的十六进制表示,则可以更容易地验证此函数是否确实 产生下一个浮点数float.hex

>>> 100.0.hex()
'0x1.9000000000000p+6'
>>> nextafter(100.0, inf).hex()
'0x1.9000000000001p+6'

Python 3.9还引入了一个密切相关且经常有用的伴随函数math.ulp,该函数给出一个值与下一个远离零的值之间的差:

>>> from math import ulp
>>> nextafter(100.0, inf) - 100.0
1.4210854715202004e-14
>>> ulp(100.0)
1.4210854715202004e-14

解决方案2:使用NumPy

如果您没有Python 3.9或更高版本,但是可以访问NumPy,则可以使用numpy.nextafter。对于常规Pythonfloat,其语义与匹配math.nextafter(尽管说Python的语义与NumPy的语义匹配会更公平,因为NumPy在Python之前很早就 可以使用此功能)。

>>> from numpy import nextafter, inf
>>> nextafter(100.0, inf)
100.00000000000001

解决方案3:nextafter自己包装C

C在中指定nextafter功能math.h(例如,参见C99的7.12.11.3节);这正是Python> = 3.9包装并在其math模块中公开的函数。如果您没有Python 3.9或更高版本,则可以使用ctypescffi动态调用Cnextafter,也可以编写一个简单的Cython包装器或公开C的Python C扩展nextafter

解决方案4:通过struct模块进行位操作

如果您愿意(在实践中几乎总是安全的)假设Python正在使用IEEE 754浮点,那么编写提供的Python函数非常容易nextafter。需要一些注意才能使所有极端情况正确。

IEEE 754二进制浮点格式经过精心设计,因此从一个浮点数到“下一个”数的转换就像递增位表示一样简单。它适用于范围内的任何数字[0, infinity),可以跨越指数边界和次法线。要生成nextUp覆盖整个浮点范围的版本,您还需要处理负数,无穷大,nan和涉及负零的一种特殊情况。以下是nextUpPython中IEEE 754功能的标准兼容版本。它涵盖了所有极端情况。

import math
import struct

def nextup(x):
    # NaNs and positive infinity map to themselves.
    if math.isnan(x) or (math.isinf(x) and x > 0):
        return x

    # 0.0 and -0.0 both map to the smallest +ve float.
    if x == 0.0:
        x = 0.0

    n = struct.unpack('<q', struct.pack('<d', x))[0]
    if n >= 0:
        n += 1
    else:
        n -= 1
    return struct.unpack('<d', struct.pack('<q', n))[0]

的实施nextDownnextAfter再这个样子。(请注意,这nextAfter不是IEEE 754所指定的函数,因此对于IEEE特殊值应该发生的情况有一些猜测。在这里,我遵循Python的decimal.Decimal类所基于的IBM Decimal Arithmetic标准。)

def nextdown(x):
    return -nextup(-x)

def nextafter(x, y):
    # If either argument is a NaN, return that argument.
    # This matches the implementation in decimal.Decimal
    if math.isnan(x):
        return x
    if math.isnan(y):
        return y

    if y == x:
        return y
    elif y > x:
        return nextup(x)
    else:
        return nextdown(x)

(部分)解决方案5:浮点运算

如果x是肯定的但不太float愿意,并且您愿意假设IEEE 754 binary64格式和语义,则有一个非常简单的解决方案:下一个从xis向上浮动x / (1 - 2**-53),下一个从xis向下浮动x * (1 - 2**-53)

更详细地,假设满足以下所有条件:

  • 您无需担心IEEE 754极端情况(零,无穷大,次法线,nans)
  • 您不仅可以假定IEEE 754 binary64浮点 格式 ,还可以假定IEEE 754 binary64 语义 :即,所有基本算术运算均已根据当前舍入模式正确舍入。
  • 您可以进一步假设当前的舍入模式为IEEE 754默认的“舍入为偶数”模式。

然后,该数量1 - 2**-53可以精确地表示为a float,并且给定非正态Python浮点正xx / (1 - 2**-53)将会匹配nextafter(x, inf)。类似地,x * (1 - 2**-53)将匹配nextafter(x, -inf),除了在x最小正法向值的拐角情况下2**-1022

使用此方法时要注意一件事:表达式2**-53将从pow系统的数学库中调用您,通常期望pow正确取整并不安全。有许多更安全的方法可以计算此常数,其中一种是使用float.fromhex。这是一个例子:

>>> d = float.fromhex('0x1.fffffffffffffp-1')  # 1 - 2**-53, safely
>>> d
0.9999999999999999
>>> x = 100.0
>>> x / d  # nextup(x), or nextafter(x, inf)
100.00000000000001
>>> x * d  # nextdown(x), or nextafter(x, -inf)
99.99999999999999

这些技巧可在浮点数的正常范围内正常工作,包括在尴尬的情况下,例如精确的2的幂。

对于证据的草图:表明x / d比赛nextafter(x, inf)正正常的x,我们可以通过两个动力,而不会影响正确性规模,因此在证明,我们可以不失一般性该损失承担0.5 <= x < 1.0。如果我们写z精确 的数学值x / d(认为是实数,而不是一个浮点数),则z - x等于x * 2**-53 / (1 - 2**-53)。结合不等式0.5 <= x <= 1 - 2**-53,我们可以得出结论2**-54 < z - x <= 2**-53,由于浮点数在间隔中正好2**-53间隔开[0.5, 1.0],因此足以保证最接近的浮点数znextafter(x, inf)。证明x * d相似。

解决方法

Python是否提供了获取浮点值的功能,该函数是通过将现有浮点值的最低有效位递增而得到的?

我正在寻找类似于std::nextafterC
++ 11中添加的功能的东西。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?