为什么我的程序不能处理大数
Why does my program not work with large numbers?
我正在试着写一个程序,找到600851475143的最大素数因子。它适用于较小的数字(直到10000),但不能再大了。我怎样才能改变呢?程序不给出任何错误或终止,只是不输出任何内容。
#include <iostream>
#include <vector>
using namespace std;
bool isPrime( unsigned long long int num);
int main() {
unsigned long long int m = 600851475143;
std::vector<int> pfactors;
pfactors.reserve(100000000);
for (long long int i = 2; i <= m; i++) {
if (isPrime(i) == true) {
if (m % i == 0) {
pfactors.push_back(i);
}
}
}
for (vector<int>::iterator it = pfactors.begin(); it != pfactors.end(); it++) {
cout << *it << endl;
}
cin.get();
return 0;
}
bool isPrime(unsigned long long int num)
{
if (num < 2)
return false;
if (num > 2 && (num % 2) == 0)
return false;
for (unsigned long long int i = 2; i < num; i++)
{
if ((num % i) == 0)
{
return false;
}
}
return true;
}
@DanyalImran和@ jean - franisfabre提供的答案都不正确。巧合的是,600851475143是71,839,1471和6857的乘积,并且所有因数都小于根号(num)。如果OP中的数字是600851475149(质数)怎么办?
因此,我们需要搜索整个范围[2,num],而不是范围[2,sqrt(num)]。
所以,这是我在几次尝试后得到的结果,我使用Eratosthenes算法的Sieve来优化搜索,以预先计算素数标志的向量并记忆先前发现的素数。
虽然埃拉托色尼筛法是在特定范围内找到所有质数的最快方法(它没有除法运算,只有比除法快几倍的乘法运算),这种方法没有多大帮助,因为它不能消除循环遍行向量以查找标记为素数的元素,然后将问题中的数字与找到的素数相除的需要(我故意在@ jean - franisfabre的实现中将vector<bool>
替换为vector<char>
,以避免vector<bool>
可能的"位打包"实现,因为在矢量计算中的位位置肯定比字符位置计算更昂贵)。
在我的1.4GHz AMD上,我用这种方法解决OP中150212868857 prime的任务的时间是~7:05分钟:
150212868857
real 7m5.156s
user 7m5.063s
sys 0m0.008s
试图记住所有以前找到的质数来加速isPrime()
测试是更糟糕的,所以我没有给它完成的机会。这可以解释为同样需要遍历质数向量,并且由于需要从内存中读取大量数据,因此成本更高。
最后一个变体只是在步骤2中迭代候选除数3到num
的范围,并且只在num
为偶数时调用isPrime
。这种方法显示了与之前相同的时间正负几秒。因此,只要所使用的数学方法符合现代CPU的本机寄存器,对vector元素的访问就显得和除法一样昂贵。
然而,当所讨论的数字不是素数时(如OP中),仍然有一个优化的地方,允许缩短搜索时间。
代码:
#include <iostream>
#include <vector>
#include <math.h>
using namespace std;
//#define SIEVE
vector<char> primeFlagger;
void initSieve(unsigned long long int limit) {
unsigned long long int root = (unsigned long long int)(sqrt(limit));
primeFlagger = vector<char>(root+1,true);
primeFlagger[0] = primeFlagger[1] = false;
for(unsigned long long int j=2; j<=root; j++)
{
if(primeFlagger[j])
{
for(unsigned long long int k=j; (k*j)<=root; k++)
{
primeFlagger[j*k]=false;
}
}
}
}
#ifdef SIEVE
bool isPrime(unsigned long long int num)
{
if (num <= 2)
return true;
if ((num % 2) == 0)
return false;
unsigned sqr = (unsigned)sqrt(num);
for(unsigned i = 3; i <= sqr; i+=2) {
if (primeFlagger[i] && num % i == 0)
return false;
}
return true;
}
#else
bool isPrime(unsigned long long int num)
{
if (num <= 2)
return true;
if ((num % 2) == 0)
return false;
unsigned sqr = (unsigned)sqrt(num);
for(unsigned i = 3; i <= sqr; i+=2) {
if (num % i == 0)
return false;
}
return true;
}
#endif
int main() {
unsigned long long int m = 600851475143;//150212868857;//600851475149;
std::vector<unsigned long long int> pfactors;
#ifdef SIEVE
initSieve(m);
#endif
if (m % 2 == 0) {
do {
m /= 2;
} while (m % 2 == 0);
pfactors.push_back(2);
}
for (long long int i = 3; i <= m; i+=2) {
if (m % i == 0 && isPrime(i)) {
do {
m /= i;
} while (m % i == 0);
pfactors.push_back(i);
}
}
for (vector<unsigned long long int>::iterator it = pfactors.begin(); it != pfactors.end(); it++) {
cout << *it << endl;
}
return 0;
}
在OP中包含number的结果:
$ g++ -O3 prime1.cpp
$ time ./a.out
71
839
1471
6857
real 0m0.004s
user 0m0.002s
sys 0m0.002s
600851475143是一个非常大的数字,你的算法非常低效。我怀疑它最终会终止,但这个"最终"远远超出了你愿意等待的时间。
以上是假设你的平台上的long long
甚至能够表示这个数字——如果它只有32位,那么它就不是。
你真正需要的是一个更有效的算法。
程序失败,因为您使用的是int
数据类型。它有32 bits, i.e 2^32 ~= 9 digits max
要访问大于9位的值,请尝试使用long long
或unsigned long long
。它有64 bits, i.e 2^64 ~= 18 digits for signed and 20 digits for unsigned
.
编辑:^这是c++ 98 (Orwell Dev c++: testing)
vector<int> pfactor;
int on vector会导致程序失败。你不需要在矢量中保留任何空间,因为它是动态的,除非你在二维矢量上工作。
示例代码:
#include<math.h>
#include<iostream>
using namespace std;
bool ifPrime ( int number ) {
for ( long long int i=2; i<sqrt(number); ++i ) {
if ( number%i == 0 ) return false;
}
return true;
}
int main ( ) {
long long int number = 600851475143;
static long long int largestPrime;
bool found = false;
for ( long long int i=sqrt(number); i>=0 && !found; i=i-1 ) {
if ( number%i==0 && ifPrime(i) ) {
largestPrime = i;
found = true;
}
}
cout << "Largest Prime for " << number << " is: " << largestPrime << endl;
}
- CStdioFile 不能处理大于 2GB 的文件?
- 为什么这个信号处理程序不能捕获 SIGHUP 或 SIGQUIT?
- std::remove() 按预期处理文字,但不能与取消引用的迭代器一起工作
- arm-none-eabi-g++ 不能使用 -flto 正确处理弱别名
- 为什么 CSpinButtonCtrl 不能正确处理大于 1000 的数字?
- 方便的标志处理,所有标志都不能放入64位
- 为什么我不能在Windows Server 2008中使用System()从服务启动批处理文件
- 为什么这个简单的批处理方法不能按预期工作?
- 为什么谷歌破板不能处理所有崩溃?如何调试这些情况
- 为什么我的C++算法不能处理超过 62 位的整数?
- 为什么std::sqrt()在C++中不能正确处理双数据
- C样式强制转换可以处理的转换,但C++强制转换不能
- 多参数模板不能很好地处理友元声明
- 输入布局,访问违规,错误处理不能像我希望的那样工作
- 为什么swig在使用__getattribute__时不能正确处理AttributeError ?
- 不支持的操作.由JRC引擎处理的文档不能在c++堆栈中打开
- C程序不能处理与c++相关的错误
- 新行不能处理c++中的文件
- 双精度/打印在c++中不能处理14位数字
- QtConcurrent::run() 不能处理超过 5 个参数?