计算最后一个位置(ULP)的单位为双打

kpo*_*zin 8 .net c# floating-point double

.NET是否有内置方法来计算给定double或float 的ULP

如果没有,最有效的方法是什么?

pho*_*oog 6

看起来这个功能非常简单; 这是基于vulkanino链接问题的公认答案中的伪代码:

double value = whatever;
long bits = BitConverter.DoubleToInt64Bits(value);
double nextValue = BitConverter.Int64BitsToDouble(bits + 1);
double result = nextValue - value;
Run Code Online (Sandbox Code Playgroud)

对于花车,你需要提供自己的实施SingleToInt32BitsInt32BitsToSingle,因为BitConverter不具备这些功能.

此页面显示了该函数的java实现中的特殊情况; 处理这些也应该是相当微不足道的.


chu*_*ica 6

phoog 答案很好,但有负数、max_double、无穷大和 NaN 的弱点。

phoog_ULP(positive x) --> 一个正数。好的。
phoog_ULP(negative x) --> 负数。我希望正数。
为了解决这个问题,我建议改为:

long bits = BitConverter.DoubleToInt64Bits(value) & 0x7FFFFFFFFFFFFFFFL;
Run Code Online (Sandbox Code Playgroud)

以下是您应该关心的需要解决的边缘案例...

phoog_ULP(x = +/- Max_double 1.797...e+308) 返回无限结果。(+1.996...e+292) 预期。
phoog_ULP(x = +/- Infinity) 结果为 NaN。+无限预期。
phoog_ULP(x = +/- NaN) 可能会意外地从 sNan 变为 qNaN。预计不会有任何变化。在这种情况下,如果符号应该变成 +,人们可以以任何一种方式争论。


为了解决这些问题,我只看到了一系列简短的粗暴if()测试来适应这些,为了方便起见,可能在“位”值上。例子:

double ulpc(double value) {
  long long bits = BitConverter::DoubleToInt64Bits(value);
  if ((bits & 0x7FF0000000000000L) == 0x7FF0000000000000L) { // if x is not finite
    if (bits & 0x000FFFFFFFFFFFFFL) { // if x is a NaN
      return value;  // I did not force the sign bit here with NaNs.
      } 
    return BitConverter.Int64BitsToDouble(0x7FF0000000000000L); // Positive Infinity;
    }
  bits &= 0x7FFFFFFFFFFFFFFFL; // make positive
  if (bits == 0x7FEFFFFFFFFFFFFFL) { // if x == max_double (notice the _E_)
    return BitConverter.Int64BitsToDouble(bits) - BitConverter.Int64BitsToDouble(bits-1);
  }
  double nextValue = BitConverter.Int64BitsToDouble(bits + 1);
  double result = nextValue - fabs(value);
  return result;
}
Run Code Online (Sandbox Code Playgroud)