Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.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++ C+中的差异+;浮点减法_C++_Templates_Floating Point_C++17_Loss Of Significance - Fatal编程技术网

C++ C+中的差异+;浮点减法

C++ C+中的差异+;浮点减法,c++,templates,floating-point,c++17,loss-of-significance,C++,Templates,Floating Point,C++17,Loss Of Significance,我正在开发一个Vec3模板类,它(毫不奇怪)存储任何类型的三个元素的向量。下面是去掉不相关位的类头: 模板 Vec3类 { 私人: T数据[3]={0}; 公众: 内联Vec3(常数T&d0、常数T&d1、常数T&d2)无例外; 内联Vec3(常量Vec3和其他)无例外; 内联void运算符=(const Vec3和其他)noexcept; 内联Vec3运算符-(常量Vec3和其他)无异常; 内联布尔运算符==(const Vec3和其他)const noexcept; }; 类型def Vec

我正在开发一个
Vec3
模板类,它(毫不奇怪)存储任何类型的三个元素的向量。下面是去掉不相关位的类头:

模板
Vec3类
{
私人:
T数据[3]={0};
公众:
内联Vec3(常数T&d0、常数T&d1、常数T&d2)无例外;
内联Vec3(常量Vec3和其他)无例外;
内联void运算符=(const Vec3和其他)noexcept;
内联Vec3运算符-(常量Vec3和其他)无异常;
内联布尔运算符==(const Vec3和其他)const noexcept;
};
类型def Vec3 Vec3f;
模板
内联Vec3::Vec3(常数T&d0、常数T&d1、常数T&d2)无例外
{
数据[0]=d0;
数据[1]=d1;
数据[2]=d2;
}
模板
内联Vec3::Vec3(常量Vec3和其他)无例外
{
*这个=其他;
}
模板
内联void Vec3::operator=(const Vec3和其他)noexcept
{
数据[0]=其他.数据[0];
数据[1]=其他.数据[1];
数据[2]=其他.数据[2];
}
模板
内联Vec3 Vec3::运算符-(const Vec3和其他)无异常
{
返回向量3(
数据[0]-其他.数据[0],
数据[1]-其他.数据[1],
数据[2]-其他.数据[2]
);
}
模板
内联bool Vec3::operator==(const Vec3和其他)const noexcept
{
如果(标准::是否相同)
{
返回
DoubleEq(数据[0],其他.data[0])&&
DoubleEq(数据[1],其他.data[1])&&
DoubleEq(数据[2],其他数据[2]);
}
否则如果(标准::是否相同)
{
返回
浮动Q(数据[0],其他.data[0])&&
浮动Q(数据[1],其他.data[1])&&
浮动Q(数据[2],其他数据[2]);
}
其他的
{
返回
数据[0]==其他。数据[0]&&
数据[1]==其他。数据[1]&&
数据[2]==其他.数据[2];
}
}
此处定义了ε比较函数:

inline bool DoubleEq(常数双a,常数双b)
{
返回(fabs(a-b)
我正在用套件测试它,但遇到以下代码片段的问题:

Vec3f vecf1={32.1432768.13439789.1345};
Vec3f vecf2={643.5348,75.4232,20.4701};
Vec3f vecf3=vecf1-vecf2;
EXPECT_TRUE(vecf1==Vec3f(32.1432768.13439789.1345));//通行证
EXPECT_TRUE(vecf2==Vec3f(643.5348,75.4232,20.4701));//通行证
EXPECT_TRUE(vecf3==Vec3f(32.1432-643.5348768.1343-75.42329789.1345-20.4701));//失败:(
这应该很简单,因为第三次测试中用于构建比较向量的数字与
vecf1
vecf2
中的数字完全相同。但是,打印
vec3f
和原始操作会产生不同的值:


std::cout我在这里看到了几个问题:

Epsilon是一个一位的错误,但大约是1。您应该缩放espilon以匹配结果的比例

1位错误(1 epsilon)适用于1次加法,操作越复杂,位错误越大。因此,您可能希望能够指定它,以便在其他测试中重复使用

例如:

#include <cmath>

template <typename _Float> 
inline bool FloatEq (_Float a, _Float b, _Float bit_margin = _Float(1)) noexcept
{
    const _Float epsilon = std::max(std::abs(a), std::abs(b)) * std::numeric_limits<_Float>::epsilon();

    return std::abs(b - a) < (bit_margin * epsilon);
}
#包括
模板
内联布尔浮点Q(_floatA,_floatB,_floatbit_margin=_Float(1))无例外
{
常量浮点数epsilon=std::max(std::abs(a),std::abs(b))*std::numeric_limits::epsilon();
返回标准::abs(b-a)<(位裕度*ε);
}

在一种情况下减去
double
,在另一种情况下减去
float
看看你是如何使用
std::numeric\u limits::epsilon()
,你能想出一种方法来编写一个几乎相等的
模板bool(ta,tb)
而不是
DoubleEq
flootq
内联bool Vec3::operator==(const-Vec3&other)const-noexcept(const-noexcept)
这种方法虽然很好,但却是有毒的。
=
应该是可转换的,例如
a==b
b==c
意味着
a==c
。事实上,它不是意味着,如果你的vec使用
=
的话,你的所有
std
算法都会爆炸。例如,“几乎相等”是非常有用的,但它的名称不应该是
==
fabs(a-b)
基本上是无用的。
epsilon()
是1和下一个可表示数字之间的差。
epsilon()
因为根据
epsilon()
的定义,
double
格式具有表示该差异的精度。但是[2,4]中数字的最小差异是该差异的两倍。它们不能通过
epsilon()来区别
因为格式没有精确性。对于问题中显示的样本值,如
32.1432
fabs(a-b)
只有当
a==b
时才是真的。相反,对于非常小的数字,
fabs(a-b)
将错误地报告
a
b
是相等的,即使它们相差很大,例如+2^−100及−23•2^−60.我知道怎么做,但我不明白为什么,也找不到任何关于为什么应该这样做的参考资料。你能分享一个来源或详细说明一下这个主题吗?浮点值由尾数和指数组成。ε在matissa中是1位错误,但你必须缩放指数以匹配你正在比较的值。乘以匹配的数字,变量的指数会更接近彼此。我明白了。
\u Float epsilon
是正确的指数,而位边距是我可以容忍的位错误数(这就是为什么它默认设置为1),对吗?正是这样。
119 inline Vec3<T> Vec3<T> :: operator - (const Vec3<T> & other) noexcept
(gdb) p this
$1 = (Vec3<float> * const) 0x5555555899a0
(gdb) p *this
$2 = {data = {32.1431999, 768.134277, 9789.13477}}
(gdb) p other
$3 = (const Vec3<float> &) @0x5555555899ac: {data = {643.53479, 75.4232025, 20.4701004}}
(gdb) n
124         data[2] - other.data[2]
(gdb) 
123         data[1] - other.data[1],
(gdb) 
122         data[0] - other.data[0],
(gdb) n
125     );
(gdb) n
126 }
(gdb) p data[0] - other.data[0]
$4 = -611.391602
(gdb) p data[1] - other.data[1]
$5 = 692.71106
(gdb) p data[2] - other.data[2]
$6 = 9768.66504
(gdb) n
Vec3Test_Subtraction_NoSideEffects_Test::TestBody (this=0x5555555898d0) at tests/vec3.hpp:218
218     std::cout << vecf3[0]         << " " << vecf3[1]         << " " << vecf3[2]          << std::endl;
(gdb) 
-611.392 692.711 9768.67
219     std::cout << 32.1432-643.5348 << " " << 768.1343-75.4232 << " " << 9789.1345-20.4701 << std::endl;
(gdb) 
-611.392 692.711 9768.66
 1 FAILED TEST
==47278== 
==47278== HEAP SUMMARY:
==47278==     in use at exit: 0 bytes in 0 blocks
==47278==   total heap usage: 347 allocs, 347 frees, 138,501 bytes allocated
==47278== 
==47278== All heap blocks were freed -- no leaks are possible
==47278== 
==47278== For lists of detected and suppressed errors, rerun with: -s
==47278== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
#include <cmath>

template <typename _Float> 
inline bool FloatEq (_Float a, _Float b, _Float bit_margin = _Float(1)) noexcept
{
    const _Float epsilon = std::max(std::abs(a), std::abs(b)) * std::numeric_limits<_Float>::epsilon();

    return std::abs(b - a) < (bit_margin * epsilon);
}