ULP 1 时的舍入 - Java 和 C++

问题描述 投票:0回答:1

问题的原因源于我在计算 C++ 中的 std::exp(x) 与 Java 中的 Math.exp(x) (x 类型为 double)时观察到的结果差异。我注意到两种语言用于计算 exp() 的算法是不同的。不过,我相信它们都确保舍入误差为 ULP 1。

所以问题如下: ULP 时如何进行舍入?它如何决定向上舍入还是向下舍入?以及“谁”做出选择?

我希望在 C++ 中计算 exp(x) 时获得与 Java 相同的精确结果。 如果我在 C++ 中复制 Java 在 Math.exp() 中使用的精确算法(实际上委托给 fdlibm),我会在两种语言之间获得相同的结果吗? 或者 ULP 1 的结果是向上或向下舍入是任意的,因此它不依赖于特定算法?

注意:我对 ULP 1 的理解是,如果数学函数的结果是,假设 f(x) = 0.55,并且接近它的浮点数是 0.52 和 0.56,那么(即使 0.56 是最佳值)选择)结果可能是 0.52 或 0.56。

进一步的问题:我还观察到,在 x86 和 x64 之间切换 C++ 确实会改变 exp(x) 的结果,有时会将其与 Java 给出的结果对齐。为什么在 x86 和 x64 构建的 C++ 中 exp(x) 的结果会发生变化?

java c++ floating-point double precision
1个回答
0
投票

注意:我对 ULP 1 的理解是,如果数学函数的结果是(假设)f(x) = 0.55,并且接近它的浮点数是 0.52 和 0.56,那么(即使 0.56 是最佳值)选择)结果可能是 0.52 或 0.56。

这是不正确的。 C++ 标准没有指定标准库中的数学例程必须计算的精确度,并且实现各不相同。并注意复数:有多种实现。你的问题指的是“C++ 中的 std::exp(x)”,就好像它是一个单一的东西一样。它不是。

exp
在不同的 C++ 实现中使用了不同的实现。单个 C++ 编译器甚至可以与包含
std::exp
实现的不同选择的库链接。

我不太熟悉 Java 标准在这方面的规范,尽管我知道它的

StrictMath
类是根据 fdlibm 版本 5.3 定义的,因此它应该在不同的实现中给出可重现的结果。

您描述的属性,其中

f(x)
的计算结果是直接限制数学 f(x) 的两个浮点数之一,称为 忠实舍入。 (不同地方使用的“忠实舍入”的定义可能略有不同。)

数学例程的实现不忠实地舍入是很常见的。多个 ULP 的错误可能是常见的,并且可能存在更大的错误。

除非使用带有 C++ 的 fdlibm 版本 5.3 实现,否则不太可能在 Java 和 C++ 中获得相同的结果。

© www.soinside.com 2019 - 2024. All rights reserved.