浮点精度——c++中的向量加法并不完全正确
floating accuracy - Vector addition in C++ is not coming out exactly right
我正在尝试在我的c++程序中添加一个向量到另一个向量,并且添加结果不准确。
这是vector类(使用cmath库):
class Vec{
float dir, mag;
public:
Vec(float dir, float mag){
this->dir = dir;
this->mag = mag;
}
float getX(){
return cos(dir)*mag;
}
Vec operator + (Vec v2){
float triangleX = cos(dir)*mag+cos(v2.dir)*v2.mag;
float triangleY = sin(dir)*mag+sin(v2.dir)*v2.mag;
return Vec(atan2(triangleY, triangleX), sqrt(pow(triangleX,2)+pow(triangleY,2)));
}
};
主要功能如下:
int main(){
Vec v1(0, 3); // 0º
Vec v2(3.14159265/2, 3); // 90º
Vec v3(3.14159265, 3); // 180º
std::cout.precision(15);
std::cout<<"v1: "<<v1.getX()<<std::endl;
std::cout<<"v1+v2: "<<(v1+v2).getX()<<std::endl;
std::cout<<"v1+v3: "<<(v1+v3).getX()<<std::endl;
return 0;
}
输出:
v1: 3
v1+v2: 2.99999976158142
v1+v3: 1.98007097372034e-014
可以看到,第一个输出v1很好。
第二个输出是0度和90度的相加(一个不应该影响x分量的角度),他的x分量接近3,但不完全是3。
第三个输出是两个大小相同的相反向量的相加,它应该是0,但它不是这里显示的。
是什么导致了这些奇怪的添加,我如何使它们准确?
v1 + v3
几乎是0.0
,代码工作正常
为什么不完全是0.0
,因为有些数字不能精确地表示为双精度。见:C/c++: 1.00000 <= 1.0f = False给出一些解释。
还有:Pi是无理数,不能在任何为自然数的进制中精确表示。
因此,任何涉及Pi的计算都不可能完全精确。
和:sin
, cos
, sqrt
通常都实现为不返回完全精确结果的算法,例如近似数值算法。
您遇到的基本问题是float
和您正在使用的pi
的值的有限精度之一。移动到double
将有所帮助,并且由于您已经包括<cmath>
,您应该使用M_PI
的值,并且至少精确到double
的精度。尽管如此,你仍然不能用这种方法得到确切的答案。(alain的答案很好地解释了原因。)
有一些可以改进的地方。一个是使用c++ 11特性的巧妙技巧,即"用户定义的字符串字面量"。如果您将此定义添加到代码中:
constexpr long double operator"" _deg(long double deg) {
return deg*M_PI/180;
}
您现在可以将_deg
附加到任何长双字量,它将在编译时自动转换为弧度。然后您的main
函数看起来像这样:
int main(){
Vec v1(0.0_deg, 3);
Vec v2(90.0_deg, 3);
Vec v3(180.0_deg, 3);
// ...
}
接下来你可以做的是存储x和y坐标,只在需要的时候做三角运算。那个版本的Vec
可能是这样的:
class Vec{
double x,y;
public:
Vec(double dir, double mag, bool cartesian=false) : x(dir), y(mag) {
if (!cartesian) {
x = mag*cos(dir);
y = mag*sin(dir);
}
}
double getX() const {
return x;
}
Vec operator + (const Vec &v2){
return Vec(x+v2.x, y+v2.y, true);
}
}
注意,我已经为构造函数创建了一个bool
值,它告诉输入是一个大小和方向还是一个x和y值。还要注意,getX()
被声明为const
,因为它不会改变Vec
,并且operator+
的参数也是const
引用,原因相同。当我在我的机器(64位机器)上进行这些更改时,我得到以下输出:
v1: 3
v1+v2: 3
v1+v3: 0
- C++从另一个类访问公共静态向量的正确方法是什么
- OpenGL GLM 矩阵/向量未正确初始化
- 向量的正确用法<int>::size_type
- 初始化 C++14 中唯一指针向量的正确方法
- 在一行中初始化和引入数组向量的正确方法?
- 如何从对象指针的向量中正确清理元素
- 指向并集的指针的向量.如何正确访问联合的元素?
- 在C++中使用矢量向量的正确方法是什么?
- 如果语句内部循环不读取完全正确的代表显示错误
- 计算Armadillo中复杂对称矩阵的有限特征向量的正确函数
- 是-!(condition)从布尔值(mask-boolean)中获得完整位向量的正确方法
- C++ 释放自定义类向量的正确方法
- 无法对结构C++中的向量进行正确的推回
- 累积没有给出我的向量的正确总和
- 多维向量的正确初始化
- 如何在<int>C++中正确传递向量以正确pthread_create?
- 传递向量的正确方法是什么?
- 链表冒泡排序并不完全正确
- c++中初始化结构体向量的正确方法
- 浮点精度——c++中的向量加法并不完全正确