首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用gmp mpf_class进行逼近

用gmp mpf_class进行逼近
EN

Stack Overflow用户
提问于 2022-01-06 17:38:04
回答 1查看 112关注 0票数 1

我正在使用UnitTest编写一个Catch2。

我想检查两个向量是否相等。它们使用gmplib看起来如下所示:

代码语言:javascript
复制
std::vector<mpf_class> result

由于我“伪造”了expected_result向量,在测试失败后我得到了以下消息:

代码语言:javascript
复制
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 }

所以我在寻找一个函数,它可以为我做一个近似。

我只是没能找到一个适合我的解决方案。

我找到了一些比较函数,但它们不适用于我的项目。

编辑:“最小的、可复制的示例就是:

代码语言:javascript
复制
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建议它运行得很好,直到我有了一些不完整的“偶数”值。

因此,下面的值失败了:

代码语言:javascript
复制
actual   0.16666666666666666666700000000000000000000000000000
expected 0.16666666666666665741500000000000000000000000000000

尽管我的“预期”值如下所示:

代码语言:javascript
复制
mpf_class expected = 0.16666666666666666666700000000000000000000000000000

回到我最初的问题,如果有一种方法,我可以比较这个数字的近似和一个类似-0.0001的epsilon,或者什么是解决这个问题的最好方法?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-01-07 02:41:49

首先,我们需要看到一些最小的,可复制的例子来确定正在发生的事情。例如,您可以从test.cpp中减少一些代码,直到只剩下几行代码,但问题仍然存在。此外,请提供编译和运行说明。通常,对你的目标做一点解释也会有所帮助。由于Catch2可以在GitHub上使用,所以不需要提供它。

在没有看到代码的情况下,我能猜到的最好的情况是,您的代码试图使用mpf_t操作符比较mpf_class中的==类型,我担心它没有超载(参见这里)。您应该将mpf_tcmp函数进行比较,因为C类型mpf_t实际上是一个包含指向实际意义和分支的指针的结构。检查GMP的tests/cxx/目录中的一些使用示例(如这里)。

我注意到您正在使用GNU 4.1版本,这是非常老的版本,如果可能的话,您可能希望使用6.2.1最新版本。此外,对于使用浮标,建议您使用GNU MPFR库而不是GMP。

编辑:我还没有设法运行Catch2,但是您的代码的问题是expected_result实际上并不等于actual_result。在GMP中,mpf_t变量具有64位意义和精度(在64位机器上),因此除法a / b实际上生成了一个二进制文件,该二进制文件输出0.16666666666666667(这是数字1之后的19个6位)。尝试用gmp_printf("%.50Ff\n", actual_result);打印结果,因为标准的cout输出将只给出6位数的值: 0.166667。

但是问题是您不能像expected_result = 0.166666666666666666667那样分配这个值,因为在C/C++中,数值常量被解析为double,因此您必须使用字符串重载属性来获得更高的精度。

但是,您也不能轻松地(或者,通常来说,合理地)创建一个小数字符串,它将正确地转换为a / b给出的完全相同的二进制,因为十进制到浮点转换具有微妙性,例如这里这里

所以,这完全取决于你的应用程序和你想要做的数值验证的类型。如果您知道您的十进制验证值对某些已知的精度是正确的,并且如果您将mpf_t变量设置为抵挡精度(例如使用mpf_set_prec),那么您可以使用容差比较,如下所示。

在C++ (没有Catch2)中,它的工作方式如下:

代码语言:javascript
复制
#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选项编译。

它产生的输出:

代码语言:javascript
复制
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)进行比较,那就没问题了。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70611257

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档