3

我已将Clipper 库的实验性 C#“float”版本翻译为 javascript。在最新的沙盒版本中,有一个似乎很难翻译的函数IsAlmostEqual 。由于数值稳定性问题,无法使用 == 运算符比较双重相等,因此需要此函数来处理这些问题。

-9223372036854775808 - aInt并且-9223372036854775808 - bInt很容易使用例如 BigInteger 库进行计算,但BitConverter.DoubleToInt64Bits更难。

知道如何将IsAlmostEqual函数转换为 javascript 吗?或者具体如何实现BitConverter.DoubleToInt64Bits到javascript?

private static bool IsAlmostEqual(double A, double B)
{
  //http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm

  Int64 aInt = BitConverter.DoubleToInt64Bits(A);
  if (aInt < 0) aInt = unchecked(-9223372036854775808 - aInt);
  Int64 bInt = BitConverter.DoubleToInt64Bits(B);
  if (bInt < 0) bInt = unchecked(-9223372036854775808 - bInt);
  return (Math.Abs(aInt - bInt) <= 10000000000);
}

数值稳定性和鲁棒性:
http ://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
http://www.mpi-inf.mpg.de/~kettner/pub/nonrobust_cgta_06.pdf
http:// cpc.cs.qub.ac.uk/MRSN/higham.pdf
http://www.2ality.com/2012/04/number-encoding.html

4

1 回答 1

2

我最终使用完全不同的函数从这里测试双重相等。原始函数使用 double 的有符号 int64 表示,如果不使用缓慢而复杂的按位运算或使用一些 BigDecimal 库,这在 Javascript 中是不可能的。它使用相对误差和绝对误差的组合。

var IsAlmostEqual = 函数(a,b)
{
  如果 (a == b) 返回真;
  var diff = Math.abs(a - b);
  if (diff < 4.94065645841247E-320) 返回真;
  a = Math.abs(a);
  b = 数学.abs(b);
  最小变量 = (b < a) ? 乙:一个;
  返回差异 < 最小 * 1e-12;
}

根据我的测试,它似乎可靠。请在jsbin中测试。

编辑:我更新了上面的代码。现在它在所有 83 个测试用例中产生与ULP 技术相同的结果(使用 maxUpls 10,000)。由于 Javascript 缺少 64 位整数,ULP 技术比上述 EPSILON 技术慢 8x-20x。

于 2014-01-06T19:31:36.940 回答