查找具有相同内部表示的浮点数/双精度数的最小值/最大值
Posted
技术标签:
【中文标题】查找具有相同内部表示的浮点数/双精度数的最小值/最大值【英文标题】:Find min/max of a float/double that has the same internal representation 【发布时间】:2009-11-03 15:48:31 【问题描述】:刷新floating points(也称为PDF)、IEEE-754 并参与in this discussion on floating point rounding when converting to strings,让我想到了修补:如何获得二进制表示相等的给定浮点数的最大值和最小值.
免责声明:对于本次讨论,我喜欢使用 IEEE-754 描述的 32 位和 64 位浮点。我对扩展浮点(80 位)或四边形(128 位 IEEE-754-2008)或任何其他标准 (IEEE-854) 不感兴趣。
背景:计算机不擅长用二进制表示 0.1
。在 C# 中,浮点数在内部将其表示为 3DCCCCCD
(C# 使用舍入到最近),双精度数表示为 3FB999999999999A
。相同的位模式用于十进制 0.100000005
(float) 和 0.1000000000000000124
(double),但不适用于 0.1000000000000000144
(double)。
为方便起见,以下 C# 代码给出了这些内部表示:
string GetHex(float f)
return BitConverter.ToUInt32(BitConverter.GetBytes(f), 0).ToString("X");
string GetHex(double d)
return BitConverter.ToUInt64(BitConverter.GetBytes(d), 0).ToString("X");
// float
Console.WriteLine(GetHex(0.1F));
// double
Console.WriteLine(GetHex(0.1));
在0.1
的情况下,没有用相同位模式表示的小十进制数,任何0.99...99
都会产生不同的位表示(即,0.999999937
的浮点数在内部产生3F7FFFFF
) .
我的问题很简单:如何找到以相同二进制表示形式内部存储的给定浮点数(或双精度数)的最低和最高十进制值。
为什么:(我知道你会问)在 .NET 转换为字符串和从字符串转换时查找舍入错误,以查找内部精确值和更好地了解我自己的舍入误差。
我的猜测是这样的:取尾数,去掉其余的,得到它的精确值,再高一个(尾数位),然后计算平均值:低于这个值的任何东西都会产生相同的位模式。我的主要问题是:如何将小数部分作为整数(位操作它不是我最强的资产)。 Jon Skeet's DoubleConverter 类可能会有所帮助。
【问题讨论】:
【参考方案1】:解决您的问题的一种方法是在 Last 中找到 ULP 或 Unit 的大小Place,你的浮点数。稍微简化一下,这是给定浮点数和下一个更大数字之间的距离。再次简化一点,给定一个可表示的浮点值 x,任何值在 (x - 1/2 ulp) 和 (x + 1/2 ulp) 之间的十进制字符串在转换为浮点数时都将舍入为 x -点值。
诀窍在于 (x +/- 1/2 ulp) 不是可表示的浮点数,因此实际计算它的值需要您使用更宽的浮点类型(如果可用)或任意width big decimal 或类似类型来进行计算。
如何找到 ulp 的大小?一种相对简单的方法大致是您建议的,这里写的是 C-ish 伪代码,因为我不懂 C#:
float absX = absoluteValue(x);
uint32_t bitPattern = getRepresentationOfFloat(absx);
bitPattern++;
float nextFloatNumber = getFloatFromRepresentation(bitPattern);
float ulpOfX = (nextFloatNumber - absX);
这是有效的,因为在 x 的位模式上加一恰好对应于在 x 的值上加一 ulp。减法中不会发生浮点舍入,因为所涉及的值非常接近(特别是 ieee-754 浮点算术的定理,如果两个数 x 和 y 满足 y/2 x - y)。这里唯一需要注意的是:
-
如果 x 恰好是最大的有限浮点数,这将不起作用(它将返回
inf
,这显然是错误的)。
如果您的平台不能正确支持逐渐下溢(比如嵌入式设备在清零模式下运行),则这不适用于非常小的 x 值。
听起来您不太可能处于这两种情况中,所以这应该可以很好地满足您的目的。
现在您知道 x 的 ulp 是什么,您可以找到四舍五入为 x 的值的区间。您可以精确地以浮点计算 ulp(x)/2,因为浮点除以 2 是精确的(同样,除非下溢)。然后你只需要计算 x +/- ulp(x)/2 合适的更大浮点类型(如果你对float
感兴趣,double
将起作用)或 Big Decimal 类型的值,你有你的间隔。
我通过这个解释做了一些简化的假设。如果您确实需要准确地说明这一点,请发表评论,我会在有机会时对有些模糊的部分进行扩展。
另一个注意事项您的问题中的以下陈述:
0.1的情况下,没有更低的 表示的十进制数 具有相同的位模式
不正确。您只是碰巧查看了错误的值(0.999999... 而不是 0.099999... -- 很容易打错)。
【讨论】:
优秀的答案,似乎是我正在寻找的信息。如果我需要更多关于花絮的帮助,我将尝试在 C# 中解决它并返回这里。我注意到您已与 IEEE-754 团队合作建立标准?我很荣幸 :)。你对那个错字是正确的!我很惊讶我找不到更低的值,但我想当然地把它写下来,错误和所有,哈哈!【参考方案2】:Python 3.1 刚刚实现了类似这样的功能:请参阅 the changelog (scroll down a bit)、bug report。
【讨论】:
以上是关于查找具有相同内部表示的浮点数/双精度数的最小值/最大值的主要内容,如果未能解决你的问题,请参考以下文章