以下都是测试int 32bit范围内的质数。
例如:1-200000014范围内有11078937个质数。
大数要用专门的类,支持任意范围大数。
质数定理给出了一个近似估计小于等于 n 的质数个数的公式:
π(n) ≈ n / ln(n)
其中 π(n) 表示小于等于 n 的质数个数,ln(n) 表示 n 的自然对数。这个公式在 n 很大时比较准确,但 n 较小时误差较大。
例如:小于等于 0xFFFFFFFF 的质数有 n/ln(n)==193635251 个。
0xFFFFFFFF 以内有2亿左右个质数,数量非常多,密度也很大,
这也是质数分解可以作为密码的原因。
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <math.h>
//质数判断
bool is_prime_optimized(int n) {
if (n <= 1) {
return false;
}
int i2 = (int)sqrt(n);
for (int i = 2; i <= i2; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
//有限大小的质数缓存
int eratosthenes_sieve(int limit, int *count, int ** prime_array) {
if (NULL== count || NULL==prime_array) {
return -1;
}
*count = 0;
*prime_array = NULL;
if (limit < 2) {
return 0;
}
bool* is_prime = (bool*)malloc(sizeof(bool) * (limit + 1));
if (NULL == is_prime) {
goto ERROR;
}
for (int i = 0; i <= limit; i++) {
is_prime[i] = true;
}
is_prime[0] = is_prime[1] = false;
for (int p = 2; p * p <= limit; p++) {
if (is_prime[p]) {
for (int i = p * p; i <= limit; i += p) {//至少从p * p开始
is_prime[i] = false;
}
}
}
int count_temp = 0;
for (int p = 2; p <= limit; p++) {
if (is_prime[p]) {
++count_temp;
}
}
*count = count_temp;
*prime_array = (int*)malloc(sizeof(int) * count_temp);
if (NULL==*prime_array) {
goto ERROR;
}
count_temp = 0;
for (int p = 2; p <= limit; p++) {
if (is_prime[p]) {
(*prime_array)[count_temp] = p;
++count_temp;
}
}
free(is_prime);
return 0;
ERROR:
if (is_prime) {
free(is_prime);
is_prime = NULL;
}
if (*prime_array) {
free(*prime_array);
*prime_array = NULL;
}
*count = 0;
return -1;
}
以下为简单测试代码
int main(int argc, char* argv[]){
int i1 = 200000014;
unsigned int i2 = 0xFFFFFFFF;
int count = 0;
int* prime_array = NULL;
printf("小于等于 %d 的质数有 n/ln(n)==%.0f 个。\n", i1, (double)i1 / log(i1));//10463629
printf("小于等于 0xFFFFFFFF 的质数有 n/ln(n)==%.0f 个。\n", (double)i2 / log(i2));//193635251
eratosthenes_sieve(i1,&count,&prime_array);
printf("小于等于 %d 的质数有 %d 个。\n", i1, count);//11078937
//for (int i = 0; i < count; i++) {
// printf("%d,", prime_array[i]);
//}
int a= 64577;
printf("%d is prime %d\n",a , is_prime_optimized(a));
for (int i = 0; i < count; i++) {
while (0 == a % prime_array[i]) {
printf("%d ", prime_array[i]);
a = a / prime_array[i];
}
if (1 == a)break;
}
if (prime_array) {
free(prime_array);
}
return 0;
}
win11下vs2022的CMakeLists.txt内容如下
cmake_minimum_required(VERSION 3.10)
project(ctest VERSION 0.1 LANGUAGES C)
set(CMAKE_C_STANDARD 99)
add_executable(ctest main.c)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_options(ctest PRIVATE -O0 -g -DDEBUG)
else()
target_compile_options(ctest PRIVATE -O2 -g)
endif()