栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

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

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

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

解决方案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.01.4210854715202004e-14>>> ulp(100.0)1.4210854715202004e-14

解决方案2:使用NumPy

如果您没有Python
3.9或更高版本,但是可以访问NumPy,则可以使用

numpy.nextafter
。对于常规Python
float
,其语义与匹配
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或更高版本,则可以使用
ctypes
cffi
动态调用C
nextafter
,也可以编写一个简单的Cython包装器或公开C的Python
C扩展
nextafter

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

如果您愿意(在实践中几乎总是安全的)假设Python正在使用IEEE
754浮点,那么编写提供的Python函数非常容易

nextafter
。需要一些注意才能使所有极端情况正确。

IEEE 754二进制浮点格式经过精心设计,因此从一个浮点数到“下一个”数的转换就像递增位表示一样简单。它适用于范围内的任何数字

[0,infinity)
,可以跨越指数边界和次法线。要生成
nextUp
覆盖整个浮点范围的版本,您还需要处理负数,无穷大,nan和涉及负零的一种特殊情况。以下是
nextUp
Python中IEEE
754功能的标准兼容版本。它涵盖了所有极端情况。

import mathimport structdef 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]

的实施

nextDown
nextAfter
再这个样子。(请注意,这
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格式和语义,则有一个非常简单的解决方案:下一个从
x
is向上浮动
x / (1 - 2**-53)
,下一个从
x
is向下浮动
x *(1 - 2**-53)

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

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

然后,该数量

1 - 2**-53
可以精确地表示为a
float
,并且给定非正态Python浮点正
x
x / (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>>> d0.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]
,因此足以保证最接近的浮点数
z
nextafter(x,inf)
。证明
x * d
相似。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/669047.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号