Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ exp10与pow不同(10)_C++_Floating Point_Math.h - Fatal编程技术网

C++ exp10与pow不同(10)

C++ exp10与pow不同(10),c++,floating-point,math.h,C++,Floating Point,Math.h,首先,我意识到大多数以10为基数的数字不能精确地以2为基数表示,因此我的问题并不是关于浮点运算的缺陷 我正在尝试编写一个函数,通过检查最后6个有意义的数字是否在某个公差范围内,并将其更改为高于某个假定精确值的下一个可表示的值(仅用于显示目的-除非它是整数或二的幂),尝试更正受累积舍入错误影响的双精度 我的函数中让我吃惊的一个部分是exp10的输出;就我所知,只要两个double之间的间距小于2,那么存储为double的整数值应该是精确的——尽管10^14正在推它,但这应该是一个精确的整数(因为1

首先,我意识到大多数以10为基数的数字不能精确地以2为基数表示,因此我的问题并不是关于浮点运算的缺陷

我正在尝试编写一个函数,通过检查最后6个有意义的数字是否在某个公差范围内,并将其更改为高于某个假定精确值的下一个可表示的值(仅用于显示目的-除非它是整数或二的幂),尝试更正受累积舍入错误影响的双精度

我的函数中让我吃惊的一个部分是exp10的输出;就我所知,只要两个double之间的间距小于2,那么存储为double的整数值应该是精确的——尽管10^14正在推它,但这应该是一个精确的整数(因为10^14=~2^46.507<2^53)。然而,这不是我的测试所显示的

我的调试工作摘录(没有什么比这更明显)和输出如下:

double test = 0.000699;
double tmp = fabs(test);
double exp = 10.0 - floor(log10(tmp));
double powTen = exp10(10.0 - floor(log10(tmp)));
double powTen2 = exp10(exp);
double powTen3 = exp10((int)exp);
double powTen4 = exp10(exp);
double powTen5 = pow(10, exp);

printf("exp: %.16lf\n", exp);
printf("powTen: %.16lf\n", powTen);
printf("powTen2: %.16lf\n", powTen2);
printf("powTen3: %.16lf\n", powTen3);
printf("powTen4: %.16lf\n", powTen4);

//these two are exact
printf("10^14: %.16lf\n", exp10(14));
printf("powTen5: %.16lf\n", powTen5);
printf("exp == 14.0: %d\n", exp == 14.0);
输出:

exp: 14.0000000000000000
powTen: 100000000000000.1250000000000000
powTen2: 100000000000000.1250000000000000
powTen3: 100000000000000.1250000000000000
powTen4: 100000000000000.1250000000000000
10^14: 100000000000000.0000000000000000
powTen5: 100000000000000.0000000000000000
exp == 14.0: 1
pow得到的是精确的答案,就像带有硬编码int的exp10一样。对于所有其他情况,我添加了1/8(10^14和10^14+下一个表示的间隔是1/64)。 文件上说exp10应该等同于pow。有人能看到我遗漏的东西吗


编辑-通过O3、O2、O1优化,我将获得预期的输出-除非运行时才能知道数据。此时exp10仍有问题。

您的
exp10
实现可能有问题。请注意,它返回的结果有时会被ulp关闭(相对于您的10^14为0.125)

这是一个相当令人发指的错误;有一种情况,正确的答案可以表示为
double
,但是
exp10
没有这样做

我赞同Ben Voigt的评论,即编译器有时可能会自行计算,而不是将它们传递给数学库。它可能做得更好,因为它可能链接到任意精度的数学库。您可以尝试使用
-fno-builtin
选项来查看它是否改变了任何内容

不幸的是,我认为没有实现
exp10
。否则我建议你用这个,别担心了

编辑:我拥有的
eglibc
源代码的副本似乎实现了
exp10
,因此:

double
__ieee754_exp10 (double arg)
{
  /* This is a very stupid and inprecise implementation.  It'll get
     replaced sometime (soon?).  */
  return __ieee754_exp (M_LN10 * arg);
}

不要期望它能很好地工作。

谢谢,我已经关注了那篇文章,但是exp10的这种行为是不正确的-除非我对它的使用不正确-我不是在问为什么0.6看起来像0.599999999….+垃圾或为什么0.3-0.2-0.1!=0.0等等。。。我想问的是,为什么可以精确表示为整数的东西不是用exp10表示的,而是用pow
exp10(14)
表示的,可能是由编译器计算的,编译器可能有不同的舍入设置。无法解释其他内容。顺便说一句,请打印
exp==14.0
Please的结果,因为这些都是编译时常数,经过优化,它们可能都是在编译过程中计算出来的。@MarkRansom 0.5 ULP是“完美的”。1 ULP为中间结果留出了足够的空间,只要您能够以稍微扩展的精度计算中间结果,每个中间结果都可能稍有错误。如果我必须将
exp10
实现为1个ULP,我会调用质量差的
exp10l()
(几个ULP错误),并将结果取整为
double
。如果我必须实现
exp10
,那会困难得多。我得先查查了解Sollya的人住在哪里,然后绑架他们的狗。这会很混乱。@MarkRansom:我不会追求完美的结果,但一个1ULP错误真的是令人发指。如何实现
exp10
以获得次ulp错误:在
[1,2]
上找到一个好的近似多项式以达到四倍精度,使用
double-double
技术将其评估为扩展精度,处理指数(作为
double-double
),并将二者相乘(再次作为
double-double-double
)。也许我会对有效位的高位和指数做类似的处理。如果做得好,你可以得到最高的保证,比如说,0.51 ulp。你们这些人和你们的疯狂杀戮。双人双人?方庭?呸
exp10
具有表现出色的系列扩展,您可以通过“Gal的精确表”和切比雪夫、凯瑟多利·费耶尔或极大极小多项式对本机双精度中评估的残差轻松提供超ulp精度。试一试,这是一个有趣的方式度过一个下午。@斯蒂芬康:考虑我NordsIdoP.FYI,最坏的情况下,Exp10的双精度(Bial64)在轮到最接近的是:Exp10(1。A83B1CF77 9890-26),其确切结果是1 000000 F434 FAAP0:01(60)0101…(其中冒号后面是截断的53位有效位之后的位序列,[60]表示前面的位1重复60次)。因此,需要大约114位的精度。以下方面的全部结果: