PDA

View Full Version : راهنمایی برای استفاده از template



ehsan_faal
یک شنبه 01 شهریور 1394, 21:59 عصر
سلام دوستان.
بنده کدی به زبان متلب داشتم و بنا به دلایلی مجبورم توی ++C هم پیاده سازیش کنم.منتها از اون جایی که خیلی از توابعی که توی متلب بود رو خودم بایستی پیاده سازی کنم حجم کد خیلی زیاد میشه که برای جلوگیری از این حجم زیاد خواستم از template استفاده کنم که ظاهرا باید جزئیات زیادی رو ازش بدونم.
حالا من در آخرای کار هستم.یکبار کد رو به پایتون تبدیل کردم تا ریزه کاریهای مربوط به اندیس آرایه ها با ++C همخوانی داشته باشه.
حالا همون کد رو میخوام توی ++C بنویسم. برای نمونه این کد پایتون که پیچیده ترین قسمت کار من رو شامل میشه رو هنوز نتونستم توی ++C بیارمش:

def impedanceCreator(Ns,Ds,N):
Sections = int((N+1)/2)
oldABCD = np.zeros((2,2),dtype = np.ndarray)
oldABCD[0,0] = evenIndex(list(map(add,Ns,Ds)))[::-1]
oldABCD[0,1] = oddIndex(list(map(add,Ns,Ds)))[::-1]
oldABCD[1,0] = oddIndex(list(map(sub,Ds,Ns)))[::-1]
oldABCD[1,1] = evenIndex(list(map(sub,Ds,Ns)))[::-1]
Z = [0]*(Sections)
Z[0] = (polyval(1,oldABCD[0,0])/polyval(1,oldABCD[1,0])).real
tempMatrix = np.ones((2,2),dtype = np.ndarray)
newABCDmatrix = np.zeros((2,2),dtype = np.ndarray)
for index in range(1,Sections):
tempMatrix[0,1] = [0,-Z[index-1]]
tempMatrix[1,0] = [0,-1/Z[index-1]]
newABCDmatrix[0,0] = polydiv(polyadd(oldABCD[0,0],polymul(tempMatrix[0,1],oldABCD[1,0])),[1,0,-1])[0]
newABCDmatrix[0,1] = polydiv(polyadd(oldABCD[0,1],polymul(tempMatrix[0,1],oldABCD[1,1])),[1,0,-1])[0]
newABCDmatrix[1,0] = polydiv(polyadd(polymul(tempMatrix[1,0],oldABCD[0,0]),oldABCD[1,0]),[1,0,-1])[0]
newABCDmatrix[1,1] = polydiv(polyadd(polymul(tempMatrix[1,0],oldABCD[0,1]),oldABCD[1,1]),[1,0,-1])[0]
oldABCD[0,0] = newABCDmatrix[0,0]
oldABCD[0,1] = newABCDmatrix[0,1]
oldABCD[1,0] = newABCDmatrix[1,0]
oldABCD[1,1] = newABCDmatrix[1,1]
Z[index] = (polyval(1,newABCDmatrix[0,0])/polyval(1,newABCDmatrix[1,0])).real
return Z

کد معادلش تقریبا این میشه :

#include <iostream>
#include "armadillo"
using namespace std;
using namespace arma;

enum class state
:char {
EvenMode, OddMode
};
enum class ComplexOrOrdinary
:char {
ComplexNumber, OrdinaryNumber
};
enum class VectorType
:char {
ComplexType, OrdinaryType
};
template<typename T>
auto polyval(const T &input, const double& Target,
const VectorType& WhichType)->decltype(input(0)) {
//using filter algorithm from matlab:
const size_t top = input.size();
Col<decltype(input(0))> result(top);
if (WhichType == VectorType::ComplexType) {
result(0) = input(0);
for (size_t counter = 1; counter < top; counter++) {
result(counter) -= (-Target) * result(counter - 1);
result(counter) += input(counter);
}
} else if (WhichType == VectorType::OrdinaryType) {
result(0) = input(0);
for (size_t counter = 1; counter < top; counter++) {
result(counter) -= (-Target) * result(counter - 1);
result(counter) += input(counter);
}
}
return result(top - 1);
}
template<typename T>
auto getDegree(const T& polynomial, const ComplexOrOrdinary& Mood) ->int {
size_t degree { 0 };
if (Mood == ComplexOrOrdinary::OrdinaryNumber) {
degree = polynomial.n_elem - 1;
if (polynomial(degree).real() == 0) {
while (polynomial(degree).real() == 0) {
degree--;
}
}
} else if (Mood == ComplexOrOrdinary::ComplexNumber) {
degree = polynomial.n_elem - 1;
if (polynomial(degree).real() == 0) {
while (polynomial(degree).real() == 0) {
degree--;
}
}
}
return degree;
}
template<typename T>
auto shiftPolynomial(const T& input, const int& howMuch,
const VectorType& WhichType) ->T {
if (WhichType == VectorType::ComplexType) {
if (howMuch > 0) {
vector<complex<double>> tmp(input.n_elem);
for (size_t index = 0; index < howMuch; index++) {
tmp[index] = 0.0;
}
for (size_t index = howMuch; index < tmp.size(); index++) {
tmp[index] = input(index - howMuch);
}
return cx_vec { tmp };
} else {
return input;
}
} else if (WhichType == VectorType::OrdinaryType) {
if (howMuch > 0) {
vector<double> tmp(input.n_elem);
for (size_t index = 0; index < howMuch; index++) {
tmp[index] = 0.0;
}
for (size_t index = howMuch; index < tmp.size(); index++) {
tmp[index] = input(index - howMuch);
}
return vec { tmp };
} else {
return input;
}
}
}
//template<typename T1, typename T2>
//cx_vec polydiv(const T1& ON, const T2& OD, const VectorType& FirstType,
// const VectorType& SecondType) {
// if (FirstType == VectorType::ComplexType
// && SecondType == VectorType::OrdinaryType) {
//
// } else if (FirstType == VectorType::ComplexType
// && SecondType == VectorType::ComplexType) {
//
// } else if (FirstType == VectorType::OrdinaryType
// && SecondType == VectorType::OrdinaryType) {
//
// } else if (FirstType == VectorType::OrdinaryType
// && SecondType == VectorType::ComplexType) {
//
// }
//
//}

int main() {
cx_vec N { { 1, 2 }, { 3, 4 } };
cout << polyval(N, 2, VectorType::ComplexType) << endl;
return 0;
}


من از کتابخانه armadillo استفاده کردم. توی این کتابخانه بردار دابل با vec و بردار مختلط دابل با cx_vec شناخنه میشه.
سوال من اینجاست که چجوری میتونم توابعی که توی کد بالا هست رو جنریک بنویسم طوری که رو هر کدام از دو نوع معرفی درست کار کنه.البته کد ++C هنوز کامل نیست فقط اگه یه راهنمایی برای این مبحث template بدید بهم بقیه رو امیدوارم بتونم خودم جلو ببرم.

با تشکر

rahnema1
یک شنبه 01 شهریور 1394, 23:17 عصر
سلام
شما مستندات Armadillo را مطالعه کنید گفته cx_vec همون <Col<cx_double هست و vec هم همون <Col<double
بنابراین یه همچین چیزی می تونید استفاده کنید

template <typename T>
Col<T> fun(){
}

ehsan_faal
یک شنبه 01 شهریور 1394, 23:20 عصر
ممنون.نمیدونم چرا قبلا با اینکه دیده بودمش استفاده نکرده بودم.
امتحانش میکنم امیدوارم درست باشه.

ehsan_faal
دوشنبه 02 شهریور 1394, 11:10 صبح
با این روشی که شما گفتید یه سری از توابعی که دارم مثله polyval درست کار میکنه ولی تابعی مثله shiftPolynomial ارور میده:

template<typename T>
auto shiftPolynomial(const Col<T>& input, const int& howMuch,
const VectorType& WhichType) ->Col<T> {
if (WhichType == VectorType::ComplexType) {
if (howMuch > 0) {
vector<complex<double>> tmp(input.n_elem);
for (size_t index = 0; index < howMuch; index++) {
tmp[index] = 0.0;
}
for (size_t index = howMuch; index < tmp.size(); index++) {
tmp[index] = input(index - howMuch);
}
return cx_vec { tmp };
} else {
return input;
}
} else if (WhichType == VectorType::OrdinaryType) {
if (howMuch > 0) {
vector<double> tmp(input.n_elem);
for (size_t index = 0; index < howMuch; index++) {
tmp[index] = 0.0;
}
for (size_t index = howMuch; index < tmp.size(); index++) {
tmp[index] = input(index - howMuch);
}
return vec { tmp };
} else {
return input;
}
}
}

int main() {
cx_vec N { { 1, 2 }, { 3, 4 } };
vec D{1,2,3};
cout << shiftPolynomial(D,5,VectorType::OrdinaryType) << endl;
return 0;
}

من دقیقا متوجه نمیشم که چرا نمیشه با enum هایی که تعریف کردم مسیر تابع رو برای ورودی های متفاوت تعیین کرد!
مثلا من اینجا یه چند جمله ای از نوع دابل رو که به این تابع میدم زیر آخرین خط مربوط به قسمت مختلط خط میکشه و میگه که نمیتونه یه Col از جنس cx_double رو به یه Col از نوع double تبدیل کنه.
کجا رو دارم اشتباه میکنم؟

ehsan_faal
دوشنبه 02 شهریور 1394, 11:30 صبح
مثال قبل رو دوباره اینطوری نوشتم.ارور قبلی رفع شده ولی الان یه ارور دیگه میگیرم:

template<typename T>
auto shiftPolynomial(const Col<T>& input, const int& howMuch,
const VectorType& WhichType) ->Col<T> {
Col<T> result(input.n_elem + howMuch);
if (WhichType == VectorType::ComplexType) {
if (howMuch > 0) {
vector<complex<double>> tmp(input.n_elem + howMuch);
for (size_t index = 0; index < howMuch; index++) {
tmp[index] = 0.0;
}
for (size_t index = howMuch; index < tmp.size(); index++) {
tmp[index] = input(index - howMuch);
}
copy_n(tmp.begin(),tmp.size(),result.begin());
} else {
return input;
}
} else if (WhichType == VectorType::OrdinaryType) {
if (howMuch > 0) {
vector<double> tmp(input.n_elem + howMuch);
for (size_t index = 0; index < howMuch; index++) {
tmp[index] = 0.0;
}
for (size_t index = howMuch; index < tmp.size(); index++) {
tmp[index] = input(index - howMuch);
}
copy_n(tmp.begin(),tmp.size(),result.begin());
} else {
return input;
}
}
return result;
}

int main() {
cx_vec N { { 1, 2 }, { 3, 4 } };

vec D{1,2,3};
cout << shiftPolynomial(D,3,VectorType::OrdinaryType) << endl;
return 0;
}

اروری که میده مربوط به استفاده از copy_n هستش که باز هم میگه دو نوع source و destination با هم compatibility ندارند. :متفکر:

rahnema1
دوشنبه 02 شهریور 1394, 17:59 عصر
این شکلی می شه نوشت

template<typename T>
auto shiftPolynomial(const Col<T>& input, const int& howMuch)
{
if (howMuch > 0)
{
Col<T> result(input.n_elem + howMuch, fill::none);
result.rows(0, howMuch - 1).zeros();
result.rows(howMuch, result.n_elem - 1) = input;
return result;
}
return input;
}