在 C++ 中添加 int 数据类型和自定义 class 数据类型以获得更高的性能
Addition between int datatypes and custom class datatypes in c++ to get higher performance
我自己制作了 class long_number 来进行比 long long int 更大的数字的数学运算(用于素数目的等)。现在我正在测试添加并比较以下代码的速度:
#include <iostream>
#include <cmath>
#include <vector>
#include <typeinfo>
#include <string>
//#include "long_number.h" the header is below
#include <chrono>
using namespace std;
using namespace ln;
typedef long long int Te;
typedef long_number Se;
int main()
{
// Start measuring time
vector<Te> numbers;
string s = "";
for(int i=1;i<15;i++)
{
s.append(to_string(i));
numbers.push_back(stoll(s));
}
auto begin = std::chrono::high_resolution_clock::now();
Te sum=0;
for(int k=0;k<=5000;k++)
{
sum=0;
for(int j=1;j<=7;j++)
for(int i =0;i<numbers.size();i++)
sum +=numbers[i];
}
cout << "Sum " <<sum <<endl;
auto end = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin);
printf("Time measured: %.6f seconds.\n", elapsed.count() * 1e-9);
vector<Se> numbers2;
string se;
for(int i=1;i<15;i++)
{
se.append(to_string(i));
numbers2.push_back((Se)stoll(se));
}
begin = std::chrono::high_resolution_clock::now();
Se sum2=0;
for(int k=0;k<=5000;k++)
{
sum2=0;
for(int j=1;j<=7;j++)
for(int i =0;i<numbers2.size();i++)
sum2 += numbers2[i];
}
cout << "Sum " <<sum2 <<endl;
end = std::chrono::high_resolution_clock::now();
elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin);
printf("Time measured: %.6f seconds.\n", elapsed.count() * 1e-9);
return 0;
}
使用 g++ main.cpp -Wall -O3 -std=c++17 -o 程序打印以下结果:
Sum 8729267916327544355
Time measured: 0.000474 seconds.
Sum 8729267916327544355
Time measured: 0.677444 seconds.
你可以看到,int加法大约快了1000倍。我的 class long_number 如下:
#include <iostream>
#include <cmath>
#include <vector>
#include <typeinfo>
#include <string>
using namespace std;
namespace ln
{
//stores long integers in vector, 0th position means 10^0 -> reversed order, using for operation of huge nubers overnight
class long_number
{
private:
public:
vector<unsigned int> numero = {};//every component store one digit of the number
unsigned int size = 0;//size of the numero - how many digit has the number
long_number() {};//default constructor
void zero_check()//checks and remuves zero digits from the left of the number
{
while(numero[numero.size()-1]==0&&numero.size()>=2)
{
numero.pop_back();
size--;
}
size = numero.size();
}
operator unsigned int() const //conversion form long_number to int
{
//cout << "typecast operator unsigned int() used" << endl;
unsigned int num=0;
for(unsigned int i=0;i<size;i++)
num += numero[i]*pow(10.,i);
return num;
}
template<typename numb>
long_number(numb a)//constructor
{
string b = to_string(a);
read(b);
}
long_number(const long_number& a)//copy constructor
{
numero = a.numero;
size = a.numero.size();
}
int ssize() const
{
return (this->numero).size();
}
void set_size(int i)
{
(this->numero).resize(i);
}
void get (ostream& out) const;//historic function to print the long_number
void read(string input); //historic function to declare long_number
vector <unsigned int> get_numero() const //not necessary cauz all is public
{
return numero;
}
void set_numero(int num,int pos)
{
numero[pos]=num;
}
long_number& operator+=(const long_number& b)//defined by the binary operator +
{
long_number a= *this;
*this = (a + b);
return *this;
}
template <typename numb>
long_number& operator=( numb b)// I don't know why is this here
{
string s = to_string(b);
this->read(s);
return *this;
}
~long_number(){}//destructor
//this is here to get acces inside the operators to another operators
//it should work also without this according to
//https://www.learncpp.com/cpp-tutorial/9-2a-overloading-operators-using-normal-functions/
//because all is public but it doesnt
friend long_number operator + ( const long_number&,const long_number&);
};
long_number operator+ (const long_number& a, const long_number& b)//sum of two long_numbers
{
long_number res;
int ten = 10;
int a_size=a.get_numero().size();//size of number a
int b_size=b.get_numero().size();//size of number b
res.set_size(max(a_size,b_size)+1);
int rest = 0; //stores the rest when adding over ten
for(int i=0;i<min(a_size,b_size);i++)//part where both numbers have digits
{
res.set_numero((a.get_numero()[i]+(b.get_numero())[i]+rest)%ten,i);//sum of digits,
rest=((a.get_numero())[i]+(b.get_numero())[i]+rest)/ten;// rest is saving suming over 10
}
if(a_size>b_size)//to find which number is greater
for(int i=min(a_size,b_size);i<a_size;i++)//part where one numbers has no digit -> is less
{
//res.get_numero().push_back((a.get_numero()[i]+rest)%10);//set zero at the higher positions of the smallest number
res.set_numero((a.get_numero()[i]+rest)%ten,i);
rest=((a.get_numero())[i]+rest)/ten;
}
else
for(int i=min(a_size,b_size);i<b_size;i++)
{
//res.get_numero().push_back(((b.get_numero())[i]+rest)%10);
res.set_numero(((b.get_numero())[i]+rest)%ten,i);
rest=((b.get_numero())[i]+rest)/ten;
}
if(rest!=0)//if the result has more digit than the greatest partner
{
//res.get_numero().push_back(rest);
res.set_numero(rest,max(a_size,b_size));
}
if((res.numero[(res.numero).size()-1])==0)//reduces zero digit from left if possible
(res.numero).erase((res.numero).end()-1);
return res;
}
ostream& operator<< (ostream& out, const long_number& num)//output of the number
{
for(int i=(num.numero).size()-1;i>=0;i--)
{
out << (num.numero)[i];
}
return out;
}
void long_number::read(string input)
{
//if(this->numero)
this->numero.erase(this->numero.cbegin(),this->numero.cend());
string s;
if(typeid (input)== typeid (string))
string s = input;
else
;
//string s = to_string(input);
for(int i=input.size()-1;i>=0;i--)
(this->numero).push_back(input[i]-'0');
this->size = (this->numero).size();
}
void long_number::get(ostream& out) const
{
for(int i=(this->numero).size()-1;i>=0;i--)
{
out << (this->numero)[i];
}
//out << endl;
}
}
我知道有更快的求和算法,但我使用的是标准的逐位求和,但我没想到差异会这么大。
速度真的是算法给定的吗?与标准数据类型相比,可以达到的最大速度是多少?在我的代码中是否有任何可以更好地优化以加速代码执行的地方?或者我可以在编译器命令中使用更多标志以获得更高的性能吗?
真的很感谢每一个帮助让我前进的人!!!
弗兰克
您的 long_number operator+
可以通过消除 get_numero()
中向量的多个副本轻松改进。
你真的不需要复制你的向量然后询问它的大小。只需为您的 class.
提供一个 size()
方法
类似地,实现 operator []
以直接访问单个数字,而不是 (a.get_numero())[i]
(同样,在对它进行索引之前复制整个向量)。
增加的时间是原来的 1,000 倍 - 很多!但是,预计会出现大约 100 次 - 只需计算您有多少步来代替简单的 add
指令
我自己制作了 class long_number 来进行比 long long int 更大的数字的数学运算(用于素数目的等)。现在我正在测试添加并比较以下代码的速度:
#include <iostream>
#include <cmath>
#include <vector>
#include <typeinfo>
#include <string>
//#include "long_number.h" the header is below
#include <chrono>
using namespace std;
using namespace ln;
typedef long long int Te;
typedef long_number Se;
int main()
{
// Start measuring time
vector<Te> numbers;
string s = "";
for(int i=1;i<15;i++)
{
s.append(to_string(i));
numbers.push_back(stoll(s));
}
auto begin = std::chrono::high_resolution_clock::now();
Te sum=0;
for(int k=0;k<=5000;k++)
{
sum=0;
for(int j=1;j<=7;j++)
for(int i =0;i<numbers.size();i++)
sum +=numbers[i];
}
cout << "Sum " <<sum <<endl;
auto end = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin);
printf("Time measured: %.6f seconds.\n", elapsed.count() * 1e-9);
vector<Se> numbers2;
string se;
for(int i=1;i<15;i++)
{
se.append(to_string(i));
numbers2.push_back((Se)stoll(se));
}
begin = std::chrono::high_resolution_clock::now();
Se sum2=0;
for(int k=0;k<=5000;k++)
{
sum2=0;
for(int j=1;j<=7;j++)
for(int i =0;i<numbers2.size();i++)
sum2 += numbers2[i];
}
cout << "Sum " <<sum2 <<endl;
end = std::chrono::high_resolution_clock::now();
elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin);
printf("Time measured: %.6f seconds.\n", elapsed.count() * 1e-9);
return 0;
}
使用 g++ main.cpp -Wall -O3 -std=c++17 -o 程序打印以下结果:
Sum 8729267916327544355
Time measured: 0.000474 seconds.
Sum 8729267916327544355
Time measured: 0.677444 seconds.
你可以看到,int加法大约快了1000倍。我的 class long_number 如下:
#include <iostream>
#include <cmath>
#include <vector>
#include <typeinfo>
#include <string>
using namespace std;
namespace ln
{
//stores long integers in vector, 0th position means 10^0 -> reversed order, using for operation of huge nubers overnight
class long_number
{
private:
public:
vector<unsigned int> numero = {};//every component store one digit of the number
unsigned int size = 0;//size of the numero - how many digit has the number
long_number() {};//default constructor
void zero_check()//checks and remuves zero digits from the left of the number
{
while(numero[numero.size()-1]==0&&numero.size()>=2)
{
numero.pop_back();
size--;
}
size = numero.size();
}
operator unsigned int() const //conversion form long_number to int
{
//cout << "typecast operator unsigned int() used" << endl;
unsigned int num=0;
for(unsigned int i=0;i<size;i++)
num += numero[i]*pow(10.,i);
return num;
}
template<typename numb>
long_number(numb a)//constructor
{
string b = to_string(a);
read(b);
}
long_number(const long_number& a)//copy constructor
{
numero = a.numero;
size = a.numero.size();
}
int ssize() const
{
return (this->numero).size();
}
void set_size(int i)
{
(this->numero).resize(i);
}
void get (ostream& out) const;//historic function to print the long_number
void read(string input); //historic function to declare long_number
vector <unsigned int> get_numero() const //not necessary cauz all is public
{
return numero;
}
void set_numero(int num,int pos)
{
numero[pos]=num;
}
long_number& operator+=(const long_number& b)//defined by the binary operator +
{
long_number a= *this;
*this = (a + b);
return *this;
}
template <typename numb>
long_number& operator=( numb b)// I don't know why is this here
{
string s = to_string(b);
this->read(s);
return *this;
}
~long_number(){}//destructor
//this is here to get acces inside the operators to another operators
//it should work also without this according to
//https://www.learncpp.com/cpp-tutorial/9-2a-overloading-operators-using-normal-functions/
//because all is public but it doesnt
friend long_number operator + ( const long_number&,const long_number&);
};
long_number operator+ (const long_number& a, const long_number& b)//sum of two long_numbers
{
long_number res;
int ten = 10;
int a_size=a.get_numero().size();//size of number a
int b_size=b.get_numero().size();//size of number b
res.set_size(max(a_size,b_size)+1);
int rest = 0; //stores the rest when adding over ten
for(int i=0;i<min(a_size,b_size);i++)//part where both numbers have digits
{
res.set_numero((a.get_numero()[i]+(b.get_numero())[i]+rest)%ten,i);//sum of digits,
rest=((a.get_numero())[i]+(b.get_numero())[i]+rest)/ten;// rest is saving suming over 10
}
if(a_size>b_size)//to find which number is greater
for(int i=min(a_size,b_size);i<a_size;i++)//part where one numbers has no digit -> is less
{
//res.get_numero().push_back((a.get_numero()[i]+rest)%10);//set zero at the higher positions of the smallest number
res.set_numero((a.get_numero()[i]+rest)%ten,i);
rest=((a.get_numero())[i]+rest)/ten;
}
else
for(int i=min(a_size,b_size);i<b_size;i++)
{
//res.get_numero().push_back(((b.get_numero())[i]+rest)%10);
res.set_numero(((b.get_numero())[i]+rest)%ten,i);
rest=((b.get_numero())[i]+rest)/ten;
}
if(rest!=0)//if the result has more digit than the greatest partner
{
//res.get_numero().push_back(rest);
res.set_numero(rest,max(a_size,b_size));
}
if((res.numero[(res.numero).size()-1])==0)//reduces zero digit from left if possible
(res.numero).erase((res.numero).end()-1);
return res;
}
ostream& operator<< (ostream& out, const long_number& num)//output of the number
{
for(int i=(num.numero).size()-1;i>=0;i--)
{
out << (num.numero)[i];
}
return out;
}
void long_number::read(string input)
{
//if(this->numero)
this->numero.erase(this->numero.cbegin(),this->numero.cend());
string s;
if(typeid (input)== typeid (string))
string s = input;
else
;
//string s = to_string(input);
for(int i=input.size()-1;i>=0;i--)
(this->numero).push_back(input[i]-'0');
this->size = (this->numero).size();
}
void long_number::get(ostream& out) const
{
for(int i=(this->numero).size()-1;i>=0;i--)
{
out << (this->numero)[i];
}
//out << endl;
}
}
我知道有更快的求和算法,但我使用的是标准的逐位求和,但我没想到差异会这么大。 速度真的是算法给定的吗?与标准数据类型相比,可以达到的最大速度是多少?在我的代码中是否有任何可以更好地优化以加速代码执行的地方?或者我可以在编译器命令中使用更多标志以获得更高的性能吗?
真的很感谢每一个帮助让我前进的人!!! 弗兰克
您的 long_number operator+
可以通过消除 get_numero()
中向量的多个副本轻松改进。
你真的不需要复制你的向量然后询问它的大小。只需为您的 class.
提供一个size()
方法
类似地,实现 operator []
以直接访问单个数字,而不是 (a.get_numero())[i]
(同样,在对它进行索引之前复制整个向量)。
增加的时间是原来的 1,000 倍 - 很多!但是,预计会出现大约 100 次 - 只需计算您有多少步来代替简单的 add
指令