缘由各位老师好!求助编辑一个大整数的快速乘除法可调用程序 - VB6论坛 - 编程论坛
目前仅发现51个梅森素数,最大的是M82589933(即2的82589933-1),有24862048位。
就如题主所述:我想用普通电脑,用特殊算法试试,但速度太慢了,不行,不能实现。(特殊算法就是指,仅仅算一步除法,进行初步判断,比如:一般人认为对于梅森数若指数p是4x+3型的奇数,指数p若是素数,且2p+1也是素数,则该梅森数可以被2p+1整除,若是不能整除呢?那就基本可以确定是素数了,这样的情况是很稀少的。比如99368963是个素数,2*99368963=198737927也是素数,2^99368963-1是否能被198737927整除呢?如果不能被整除,那就可能是素数,几乎是确定的。第51个梅森素数没有这个数大呢,如果这个数是素数就是第52个梅森素数。)
家用普通电脑创建这样一个数组是否满足需求_int64 a[100000]{},公共_int64 cf[10000000]{};
相信数值运算远比字符运算快得多得多多
这就是我的分治法,不同以往字符运算,与其在字符上绞尽脑汁,不如跳出字符,另寻新途。
void 二的次方数组(_int64* 数, int 长, _int64 次)
{
_int64 溢 = 0, 段 = 0, 乘数 = 0, 序 = 长 - 1, 模 = 1E+9, 次方 = 1;
数[序] = 1;
while (次方)
{
if ((乘数 = 数[序]) > 0)
{
数[序] = (乘数 - 乘数 / 模*模) * 2 + 溢;
溢 = 数[序] / 模;
数[序] -= 溢*模;
段 = (乘数 / 模) * 2 + 溢;
溢 = 段 / 模;
数[序] += (段 - 段 / 模*模)*模;
//cout << 数[序] << "\t" << 溢 << "\t:";
--序;
}
else
{
数[序] += 溢;
if (++次方 > 次 || 数[0] > 0)
{
while (序 < 长)
写入文本("..\\Debug\\回复专用\\二次方数据" + std::to_string(次方) + ".txt", std::to_string(数[序++]) + "\n");
次方 = 0;
}
else;
if (次方 % 4000000 == 0)
{
写入文本("..\\Debug\\回复专用\\二次方数据" + std::to_string(次方) + ".txt", std::to_string(序) + "\n");
while (++序 < 长)
写入文本("..\\Debug\\回复专用\\二次方数据" + std::to_string(次方) + ".txt", std::to_string(数[序]) + "\n");
//次方 = 0;
}
else;
序 = 长 - 1; 溢 = 0;
//cout << 次方 << "\n";
}
}
}
_int64 a[900000]{}, al = 900000, x = 0, p = 0;
clock_t 开始 = clock();
二的次方数组(a, 100000, 99368963);
clock_t 结束 = clock();
while (x < al)if (a[x] || p)
std::cout << setw(18) << setfill('0') << a[x], ++x, ++p;
else ++x;
std::cout << "\t" << p << "\n";
void 写入文本(string 文件名, string 内容)
{
std::ofstream 文件(文件名, std::ios::app);
文件 << 内容;//第一条数据会少1位数,后面的就是18位数了.<< setw(18) << setfill('0')
}
void findfile(std::string path, std::string mode)
{
_finddata_t file;
intptr_t HANDLE;
std::string Onepath = path + mode;
HANDLE = _findfirst(Onepath.c_str(), &file);
if (HANDLE == -1L)std::cout << "无法匹配文件夹路径" << std::endl;
do {
if (file.attrib)
{
std::string newPath = path + file.name;
std::cout << file.name << " " << std::endl;
}//判断是否有子目录 & _A_SUBDIR
//if ((strcmp(file.name, ".") != 0) && (strcmp(file.name, "..") != 0))//判断是否为"."当前目录,".."上一层目录
//{
// std::string newPath = path + "\\" + file.name;
// findfile(newPath, mode);
//}
//else
// std::cout << file.name << " " << std::endl;
} while (_findnext(HANDLE, &file) == 0);
_findclose(HANDLE);
}
void findfile(std::string path, std::string mode, _int64* 数, int 长)
{
_finddata_t file;
intptr_t HANDLE = _findfirst((path + mode).c_str(), &file);
if (HANDLE == -1L)
std::cout << "无法匹配文件夹路径" << std::endl;
else;
do
{
if (file.attrib)
std::string newPath = path + file.name;
else;
} while (_findnext(HANDLE, &file) == 0);
读取文本(path + file.name, 数, 长);
_findclose(HANDLE);
}
std::string mode = "\\二次方数据*.txt";
std::string path = "..\\Debug\\回复专用";
findfile(path, mode);
SYSTEMTIME timeDest;
SetWindowPos(GetConsoleWindow(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);//控制台程序置顶窗口
void 二的次方数组(_int64* 数, int 长, _int64 次)
{
_int64 溢 = 0, 段 = 0, 乘数 = 0, 序 = 长 - 1, 模 = 1E+9, 次方 = 1;
读取文本("..\\Debug\\回复专用\\", "二次方数据*.txt", 数, 长, 次方);
char 时间[128]; _strtime_s(时间, 128); printf("时间:%s次方%d\n", 时间, 次方);
if (次方 == 1)数[序] = 1; else;
while (次方)
{
if (数[序] > 0)//(乘数 = 数[序])
{
数[序] = 数[序] * 2 + 溢;// std::cout << 数[序] << "\t";
溢 = 数[序] / 1E+18;
数[序] -= 溢*1E+18;
--序;
}
else
{
数[序] += 溢;
if (++次方 > 次 || 数[0] > 0)
{
while (序 < 长)
写入文本("..\\Debug\\回复专用\\二次方数据" + std::to_string(次方) + ".txt", std::to_string(数[序++]) + "\n");
次方 = 0;
}
else if (次方 % 200000 == 0){_strtime_s(时间, 128); printf("次方%d 时间:%s\n", 次方, 时间);}
else if (次方 % 2000000 == 0)
{
写入文本("..\\Debug\\回复专用\\二次方数据" + std::to_string(次方) + ".txt", std::to_string(序) + "\n");
while (++序 < 长)
写入文本("..\\Debug\\回复专用\\二次方数据" + std::to_string(次方) + ".txt", std::to_string(数[序]) + "\n");
_strtime_s(时间, 128); printf("时间:%s数据输出完成。\n", 时间);
}
else;
序 = 长 - 1; 溢 = 0;
}
}
}
void 读取文本(std::string 路径, std::string 文件名, _int64* 数, int 长, _int64& 次方)
{
_finddata_t file;
std::string newPath = 路径 + 文件名, 读取 = "";
_int64 cf = 0; int j = 0, jj = 0;
intptr_t HANDLE = _findfirst((路径 + 文件名).c_str(), &file);
if (HANDLE == -1L)
std::cout << "无法匹配文件夹路径" << std::endl;
else
do
{
if (file.attrib)
{
newPath = 路径 + file.name;
j = newPath.find("数据") + 4;
jj = newPath.find(".txt");
cf = _atoi64(newPath.substr(j, jj - j).c_str());
if (次方 < cf)
次方 = cf, 读取 = newPath; else;
}
else;
} while (_findnext(HANDLE, &file) == 0);
_findclose(HANDLE);
std::string 读 = "";
int 序 = 0, 位 = 0;
std::ifstream 文件(读取);
if (!文件.eof())
{
while (getline(文件, 读))
if (序 == 0)
序 = _atoi64(读.c_str());
else
数[++序] = _atoi64(读.c_str());
文件.close();
}
else;
std::cout << 数[序] << "\t" << 读 << "\n";
}
void 二的次方数组(_int64 数[][10000000], _int64 长, _int64 次)
{
_int64 溢 = 0, 序 = 长 - 1, 次方 = 1, 组 = 0;
二的次方数组读取文本("..\\Debug\\回复专用\\", "二次方数据*.txt", 数, 长, 次方);
char 时间[128]; _strtime_s(时间, 128); printf("时间:%s 次方%d\n", 时间, 次方);
if (次方 == 1)数[组][序] = 1; else;
while (次方 && 序 > -1)
{
if (数[组][序] > 0)
{
数[组][序] = 数[组][序] * 2 + 溢;
溢 = 数[组][序] / 1E+18;
数[组][序] -= 溢*1E+18;
if (--序 < 0 && 组 < 1) ++组, 序 = 长 - 1;// --序;
}
else
{
数[组][序] += 溢;
if (++次方 > 次 || 数[组][0] > 1E+18 || 次方 % 40000 == 0)
{
_strtime_s(时间, 128); printf("时间:%s ", 时间); std::cout << "次方" << 次方 << " 数量" << 长 - 序 << " ";
写入文本("..\\Debug\\回复专用\\二次方数据" + std::to_string(次方) + ".txt", std::to_string(序) + "\n");
while (++序 < 长)
{
写入文本("..\\Debug\\回复专用\\二次方数据" + std::to_string(次方) + ".txt", std::to_string(数[组][序]) + "\n");
显示进度(长, 序);
}
_strtime_s(时间, 128); printf(":%s数据保存完成。\n", 时间);
if (次方 > 次 || 数[组][0] > 1E+18) 次方 = 0;
}
if (次方 % 10000 == 0)
{
std::string 标题 = "VsC++:" + std::to_string(次方);
system(("title " + 标题).data());
}
序 = 长 - 1; 组 = 溢 = 0;
}
}
}
果如预想的一样优化修改程序后运算历时减少一半不止,运算200万只用了2小时,原来需要6小时,可以这样总结,本次设计的加法减法二次方乘法都采用了最快速代码进行优化,最大限度提高运算速度,也不耽误在电脑上做其他事情开其他程序,由此可以看出语句越精简耗时越少效率越高不可忽视非常重要,尤其对于有时间要求的程序设计是要特别注意语句的精炼。同时也完成了接续运算功能,读取前面保存的数据文本文件转到数组,从而不再担忧时间问题,随时随地可以使用接续运算。