G ++编译器中的奇怪的隐式转换警告

我有这个功能可以从极谱表示法创建一个在其中使用支撑初始化程序的向量:

// Constructs a 2D vector from XY-coordinates.
inline vector2(float x, float y) : x_(x), y_(y) { }

// Constructs a 2D vector from polar coordinates
static vector2 polar(float r, float phi) {
    return {r * cos(phi), r * sin(phi)};
}

在MSVS中,一切似乎都很好,但是g ++编译器显示的警告对我来说似乎很奇怪:

vector2.h:37:23: warning: narrowing conversion of ‘(((double)r) * cos(((double)phi)))’ from ‘double’ to ‘float’ inside { } [-Wnarrowing]
             return {r * cos(phi), r * sin(phi)};
                     ~~^~~~~~~~~~

如果我使用构造函数,警告消失:

// Constructs a 2D vector from polar coordinates
static vector2 polar(float r, float phi) {
    return vector2(r * cos(phi), r * sin(phi));
}

Why does this warning appear? Does it mean that a compiled program will do an unnecessary conversion from float to double and back to float?

评论
  • 背后的孤独
    背后的孤独 回复

    You are not using the correct cos and sin

    #include <cmath>
    
    class vector2 {
    public:
    float x_, y_;
    // Constructs a 2D vector from XY-coordinates.
    inline vector2(float x, float y) : x_(x), y_(y) { }
    };
    
    // Constructs a 2D vector from polar coordinates
    static vector2 polar(float r, float phi) {
        return {r * std::cos(phi), r * std::sin(phi)};
    }
    

    Using the std::cos and std::sin gives the correct result as they are overload like this:

    double cos (double x);
    float cos (float x);
    long double cos (long double x);
    double cos (T x);           // additional overloads for integral types
    
  • 蜡笔小舅@
    蜡笔小舅@ 回复

    Judging from the warning you present it seems that you are using a cos() whose return type is double (8 bytes usually), so when you use it's result in an arithmetic operation with a float (4 bytes usually) the implicit conversion is from float to double (smaller to bigger type).

    If you then store it in a float there is an implicit conversion from a bigger type to a smaller type with possible data loss, hence the warning.

    由于我们没有您的全部代码,因此很难确定,但这似乎是事实。

    #include <iostream>
    #include <cmath>
    
    using std::cout, std::endl, std::cos; // (C++17 comma separated)
    
    int main(){
        float x = 2.0;
    
        cout << sizeof(float) << endl;  // 4
        cout << sizeof(double) << endl << endl; // 8
    
        auto y = cos(20) * x;  // overloaded --> double cos (double x(conversion)); C++11
        float d = cos(20) * x;  // overloaded --> float cos (float x); C++11
    
        cout << sizeof(y) << endl;  // 8
        cout << sizeof(d) << endl;  // 4
    }
    

    在这里一切正常,调用适当的重载函数,在您看来,这似乎没有发生。

  • yyzs1995
    yyzs1995 回复

    如果您发布整个源代码,将很有帮助。

    根据您发布的内容,我假设您没有类似的内容

    using namespace std;
    

    So cos() and sin() are the old C versions. They both expect an input of type double. cosf() and sinf() are the function expecting a float. Since you are using c++ you want to use the STL functions and not the old C ones.

    所以做以下

    static vector2 polar(float r, float phi) {
        return {r * std::cos(phi), r * std::sin(phi)};
    }
    

    STL函数是重载,因此它们将float和double作为输入,而没有任何隐式转换。