C ++中的向量加法并不完全正确[重复]

     2023-02-16     180

关键词:

【中文标题】C ++中的向量加法并不完全正确[重复]【英文标题】:Vector addition in C++ is not coming out exactly right [duplicate] 【发布时间】:2014-05-04 13:04:57 【问题描述】:

我正在尝试在我的 C++ 程序中将一个向量添加到另一个向量,但结果不准确。

这是矢量类(使用 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。

第三个输出是2个大小相同的相反向量相加,本来应该是0,但不是这里显示的。

是什么导致了这些奇怪的添加,我如何使它们准确无误?

【问题讨论】:

我建议使用坐标 (x,y) 来轻松生活。 推荐使用双精度,不仅因为它更准确,而且大多数现代架构都针对双精度而非浮点数进行了优化 @LưuVĩnhPhúc 你知道使用doublefloat 更快的平台吗? Afaik 所有平台都支持两者,大多数仍然是 float 的两倍。并且float 的内存占用也只有double 的一半,因此在所有平台上使用float 的内存绑定计算将执行得更快。不过,我完全同意你应该将 double 用作默认值。 @cmaster 我听到很多人说他们看到 double 比 float 快。实际上我以前没有做过基准测试,但是这个网站上的大多数答案都表明现代平台上的双精度数至少与浮点数一样快。 ***.com/questions/1074474/…***.com/questions/4584637/… @LưuVĩnhPhúc 阅读链接上的答案,我找不到任何人声称双打 比浮动快。没错,因为那是错误的。在我知道的所有平台上,情况恰恰相反。但是我不了解所有平台,所以我不能排除这种疯狂的 CPU 比浮点数更快地加倍的可能性。因此,在某些(深奥的)平台上,双打可能可能更快。但这正是我的问题:您知道双打速度更快的特定平台吗? 【参考方案1】:

v1 + v3 几乎是0.0,代码运行正常。

为什么不完全是0.0

因为有些数字不能完全表示为双精度数。 一些解释见:C/C++: 1.00000 <= 1.0f = False。

另外:Pi 是一个irrational 数字,不能以自然数的任何基数精确表示。

因此,任何涉及 Pi 的计算都不会完全精确。

并且:sincossqrt 通常都是作为不返回完全精确结果的算法实现的,例如近似数值算法。

【讨论】:

我打算在您编辑帖子之前对此发表评论。此外,不建议使用这样的文字而不是 PI 常量 如果我错了请纠正我,但我认为sin & co。仅在您打开快速数学编译器标志时是近似值? @cmaster 我不知道它们在哪些库/使用哪些标志是近似的,但更快的实现之一是具有线性插值的表。 (这实际上不是近似的,但也不是完全精确的) @cmaster 我编辑了我的答案,使其更加准确。感谢您的意见。 @alain:为了迂腐,可以将 pi 准确地表示为 1 基 pi。【参考方案2】:

您遇到的基本问题是float 的精度有限和您正在使用的pi 的值之一。移动到double 会有所帮助,因为您已经包含&lt;cmath&gt;,您应该使用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 ++中的函数[重复]

】将指针向量传递给c++中的函数[重复]【英文标题】:Passavectorofpointerstofunctioninc++[duplicate]【发布时间】:2019-11-2916:54:33【问题描述】:我在这里看到了很多帖子,但没有一个能解释我想要做什么。我有向量vector&lt;Car*&gt;car... 查看详情

C中的算术级数不是正确的结果[重复]

】C中的算术级数不是正确的结果[重复]【英文标题】:NottherightresultwithArithmeticProgressioninC[duplicate]【发布时间】:2014-09-2820:41:53【问题描述】:我试图将数字(x0)的倍数与级数(r)和次数(n)相加。如果我使用数字x0=6,r=3,n=3,结果应该... 查看详情

用向量填充c ++中的简单动态数组[重复]

】用向量填充c++中的简单动态数组[重复]【英文标题】:fillasimpledynamicarrayinc++withvector[duplicate]【发布时间】:2018-11-0319:40:50【问题描述】:我正在尝试填充动态二维数组我哪里错了#include<vector>cin<<x;vector<vector<int>&... 查看详情

从基类c ++的向量中的派生类调用虚拟方法[重复]

】从基类c++的向量中的派生类调用虚拟方法[重复]【英文标题】:Callingvirtualmethodfromderivedclassinvectorofbaseclassc++[duplicate]【发布时间】:2013-07-0102:26:21【问题描述】:在BaseClass类中我有一个公共函数:virtualvoidCall();在派生类Archer内... 查看详情

如何标准化r中的向量[重复]

】如何标准化r中的向量[重复]【英文标题】:Howtonormalizeavectorinr[duplicate]【发布时间】:2021-05-1307:03:07【问题描述】:我有一个问题,我想规范化数据框中的一列,以使该列的标准差等于1。sd()函数只返回一个标准差值,但我想... 查看详情

如何在Mexfile中的matlab(矩阵,单元格)和c ++(向量或自定义类)之间正确转换变量

】如何在Mexfile中的matlab(矩阵,单元格)和c++(向量或自定义类)之间正确转换变量【英文标题】:Howtoconvertvariblescorrectelybetweenmatlab(matrix,cell)andc++(vectorsorself-definingclass)inMexfile【发布时间】:2018-08-0316:41:19【问题描述】:我刚... 查看详情

Vector中的C ++字符串输入[重复]

】Vector中的C++字符串输入[重复]【英文标题】:C++StringinputinVector[duplicate]【发布时间】:2021-03-2506:37:32【问题描述】:我想将多字串输入向量"name"。使用cin对于单字输入效果很好。我想要的是:获取用户输入的字符串数。例如:... 查看详情

C ++中的“in”列表等效项[重复]

】C++中的“in”列表等效项[重复]【英文标题】:"in"listequivalentinc++[duplicate]【发布时间】:2016-04-2710:09:17【问题描述】:假设我在C++中有一个向量v=(\'a\',\'e\',\'i\',\'o\',\'u\')。我想通过简单地检查字符是否在向量v中来检查... 查看详情

如何计算C中的内存消耗[重复]

】如何计算C中的内存消耗[重复]【英文标题】:HowtocalculatememoryconsumptioninC[duplicate]【发布时间】:2014-02-1605:27:37【问题描述】:有什么方法可以计算C中的内存消耗。我已经检查了***上的其他答案,但它们并不令人满意。类似于... 查看详情

C ++编译器错误中的简单类继承[重复]

】C++编译器错误中的简单类继承[重复]【英文标题】:simpleclassinheritanceinc++compilererrors[duplicate]【发布时间】:2013-12-0205:01:36【问题描述】:我希望我的Dog类正确继承Pet中的函数,以便main中的代码能够正确执行。编译器警告从基... 查看详情

C语言中的除法[重复]

】C语言中的除法[重复]【英文标题】:DivisioninClanguage[duplicate]【发布时间】:2021-12-1107:45:45【问题描述】:大家好,希望你们一切顺利,我是C语言的新手,我只需要问一个基本问题,即当我在C中像这样除数时:#include<stdio.h>... 查看详情

C中的RunLength解码[重复]

】C中的RunLength解码[重复]【英文标题】:RunLengthDecodinginC[duplicate]【发布时间】:2015-05-2615:35:20【问题描述】:这是我的运行长度解码程序。但是将输出作为垃圾值提供。char*decode_rle(char*a,intlength)方法中的输出是正确的,但是当... 查看详情

代码中的c ++ 2D向量push_back错误

】代码中的c++2D向量push_back错误【英文标题】:c++2Dvectorpush_backerrorincode【发布时间】:2014-07-2903:51:20【问题描述】:我让我的程序使用单个向量,并决定使用2D向量来表示多只手(一维向量vPlayerHand1加上一维向量vPlayerHand2加上...... 查看详情

计算所有组合减去向量的所有值[重复]

...的长度是可变的,我将返回所有元素的组合矩阵减去向量中的值像这样:[x_1][x_2][x_3][1,]345[2,]245[3,]145[4,]335[5,]325[6,]3 查看详情

C ++中的短无符号整数[重复]

】C++中的短无符号整数[重复]【英文标题】:ShortunsignedintinC++[duplicate]【发布时间】:2021-06-2413:44:49【问题描述】:所以在我的课堂考试中,我应该将X声明为短无符号。我宣布它是shortunsignedintX。这种方式仍然可以正确吗?谢谢... 查看详情

c ++如何从函数中的向量中删除对象

】c++如何从函数中的向量中删除对象【英文标题】:c++howtoremoveobjectsfromavectorinafunction【发布时间】:2013-12-1512:14:32【问题描述】:我想从向量中删除对象。向量通过引用传递,我迷路了。我已经尝试过brickList.erase(it)以及组合擦... 查看详情

关于向量空间的基本性质,与子空间的最最基本性质

...空间H是向量空间V的一个子集,并且满足三条性质:1、V中的零向量在空间H中2、H对向量加法封闭,即对于H中的任意向量,u,v,u+v仍然在H中3、H标量乘法封闭,即对于H 中的任意向量,v以及任意标量c,向量cv仍然在空间H中 例... 查看详情

C ++中的Lambda函数,参数和逻辑[重复]

】C++中的Lambda函数,参数和逻辑[重复]【英文标题】:Lambdafunction,argumentsandlogicinc++[duplicate]【发布时间】:2021-11-1623:47:34【问题描述】:我不熟悉在C++中使用lambda函数。我一直在研究网络,找到了几篇解释lambda函数的语法和用途... 查看详情