エラーの原因が分かりません。お願い致します

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
わんこ君
記事: 4
登録日時: 10年前

エラーの原因が分かりません。お願い致します

#1

投稿記事 by わんこ君 » 10年前

現在、linuxを使ってフーリエ変換のプログラムを書こうとしています。コードをすべて書き終えてコンパイルしようとした所、
g++ -std=c++0x -Wall -O3 -lm m_source.cpp Math.o FT.o -o m_source
FT.o: In function `FFTmix::bfy(Complex*, Complex*, int, int, int)':
FT.cpp:(.text+0x5ca): undefined reference to `Complex& operator/=<int>(Complex&, int)'
FT.o: In function `FFTof2::bfy(std::vector<std::vector<Complex, std::allocator<Complex> >, std::allocator<std::vector<Complex, std::allocator<Complex> > > >&, std::vector<std::vector<Complex, std::allocator<Complex> >, std::allocator<std::vector<Complex, std::allocator<Complex> > > >&)':
FT.cpp:(.text+0x8b5): undefined reference to `Complex operator*<double>(double, Complex)'
FT.cpp:(.text+0xa45): undefined reference to `Complex operator*<double>(double, Complex)'
FT.o: In function `DFTof2::bfy(std::vector<std::vector<Complex, std::allocator<Complex> >, std::allocator<std::vector<Complex, std::allocator<Complex> > > >&, std::vector<std::vector<Complex, std::allocator<Complex> >, std::allocator<std::vector<Complex, std::allocator<Complex> > > >&)':
FT.cpp:(.text+0xec2): undefined reference to `Complex& operator/=<int>(Complex&, int)'
collect2: エラー: ld はステータス 1 で終了しました
make: *** [m_source] エラー 1

の様なエラーが発生しました。
Math.h内にある"Complexクラス"のoperatorはこのエラー以外全て機能しています。どうすればよろしいのでしょうか?
以下がコードになります。

~Math.h~

コード:

#ifndef _MATH_H_
#define _MATH_H_

#include <iostream>
#include <cmath>

class Complex {

    friend Complex operator+(const Complex,const Complex);
    friend Complex operator-(const Complex,const Complex);
    template <typename T>
    friend Complex operator*(const T,const Complex);
    friend Complex operator*(const Complex,const Complex);
    template <typename T>
    friend Complex operator/(const T,const Complex);
    friend Complex operator/(const Complex,const Complex);
    
    friend Complex& operator+=(Complex&,const Complex);
    friend Complex& operator-=(Complex&,const Complex);
    template <typename T>
    friend Complex& operator*=(Complex&,const T);
    friend Complex& operator*=(Complex&,const Complex);
    template <typename T>
    friend Complex& operator/=(Complex&,const T);
    friend Complex& operator/=(Complex&,const Complex);
    
    friend bool operator==(const Complex,const Complex);
    friend bool operator!=(const Complex,const Complex);
    friend std::ostream& operator<<(std::ostream&,const Complex&);

public:
    double Re,Im;

    template <typename T,typename U>
    Complex(const T t_Re,const U t_Im):Re(static_cast<double>(t_Re)),Im(static_cast<double>(t_Im)) { };
    template <typename T>
    explicit Complex(const T t_Re):Re(static_cast<double>(t_Re)),Im(0.0) { };
    Complex(void):Re(0.0),Im(0.0) { };
    
    template <typename T,typename U>
    void set(const T,const U);
    /*
     * calculate r and theta
     * r=sqrt(Re^2+Im^2), theta=atan(Im/Re)
     */
    double abs();
    double arg();
};  
~Math.cpp~

コード:

#include "../header/Math.h"

Complex operator+(const Complex a,const Complex b) {

    return Complex(a.Re+b.Re,a.Im+b.Im);
};
Complex operator-(const Complex a,const Complex b) {

    return Complex(a.Re-b.Re,a.Im-b.Im);
};
template <typename T>
Complex operator*(const T N,const Complex a) {

    return Complex(a.Re*N,a.Im*N);
};
Complex operator*(const Complex a,const Complex b) {

    return Complex(a.Re*b.Re-a.Im*b.Im,a.Re*b.Im+b.Re*a.Im);
};
template <typename T>
Complex operator/(const T N,const Complex a) {

    return (1/N)*a;
};
Complex operator/(const Complex a,const Complex b) {

    double r=pow(const_cast<Complex&>(b).abs(),2);
    return Complex((a.Re*b.Re+a.Im*b.Im)/r,(a.Re*(-b.Im)+b.Re*a.Im)/r);
};

Complex& operator+=(Complex& a,const Complex b) {

    a=a+b;
    return a;
};
Complex& operator-=(Complex& a,const Complex b) {

    a=a-b;
    return a;
};
template <typename T>
Complex& operator*=(Complex& a,const T N) {

    a=a*N;
    return a;
};
Complex& operator*=(Complex& a,const Complex b) {

    a=a*b;
    return a;
};
template <typename T>
Complex& operator/=(Complex& a,const T N) {

    a=a/N;
    return a;
};
Complex& operator/=(Complex& a,const Complex b) {

    a=a/b;
    return a;
};

bool operator==(const Complex a,const Complex b) {

    return ((a.Re==b.Re&&a.Im==b.Im)? true:false);
};
bool operator!=(const Complex a,const Complex b) {

    return !(a==b);
};
std::ostream& operator<<(std::ostream& os,const Complex& a) {

    os<< a.Re <<" "<< a.Im;
    return os;
};

template <typename T,typename U>
void Complex::set(const T t_Re,const U t_Im) {

    Re=static_cast<double>(t_Re),Im=static_cast<double>(t_Im);
};

/*
 * calculate r and theta
 * r=sqrt(Re^2+Im^2), theta=atan(Im/Re)
 */
double Complex::abs(void) {

    return sqrt(pow(Re,2)+pow(Im,2));
};
double Complex::arg(void) {

    return atan2(Im,Re);
}; 
~FT.h~

コード:

#include <vector>
#include "./Math.h"

//Fourier Transformation on 1D
class DFT {
public:
    void bfy(Complex*,Complex*,int);
};

class FFTmix {
private:
    std::vector<Complex> tmp;
public:
    FFTmix(void) {
        tmp.clear();
    };

    void bfy(Complex*,Complex*,int,int,int);
};

//Fourier Transformation on 2D
class DFTof2 {
private:
    std::vector<Complex> tmp,in,out;
public:
    DFTof2(void) {
        tmp.clear(),in.clear(),out.clear();
    };

    void bfy(std::vector<std::vector<Complex> >&,std::vector<std::vector<Complex> >&);
};

class FFTof2 {
private:
    std::vector<Complex> ttmp,tmp,dat;
public:
    FFTof2(void) {
        ttmp.clear(),tmp.clear(),dat.clear();
    };

    void bfy(std::vector<std::vector<Complex> >&,std::vector<std::vector<Complex> >&);
};

//calculate W using Fourier Transformation
Complex W(const int,const int);
~FT.cpp~

コード:

#include <cstring>
#include "../header/FT.h"

//Fourier Transformation on 1D
void DFT::bfy(Complex in[],Complex out[],int ALL) {

    for(int i=0;i<ALL;++i) {
        for(int j=0;j<ALL;++j) out[i]+=W(-i*j,ALL)*in[j];
    }
};

void FFTmix::bfy(Complex in[],Complex out[],int N,int n,int ALL) {

    if(N<=1) return;
    else if(N==ALL) tmp.resize(N,Complex());

    int width=2,height;
    while(N>=pow(width,2)) {
        if(N%width==0) break;
        ++width;
    }
    if(N%width!=0) width=N;
    height=N/width;

    for(int h=0;h<height;++h) {
        for(int w=0;w<width;++w) {
            Complex buf=Complex();
            for(int r=0;r<N;r+=height) buf+=in[h+r]*W(-w*r,n);
            out[height*w+h]=buf*W(-h*w,n);
        }
    }
    for(int r=0;r<N;r+=height) bfy(&out[r],in,height,n/width,ALL);

    if(N==ALL) {
        for(int h=0;h<height;++h) {
            for(int w=0;w<width;++w) {
                out[height*w+h]/=N;
            }
        }
    } else {
        for(int h=0;h<height;++h) {
            for(int w=0;w<width;++w) {
                in[width*h+w]=out[height*w+h];
            }
        }
    }
};

//Fourier transformation on 2D
void DFTof2::bfy(std::vector<std::vector<Complex> >& t_in,std::vector<std::vector<Complex> >& t_out) {

    int ALL_x=t_in.size(),ALL_y=t_in[0].size();

    tmp.resize(ALL_x*ALL_y,Complex()),in.resize(ALL_x*ALL_y,Complex()),out.resize(ALL_x*ALL_y,Complex());
    for(int i=0;i<ALL_x;++i) {
        for(int j=0;j<ALL_y;++j) in[j+i*ALL_y]=t_in[i][j];
    }
    
    int x,y,u=0,v=0;
    for(Complex& val1:out) {
        x=y=0;
        for(Complex val2:in) {
            tmp[v+x*ALL_y]+=W(-v*y,ALL_y)*val2,++y;
            if(y==ALL_y) y=0,++x;
        }
        for(x=0;x<ALL_x;++x) val1+=W(-u*x,ALL_x)*tmp[v+x*ALL_y];
        val1/=ALL_x*ALL_y;
    }
};

void FFTof2::bfy(std::vector<std::vector<Complex> >& in,std::vector<std::vector<Complex> >& out) {

    int ALL_x=in.size(),ALL_y=in[0].size();
    FFTmix FFT;

    tmp.resize(ALL_x*ALL_y,Complex()),dat.resize(ALL_x,Complex());
    for(int y=0;y<ALL_y;++y) {
        ttmp.resize(ALL_x,Complex());
    
        for(int x=0;x<ALL_x;++x) dat[x]=in[x][y];
        FFT.bfy(&dat[0],&ttmp[0],ALL_x,ALL_x,ALL_x);
        for(int u=0;u<ALL_x;++u) tmp[y+u*ALL_y]=1.0/ALL_x*ttmp[u];
    }
    dat.resize(ALL_y,Complex());
    for(int u=0;u<ALL_x;++u) {
        ttmp.resize(ALL_y,Complex());
    
        for(int y=0;y<ALL_y;++y) dat[y]=tmp[y+u*ALL_y];
        FFT.bfy(&dat[0],&ttmp[0],ALL_y,ALL_y,ALL_y);
        for(int v=0;v<ALL_y;++v) out[u][v]=1.0/ALL_y*ttmp[v];
    }
};

//calculate W using Fourier Transformation
Complex W(const int n,const int N) {

    double Re=cos((n%N)*2*M_PI/N),Im=sin((n%N)*2*M_PI/N);
    Re=((fabs(static_cast<double>(Re))<pow(10.0,-15))? 0.0:Re),
        Im=((fabs(static_cast<double>(Im))<pow(10.0,-15))? 0.0:Im);
    return Complex(Re,Im);
};
~m_source.cpp~

コード:

#include "../header/FT.h"

int main(int argv,char** argc) {

    Complex in[10]={Complex(1,0)},out[10]={Complex()};
    DFT DFT;

    DFT.bfy(&in[0],&out[0],10);

    for(Complex& val:out) std::cout<< val <<std::endl;

    return 0;
} 

sleep

Re: エラーの原因が分かりません。お願い致します

#2

投稿記事 by sleep » 10年前

1つ例を挙げると
わんこ君 さんが書きました: template <typename T>
Complex& operator/=(Complex& a,const T N) {

a=a/N;
return a;
};
仮に T が int型だとして
Complex / int の式を計算する / の operator は定義されていませんよね?
そういう Complex と T を使用した 計算があちこちで記述されているので
どうやって計算すれば良いのか定義されていないので分かりませんよ、と言われています。

Complex と T(に当てはまる予定の型。上記の例で言うと int) の計算をどうやって行えば良いのか、定義してやれば解決できます。

sleep

Re: エラーの原因が分かりません。お願い致します

#3

投稿記事 by sleep » 10年前

あと、複素数クラス(complex)は、C++の標準ライブラリにありますよ。

わんこ君
記事: 4
登録日時: 10年前

Re: エラーの原因が分かりません。お願い致します

#4

投稿記事 by わんこ君 » 10年前

sleep さんが書きました:1つ例を挙げると
わんこ君 さんが書きました: template <typename T>
Complex& operator/=(Complex& a,const T N) {

a=a/N;
return a;
};
仮に T が int型だとして
Complex / int の式を計算する / の operator は定義されていませんよね?
そういう Complex と T を使用した 計算があちこちで記述されているので
どうやって計算すれば良いのか定義されていないので分かりませんよ、と言われています。

Complex と T(に当てはまる予定の型。上記の例で言うと int) の計算をどうやって行えば良いのか、定義してやれば解決できます。
わかりました、ありがとうございました。書き直し次第投稿しようと思います。
後、Complexがあるのは知っているのですが練習を兼ねて作成をしています。説明不足で申し訳ありません

わんこ君
記事: 4
登録日時: 10年前

Re: エラーの原因が分かりません。お願い致します

#5

投稿記事 by わんこ君 » 10年前

結局templateを使ったoperatorの定義がうまく出来ず(*は定義できても*=が定義出来なかったり)だったので、全て複素数で扱うことで終結させました。

コード:

class Complex {

    friend Complex operator+(const Complex,const Complex);
    friend Complex operator-(const Complex,const Complex);
    friend Complex operator*(const Complex,const Complex);
    friend Complex operator/(const Complex,const Complex);
    
    friend Complex& operator+=(Complex&,const Complex);
    friend Complex& operator-=(Complex&,const Complex);
    friend Complex& operator*=(Complex&,const Complex);
    friend Complex& operator/=(Complex&,const Complex);
    
    friend bool operator==(const Complex,const Complex);
    friend bool operator!=(const Complex,const Complex);
    friend std::ostream& operator<<(std::ostream&,const Complex&);

public:
    double Re,Im;

    template <typename T>
    Complex(const T t_Re,const T t_Im=0):Re(static_cast<double>(t_Re)),Im(static_cast<double>(t_Im)) { };
    Complex(void):Re(0.0),Im(0.0) { };

    /*
     * calculate r and theta
     * r=sqrt(Re^2+Im^2), theta=atan(Im/Re)
     */
    double abs();
    double arg();
};
templateを使ったいい方法を知っている方がいらっしゃいましたら、教えていただけたら嬉しいです

sleep

Re: エラーの原因が分かりません。お願い致します

#6

投稿記事 by sleep » 10年前

operator* が定義できれば、operator*= は定義できるはずなので
どう上手くいかなかったのか、と
いい方法、の定義がよく分からないため、話が見えませんが
sampleを載せておきます。
(結局 doubleで計算しているだけなので、templeteを使用する必要は無いような・・・)

コード:

#include <iostream>

struct A
{
	double x, y;

/*
	A operator*(const double N)
	{
		return { x * N, y * N };
	}
	template<typename T>
	friend A operator*(const T N, const A a)  //「const A a」の const が原因。外せば良い。
	{
		return a * N;
	}
*/
	friend A operator*(const A a, const double N)  //friend にし、A を const で受け取るようにする
	{
		return{ a.x * N, a.y * N };
	}
	template<typename T>
	friend A operator*(const T N, const A a)  //上記の簡易対応をすれば、const が付与されていても問題ない。
	{
		return a * N;
	}

	template<typename T>
	friend A operator*=(A& a, const T N)
	{
		a = a * N;
		return a;
	}
};

int main()
{
	A a = { 1, 2 };
	std::cout << a.x << " " << a.y << std::endl;

	a = a * 2;
	std::cout << a.x << " " << a.y << std::endl;

	a = 5 * a;
	std::cout << a.x << " " << a.y << std::endl;

	a *= 3;
	std::cout << a.x << " " << a.y << std::endl;

	return 0;
}

ISLe()

Re: エラーの原因が分かりません。お願い致します

#7

投稿記事 by ISLe() » 10年前

テンプレート関数の本体の定義をcppファイルに書いているのがいけないのでは?

sleep

Re: エラーの原因が分かりません。お願い致します

#8

投稿記事 by sleep » 10年前

これは失礼しました。

ISLeさん、ありがとうございます。
コメントを見て気付きました。
定義の中身に誤りは無かったので、その時点で意識から外れて別のことが原因だと思い込んでしまった様です。
これは完全に私の見落としですね。

そして、わんこ君さん 申し訳ないです。
私の指摘も修正点の1つではあるのですが、初回に掲示いただいたエラーの原因は ISLeさんのおっしゃってるとおりですね。

わんこ君
記事: 4
登録日時: 10年前

Re: エラーの原因が分かりません。お願い致します

#9

投稿記事 by わんこ君 » 10年前

sleep さんが書きました:これは失礼しました。

ISLeさん、ありがとうございます。
コメントを見て気付きました。
定義の中身に誤りは無かったので、その時点で意識から外れて別のことが原因だと思い込んでしまった様です。
これは完全に私の見落としですね。

そして、わんこ君さん 申し訳ないです。
私の指摘も修正点の1つではあるのですが、初回に掲示いただいたエラーの原因は ISLeさんのおっしゃってるとおりですね。
ISLeさん、sleepさん、ありがとうございました。
そういうことだったのですね、次から気をつけたいと思います。

sleep

Re: エラーの原因が分かりません。お願い致します

#10

投稿記事 by sleep » 10年前

ちなみにtemplate関数の宣言と定義を別ファイルにする方法がまったく無いわけではありません。
ただ、いつまで通用するか分からないですけどね。

Math.cpp から template関数の定義 を抽出して別ファイル(Math_template.cpp)とし
Math.h のclass定義の下でそのファイルをincludeさせれば、プロトタイプ宣言などで型を明示してインスタンス化させなくても 別ファイルにすることは可能です。
(※Math_template.cpp に Math.hをincludeさせる必要はありません。また、Math_template.cpp の拡張子は何でも構いません。注意点としてこのファイルはコンパイル単位とすることはできません)

g++ -std=c++11 -Wall -O3 -lm -c Math.cpp
g++ -std=c++11 -Wall -O3 -lm -c FT.cpp
g++ -std=c++11 -Wall -O3 -lm m_source.cpp Math.o FT.o -o m_source

Math.h

コード:

#ifndef _MATH_H_
#define _MATH_H_

#include <iostream>
#include <cmath>

class Complex {
...  //宣言の中身は元と一緒
};

#include "Math_template.cpp"   //ここで template関数の定義ファイルを includeしてやる

#endif
Math_template.cpp (Math_template.h でも Math_template.hpp でも 拡張子は何でも良い)

コード:


template <typename T>
Complex operator*(const T N, const Complex a) {

	return Complex(a.Re*N, a.Im*N);
};

template <typename T>
Complex operator/(const T N, const Complex a) {

	return (1 / N)*a;
};

template <typename T>
Complex& operator*=(Complex& a, const T N) {

	a = a*N;
	return a;
};

template <typename T>
Complex& operator/=(Complex& a, const T N) {

	//a = a / N;   //Complex& operator/(Complex& a, const T N) を定義する必要あり
	return a;
};

template <typename T, typename U>
void Complex::set(const T t_Re, const U t_Im) {

	Re = static_cast<double>(t_Re), Im = static_cast<double>(t_Im);
};
Math.cpp

コード:

#include "../header/Math.h"

Complex operator+(const Complex a, const Complex b) {

	return Complex(a.Re + b.Re, a.Im + b.Im);
};
Complex operator-(const Complex a, const Complex b) {

	return Complex(a.Re - b.Re, a.Im - b.Im);
};
Complex operator*(const Complex a, const Complex b) {

	return Complex(a.Re*b.Re - a.Im*b.Im, a.Re*b.Im + b.Re*a.Im);
};
Complex operator/(const Complex a, const Complex b) {

	double r = pow(const_cast<Complex&>(b).abs(), 2);
	return Complex((a.Re*b.Re + a.Im*b.Im) / r, (a.Re*(-b.Im) + b.Re*a.Im) / r);
};

Complex& operator+=(Complex& a, const Complex b) {

	a = a + b;
	return a;
};
Complex& operator-=(Complex& a, const Complex b) {

	a = a - b;
	return a;
};
Complex& operator*=(Complex& a, const Complex b) {

	a = a*b;
	return a;
};
Complex& operator/=(Complex& a, const Complex b) {

	a = a / b;
	return a;
};

bool operator==(const Complex a, const Complex b) {

	return ((a.Re == b.Re&&a.Im == b.Im) ? true : false);
};
bool operator!=(const Complex a, const Complex b) {

	return !(a == b);
};
std::ostream& operator<<(std::ostream& os, const Complex& a) {

	os << a.Re << " " << a.Im;
	return os;
};

/*
* calculate r and theta
* r=sqrt(Re^2+Im^2), theta=atan(Im/Re)
*/
double Complex::abs(void) {

	return sqrt(pow(Re, 2) + pow(Im, 2));
};
double Complex::arg(void) {

	return atan2(Im, Re);
};
あと、

コード:

return (1 / N)*a;
この計算は N が int型だと(N が 1 以外の場合) 0 となってしまうので注意が必要です。
先に計算される 1 と N が整数で扱われ、小数点以下が切り捨てとなるためです。

閉鎖

“C言語何でも質問掲示板” へ戻る