0

モジュラスを計算する関数を実装しようとしている複素数クラスがあります(これにはsqrtを使用する必要があります)。

私のヘッダーファイルは次のとおりです。

#ifndef MY_CLASS_H
#define MY_CLASS_H

template <class T> class complex
{
    // function to overload operator<< a friend
    template <class T>
    friend std::ostream& operator<< (std::ostream &os, const complex<T> &z);
private:
    T re,im;
public:

    // Constructors & destructor
    complex(){re=im=0;}
    complex( const T& r, const T& i ) : re(r), im(i) {}
    ~complex(){}

    // Return real component
    T realcomp() const {return re;}
    // Return imaginary component
    T imagcomp() const {return im;}
    // Return modulus
    double modulus() {return sqrt(im*im + re*re);}

etc....

コンパイラはエラーを出力します:

error C2668: 'sqrt' : ambiguous call to overloaded function
 could be 'long double sqrt(long double)'
 or       'float sqrt(float)'
 or       'double sqrt(double)'

sqrt私が知っていることは、それが通過しているデータのタイプを知る必要があることを私に伝えています。

私のプログラムでは、imまたはのいずれかの値reを取ります。doubleint

sqrtは浮動小数点値のみを取ると言っているのは正しいですか?もしそうなら、どうすれば「データの損失」の警告なしにimとreをフローティングポイントに強制できますか。それらを変換せずにこれを行うことはできますか?

4

6 に答える 6

2

いいえ、sqrtは通常フロートを取りません。必要なものはライブラリによって異なります。あなたの場合、いくつかのオーバーロードされたsqrt関数があり、1つは、、1つは、、floatもうdouble1つはを取りますlong double

あなたが抱えている問題は、それらのどれも取らないことintであり、intからあなたが使用できるタイプへの複数の変換があるので、コンパイラはあなたに(キャストによって)選択させます。doubleまたはのみを使用している場合はint、-にキャストしdoubleます。プレシジョンが失われることはありません。long doubleある時点で使用したい場合は、それにキャストします。

double modulus() {return sqrt((double)im*im + re*re);}
于 2012-04-13T17:29:35.607 に答える
1

いくつかの解決策がありますが、最初に、コードに問題があります。関数sqrtはどこから来ているのですか。ユーザーにが含まれている場合は 、バージョンのみを取得<sqrt.h>する必要があり、あいまいさはありません。doubleユーザーがを含む場合、 C ++ 11より前では、コードは;<csqrt>を見つけることができません。sqrt実際には、これを正しく実装したコンパイラはなく、何が得られるかは実装によって異なります。

最も安全な解決策は、独自の特別な名前空間を宣言し、インクルードし、必要なもの<csqrt>を定義し、それらの実装で使用して、名前空間で を呼び出すことです。sqrtstd::sqrtsqrt

#include <csqrt>

namespace SafetyFirst
{
    inline int
    sqrt( int in )
    {
        return static_cast<int>( std::sqrt( static_cast<double>( in ) ) );
    }

    inline double
    sqrt( double in )
    {
        return std::sqrt( in ) ;
    }

    //  And so on for any other types you might need.  The
    //  standard provides std::sqrt for the floating point
    //  types only.
}

このように、過負荷解決は常に完全に一致するものを見つけ、実際に必要な機能を正確に決定します。また、クライアントが使用できる可能性のある新しい数値型を定義する方法があります。sqrt同じ名前空間で定義するだけで、おそらく型と同じ名前空間の実装に転送されます。

または、次のことを行うことができます。

#include <cmath>    // To ensure getting a fixed set of overloads
using std::sqrt;

inline int
sqrt( int in )
{
    return static_cast<int>( std::sqrt( static_cast<double>( in ) ) );
}

//  And so on for any standard integral types you want...
//  And your class here...

クライアント定義型の場合、ADLはコンパイラーが正しい名前空間を検索することを保証するため、名前空間に転送機能を提供する必要はありません。

これは、グローバル名前空間での検索を予期していないクライアントコードを台無しにする可能性があることを除いて、実際にはかなり優れたソリューションです。std::sqrt( float )(このようなコードは移植性がありませんが、一部のプラットフォームに存在する可能性があります。)

于 2012-04-13T17:45:22.173 に答える
0

これを試して:

double modulus() {return sqrt((double)im*im + re*re);}

あなたはいつもdouble sqrt(double)この方法で呼び出すでしょう、しかしあなたの説明を考えれば、それはおそらく大丈夫です。

于 2012-04-13T17:23:31.983 に答える
0

この問題は、sqrtの関数呼び出しのあいまいな入力が原因で発生します。sqrt関数には、floatまたはdoubleのいずれかの異なる入力パラメーター(オーバーロード関数)があります。

私は非常によく似た問題を抱えています:私が書いた最初のコードで:

    #include <iostream>     // std::cout
    #include <cmath>    // std::sqrt

   int main()
    {
      float ss;
      ss= std::sqrt(120);  //in this line compiler not sure 120 is float or double
      std::cout<<ss;
      std::cin>>ss;
      return 0;
    } 

このコードでは、コンパイラはパラメータがfloatまたはdoubleかどうかわからない

次のように、floatまたはdoubleのいずれかのパラメーターのタイプを確認するために、コードを修正することができます。

    #include <iostream>     // std::cout
    #include <cmath>    // std::sqrt

    int main()
    {
      float ss;  //you can change to double 
      ss=120;    //this line make compiler sure 120 is float 
      ss=std::sqrt(ss); //in this line compiler sure that sqrt function 
      std::cin>>ss;
      return 0;
    }
于 2013-08-14T07:59:42.497 に答える
0

ここでは少し遅れるかもしれませんが、コンパイラが適切な関数を選択できるように、テンプレートから助けを得ました。

#ifndef SQUARE_ROOT_HPP
#define SQUARE_ROOT_HPP

#include <cmath>

template<typename Scalar>
Scalar square_root(Scalar value)
{
    return square_root(static_cast<double>(value));
}

template<>
float square_root(float value)
{
    return std::sqrt(value);
}

template<>
double square_root(double value)
{
    return std::sqrt(value);
}

template<>
long double square_root(long double value)
{
    return std::sqrt(value);
}

#endif // SQUARE_ROOT_HPP
于 2017-01-04T07:23:02.997 に答える
0

私の問題も同様でした。古いソースを拡張して、mprealの追加使用に適合させるようにしています。これは厄介な作業です。最後の問題の1つ:大きなテンプレートの小さなステートメント:

`T help = sqrt(g.eval(f.eval(a))());`

私は苦労しなければなりませんでした..私が試したものは何でも失敗しました-非常に異なるエラーメッセージ、複雑な平方根からの違法な変換のように、いくつかはクレイジーに見えますが、私はフロートタイプのみを使用しました。mprealをlongdoubleに変換して精度を捨てます。 特にTがlongdoubleの場合、then-それぞれのelse-partでstd::とmpfr::を使用すると、誤解を招くエラーメッセージが表示され、Tに応じてthen-またはelse-partで解決できないタイプエラーが発生していましたif(std::is_floating_point<T>::value) ..if(std::is_same<T,long double>::value) ..

私はここで解決策を見つけたでしょう-もし私が自分の問題の原因を知っていれば...

私の解決策:

inline long double wurz(long double x) { return std::sqrt(x); };
inline mpreal wurz(mpreal x) { return sqrt(x); };

template<class T>
  ....
  real_word helpa2 = wurz(g.eval(f.eval(a))());

私がこのページを見つけたのは、私よりも自然で愚かな解決策があるかどうかを尋ねたいときです。

于 2017-07-06T21:39:22.733 に答える