使用 gmp 的近似值 mpf_class
Approximation using gmp mpf_class
我正在使用 Catch2 编写单元测试。
我想检查两个向量是否相等。使用 gmplib 它们看起来像下面这样:
std::vector<mpf_class> result
由于我 'faking' expected_result 向量,我在测试失败后收到以下消息:
unittests/test.cpp:01: FAILED:
REQUIRE( actual_result == expected_result )
with expansion:
{ 0.5, 0.166667, 0.166667, 0.166667 }
==
{ 0.5, 0.166667, 0.166667, 0.166667 }
所以我一直在寻找一个可以为我做近似的函数。
我只是没有成功找到适合我的解决方案。
我找到了一些 Comparison Functions 但它们不适用于我的项目。
编辑:
“最小的、可重现的例子就是:
TEST_CASE("DemoTest") {
// simplified:
mpf_class a = 1;
mpf_class b = 6;
mpf_class actual_result = a / b;
mpf_class expected_result= 0.16666666667;
REQUIRE(actual_result == expected_result);
}
与我的实际应用程序的“唯一”区别是结果存储在向量中。但是因为我只是通过说它是“0.1666666667”来“伪造”结果,所以它可能不再适合 == 了。所以我需要一个采用近似值并比较范围的函数,如 epsilon = +-0.001.
编辑:
实施解决方案后,@Arc 建议它运行良好,直到我有一些不完整的“偶数”值。
所以我有以下值的失败:
actual 0.16666666666666666666700000000000000000000000000000
expected 0.16666666666666665741500000000000000000000000000000
尽管我的“预期”值是这样的:
mpf_class expected = 0.16666666666666666666700000000000000000000000000000
回到我最初的问题,是否有一种方法可以将数字的近似值与类似 +-0.0001 的 epsilon 进行比较,或者解决此问题的最佳方法是什么?
首先,我们需要看一些 Minimal, Reproducible Example 以确定发生了什么。例如,您可以从 test.cpp
中删除一些代码,直到只剩下几行代码,但问题仍然存在。另外,请提供编译和 运行ning 说明。通常,对您的目标做一些解释也可能有所帮助。由于 Catch2 在 GitHub 上可用,因此您无需提供它。
在没有看到代码的情况下,我最多只能猜测您的代码正在尝试使用 ==
运算符来比较 mpf_class
中的 mpf_t
类型,这恐怕尚未过载(参见 here). You should compare mpf_t
s with the cmp
function, since the C type mpf_t
is actually an struct containing the pointer to the actual significand limbs. Check some usage examples in the tests/cxx/
directory of GMP (like here)。
我注意到您使用的是非常旧的 GNU MP 4.1 版本,如果可能,您可能想移动到最新版本 6.2.1。此外,对于使用浮点数,建议您使用 GNU MPFR 库而不是 GMP 浮点数。
编辑:我还没有设法 运行 Catch2,但是你的代码的问题是 expected_result
实际上不等于 actual_result
。在 GMP mpf_t
中,变量是用 64 位有效位精度创建的(在 64 位机器上),因此除法 a / b
实际上会产生一个打印 0.166666666666666666667 的二进制文件(即数字 1 后的 19 个六) ).尝试用 gmp_printf("%.50Ff\n", actual_result);
打印结果,因为标准 cout
输出只会给你四舍五入到 6 位数字的值:0.166667.
但问题是你不能像 expected_result = 0.166666666666666666667
这样赋值,因为在 C/C++ 中数字常量被解析为 double
,因此你必须使用字符串重载归因以获得更高的精确度。
但是你也不能轻易地(或者,一般来说,合理地)创造一个十进制字符串,该字符串将正确转换为由 [=23 给出的完全相同的二进制文件=] 因为十进制到浮点数的转换有微妙之处,例如参见 [=37=].
因此,这完全取决于您的应用程序和您打算进行的数值验证类型。如果您知道您的小数验证值对于某些已知精度是正确的,并且如果您将 mpf_t
变量设置为承受精度(例如使用 mpf_set_prec
),那么您可以使用公差比较,就像这样。
在 C++ 中(没有 Catch2),它是这样工作的:
#include <iostream>
#include <gmpxx.h>
using namespace std;
int main (void)
{
mpf_class a = 1;
mpf_class b = 6;
mpf_class actual = a / b;
mpf_class expected;
mpf_class tol;
expected = "0.166666666666666666666666666666667";
tol = "1e-30";
cout << "actual " << actual << "\n";
cout << "expected " << expected << "\n";
gmp_printf("actual %.50Ff\n", actual);
gmp_printf("expected %.50Ff\n", expected);
gmp_printf("tol %.50Ff\n", tol);
mpf_class diff = expected - actual;
gmp_printf("diff %.50Ff\n", diff);
if (abs(actual - expected) < tol)
cout << "ok\n";
else
cout << "nop\n";
return 0;
}
并使用 -lgmpxx -lgmp
选项进行编译。
它产生输出:
actual 0.166667
expected 0.166667
actual 0.16666666666666666666700000000000000000000000000000
expected 0.16666666666666666666700000000000000000000000000000
tol 0.00000000000000000000000000000100000000000000000000
diff 0.00000000000000000000000000000000033333529249058470
ok
如果我理解 Catch2 很好,如果你将 expected_result
分配给字符串然后与 REQUIRE(abs(actual - expected) < tol)
进行比较应该没问题。
我正在使用 Catch2 编写单元测试。
我想检查两个向量是否相等。使用 gmplib 它们看起来像下面这样:
std::vector<mpf_class> result
由于我 'faking' expected_result 向量,我在测试失败后收到以下消息:
unittests/test.cpp:01: FAILED:
REQUIRE( actual_result == expected_result )
with expansion:
{ 0.5, 0.166667, 0.166667, 0.166667 }
==
{ 0.5, 0.166667, 0.166667, 0.166667 }
所以我一直在寻找一个可以为我做近似的函数。
我只是没有成功找到适合我的解决方案。
我找到了一些 Comparison Functions 但它们不适用于我的项目。
编辑: “最小的、可重现的例子就是:
TEST_CASE("DemoTest") {
// simplified:
mpf_class a = 1;
mpf_class b = 6;
mpf_class actual_result = a / b;
mpf_class expected_result= 0.16666666667;
REQUIRE(actual_result == expected_result);
}
与我的实际应用程序的“唯一”区别是结果存储在向量中。但是因为我只是通过说它是“0.1666666667”来“伪造”结果,所以它可能不再适合 == 了。所以我需要一个采用近似值并比较范围的函数,如 epsilon = +-0.001.
编辑:
实施解决方案后,@Arc 建议它运行良好,直到我有一些不完整的“偶数”值。
所以我有以下值的失败:
actual 0.16666666666666666666700000000000000000000000000000
expected 0.16666666666666665741500000000000000000000000000000
尽管我的“预期”值是这样的:
mpf_class expected = 0.16666666666666666666700000000000000000000000000000
回到我最初的问题,是否有一种方法可以将数字的近似值与类似 +-0.0001 的 epsilon 进行比较,或者解决此问题的最佳方法是什么?
首先,我们需要看一些 Minimal, Reproducible Example 以确定发生了什么。例如,您可以从 test.cpp
中删除一些代码,直到只剩下几行代码,但问题仍然存在。另外,请提供编译和 运行ning 说明。通常,对您的目标做一些解释也可能有所帮助。由于 Catch2 在 GitHub 上可用,因此您无需提供它。
在没有看到代码的情况下,我最多只能猜测您的代码正在尝试使用 ==
运算符来比较 mpf_class
中的 mpf_t
类型,这恐怕尚未过载(参见 here). You should compare mpf_t
s with the cmp
function, since the C type mpf_t
is actually an struct containing the pointer to the actual significand limbs. Check some usage examples in the tests/cxx/
directory of GMP (like here)。
我注意到您使用的是非常旧的 GNU MP 4.1 版本,如果可能,您可能想移动到最新版本 6.2.1。此外,对于使用浮点数,建议您使用 GNU MPFR 库而不是 GMP 浮点数。
编辑:我还没有设法 运行 Catch2,但是你的代码的问题是 expected_result
实际上不等于 actual_result
。在 GMP mpf_t
中,变量是用 64 位有效位精度创建的(在 64 位机器上),因此除法 a / b
实际上会产生一个打印 0.166666666666666666667 的二进制文件(即数字 1 后的 19 个六) ).尝试用 gmp_printf("%.50Ff\n", actual_result);
打印结果,因为标准 cout
输出只会给你四舍五入到 6 位数字的值:0.166667.
但问题是你不能像 expected_result = 0.166666666666666666667
这样赋值,因为在 C/C++ 中数字常量被解析为 double
,因此你必须使用字符串重载归因以获得更高的精确度。
但是你也不能轻易地(或者,一般来说,合理地)创造一个十进制字符串,该字符串将正确转换为由 [=23 给出的完全相同的二进制文件=] 因为十进制到浮点数的转换有微妙之处,例如参见 [=37=].
因此,这完全取决于您的应用程序和您打算进行的数值验证类型。如果您知道您的小数验证值对于某些已知精度是正确的,并且如果您将 mpf_t
变量设置为承受精度(例如使用 mpf_set_prec
),那么您可以使用公差比较,就像这样。
在 C++ 中(没有 Catch2),它是这样工作的:
#include <iostream>
#include <gmpxx.h>
using namespace std;
int main (void)
{
mpf_class a = 1;
mpf_class b = 6;
mpf_class actual = a / b;
mpf_class expected;
mpf_class tol;
expected = "0.166666666666666666666666666666667";
tol = "1e-30";
cout << "actual " << actual << "\n";
cout << "expected " << expected << "\n";
gmp_printf("actual %.50Ff\n", actual);
gmp_printf("expected %.50Ff\n", expected);
gmp_printf("tol %.50Ff\n", tol);
mpf_class diff = expected - actual;
gmp_printf("diff %.50Ff\n", diff);
if (abs(actual - expected) < tol)
cout << "ok\n";
else
cout << "nop\n";
return 0;
}
并使用 -lgmpxx -lgmp
选项进行编译。
它产生输出:
actual 0.166667
expected 0.166667
actual 0.16666666666666666666700000000000000000000000000000
expected 0.16666666666666666666700000000000000000000000000000
tol 0.00000000000000000000000000000100000000000000000000
diff 0.00000000000000000000000000000000033333529249058470
ok
如果我理解 Catch2 很好,如果你将 expected_result
分配给字符串然后与 REQUIRE(abs(actual - expected) < tol)
进行比较应该没问题。