这次实验主要围绕C++中的整数运算与因数分解展开,通过四个编程任务来训练面向对象编程能力和算法思维。作为C++初学者常见的练习项目,这类实验能有效提升对循环控制、函数封装和数学运算的理解。
实验的核心目标是:
提示:虽然实验要求使用面向对象方法,但对于这类数学计算问题,过程式编程往往更直接。建议先实现功能再考虑如何用类来封装。
完数(Perfect number)指恰好等于其真因数之和的正整数。例如6=1+2+3,28=1+2+4+7+14。已知的完数都是偶数,且与梅森素数有密切关系。
cpp复制vector<int> findPerfectNumbers(int n) {
vector<int> result;
for(int num=2; num<=n; ++num){
int sum = 1; // 1是所有数的因数
for(int i=2; i*i<=num; ++i){
if(num%i == 0){
sum += i;
if(i != num/i) sum += num/i;
}
}
if(sum == num) result.push_back(num);
}
return result;
}
关键优化点:
cpp复制void printPerfectNumbers(int n, const vector<int>& pnums){
cout << n << ":";
for(int num : pnums){
cout << " " << num;
}
cout << endl;
}
注意:当n较小时可能没有完数,此时应输出"n:"后面不跟任何数字,不要省略冒号。
12! = 479001600,其质因数分解为:
2^10 × 3^5 × 5^2 × 7 × 11
因数对数计算公式:
对于n = p1^a1 × p2^a2 ×...× pk^ak
因数总数为(a1+1)(a2+1)...(ak+1)
因数对数为[总数+1]/2(考虑对称性)
cpp复制const long long FACT12 = 479001600;
int countFactorPairs(){
int count = 0;
for(long long i=1; i*i<=FACT12; ++i){
if(FACT12%i == 0){
if(FACT12/i == i) count++;
else count += 2;
}
}
return count/2;
}
基础方法是对每个数n遍历1到n检查因数,但效率太低。优化方案:
cpp复制int countFactors(int n){
int count = 0;
for(int i=1; i*i<=n; ++i){
if(n%i == 0){
count += (i*i == n) ? 1 : 2;
}
}
return count;
}
更高效的方案是先进行质因数分解:
cpp复制int countFactorsByPrime(int n){
int count = 1;
for(int p=2; p*p<=n; ++p){
if(n%p == 0){
int exp = 0;
while(n%p == 0){
n /= p;
exp++;
}
count *= (exp+1);
}
}
if(n > 1) count *= 2;
return count;
}
高效的半素数检测需要先实现素数判断。埃拉托斯特尼筛法:
cpp复制vector<bool> sieve(int max_num){
vector<bool> is_prime(max_num+1, true);
is_prime[0] = is_prime[1] = false;
for(int i=2; i*i<=max_num; ++i){
if(is_prime[i]){
for(int j=i*i; j<=max_num; j+=i){
is_prime[j] = false;
}
}
}
return is_prime;
}
cpp复制bool isSemiprime(int n, const vector<bool>& is_prime){
for(int i=2; i<=n/2; ++i){
if(n%i == 0 && is_prime[i] && is_prime[n/i]){
return true;
}
}
return false;
}
cpp复制class NumberAnalyzer {
private:
vector<bool> prime_cache;
int max_cached;
public:
NumberAnalyzer(int max_num=1000000) {
prime_cache = sieve(max_num);
max_cached = max_num;
}
bool isPrime(int n) { /*...*/ }
bool isPerfect(int n) { /*...*/ }
bool isSemiprime(int n) { /*...*/ }
int countFactors(int n) { /*...*/ }
};
cpp复制int main() {
NumberAnalyzer analyzer(1000000);
cout << "28 is perfect? " << analyzer.isPerfect(28) << endl;
cout << "15 is semiprime? " << analyzer.isSemiprime(15) << endl;
cout << "Factors of 36: " << analyzer.countFactors(36) << endl;
return 0;
}
完数检测不准确
大数运算溢出
素数判断效率低
半素数误判
在实际测试中,我发现边界条件最容易出错。比如处理n=1时的特殊情况,或者最大取值范围接近2^32时的整数溢出问题。建议对所有输入参数先进行有效性检查。