Build into dist/, list primes to 1,000,000 with timing, add wiki

This commit is contained in:
2026-10-20 01:07:36 +08:00
parent e4be228a5b
commit 42774d3d3a
8 changed files with 173 additions and 70 deletions
+1
View File
@@ -0,0 +1 @@
dist/
+14 -11
View File
@@ -1,36 +1,39 @@
# Builds prime_avx2 on Linux (gcc) and Windows (MinGW-w64 / MSYS2 gcc).
# Builds prime_avx2 into dist/ on Linux (gcc) and Windows (MinGW-w64 / MSYS2 gcc).
# make build
# make run build and run
# make clean remove build output
# make clean remove dist/
CC ?= gcc
CFLAGS ?= -O3 -mavx2 -Wall -Wextra
LDLIBS += -lm
DIST := dist
ifeq ($(OS),Windows_NT)
EXE := .exe
RM := del /Q /F
# make on Windows may use cmd.exe, which needs backslashes
RUN := .\prime_avx2$(EXE)
RMTARGET := prime_avx2$(EXE)
RUN := $(DIST)\prime_avx2$(EXE)
RMDIR := if exist $(DIST) rmdir /S /Q $(DIST)
else
EXE :=
RM := rm -f
RUN := ./prime_avx2
RMTARGET := prime_avx2
RUN := ./$(DIST)/prime_avx2
RMDIR := rm -rf $(DIST)
endif
TARGET := prime_avx2$(EXE)
TARGET := $(DIST)/prime_avx2$(EXE)
.PHONY: all run clean
all: $(TARGET)
$(TARGET): prime_avx2.c
$(TARGET): src/prime_avx2.c | $(DIST)
$(CC) $(CFLAGS) $< -o $@ $(LDLIBS)
$(DIST):
mkdir $(DIST)
run: $(TARGET)
$(RUN)
clean:
-$(RM) $(RMTARGET)
-$(RMDIR)
+24
View File
@@ -0,0 +1,24 @@
# Build and run
**English**
The `Makefile` is in the repository root and puts the executable in `dist/`.
It needs `gcc` (Linux, or MinGW-w64 / MSYS2 on Windows) and a CPU with AVX2.
```bash
make
```
```bash
make run
```
```bash
make clean
```
To save the primes and still see the time, redirect only standard output:
```bash
./dist/prime_avx2 > primes.txt
```
+34
View File
@@ -0,0 +1,34 @@
# Description
**English**
## Purpose
The program shows how fast a CPU is. How fast it looks depends on how the
program is written, so the number is a measure of the CPU and the code
together, not of the CPU alone.
## What it does
It tests every number from 0 to 1,000,000 with `is_prime_avx2`, which uses
AVX2 trial division by 6k ± 1 (four divisors per step). It prints each prime
on its own line and writes a summary line to standard error:
```text
Found 78498 primes from 0 to 1000000 in 13.806 ms
```
78,498 is the known count of primes up to 1,000,000, so the summary line also
works as a correctness check.
## Why the time depends on the code
The same CPU gives very different times for different programs:
- the algorithm (trial division, a sieve, a segmented sieve),
- the instruction set used (scalar code, AVX2, AVX-512),
- compiler and flags (`-O3 -mavx2`, MSVC `/O2 /arch:AVX2`),
- what is measured (only the search, or also printing to a console).
Here only the search is timed. Output is collected first and printed
afterwards, so console speed does not change the number.
+10
View File
@@ -0,0 +1,10 @@
# prime-numbers-c
**English**
A small C program that lists every prime number from 0 to 1,000,000 and
reports how long it took.
- [Description](Description): what the program is for
- [Results](Results): measured times on real hardware
- [Build and run](Build-and-Run): `make`, `make run`
+14
View File
@@ -0,0 +1,14 @@
# Results
**English**
Time to find all primes from 0 to 1,000,000. Only the search is timed.
| CPU | Result |
| --- | --- |
| 13th Gen Intel(R) Core(TM) i5-13600K | Found 78498 primes from 0 to 1000000 in 20.977 ms |
A result is only comparable with another when the code, compiler and flags
are the same. To add a result, run the program on your machine (see
[Build and run](Build-and-Run)) and add a row with your CPU name and the
summary line.
+4
View File
@@ -0,0 +1,4 @@
- [Home](Home)
- [Description](Description)
- [Results](Results)
- [Build and run](Build-and-Run)
+20 -7
View File
@@ -3,6 +3,7 @@
#include <stdint.h>
#include <inttypes.h>
#include <math.h>
#include <time.h>
#include <immintrin.h> // AVX2 intrinsics
// Returns true if n is prime, using AVX2 trial division by 6k +/- 1.
@@ -44,16 +45,28 @@ bool is_prime_avx2(uint64_t n) {
return true;
}
#define LIMIT 1000000u
// Seconds elapsed between two timespec_get(TIME_UTC) samples.
static double elapsed(const struct timespec *a, const struct timespec *b) {
return (double)(b->tv_sec - a->tv_sec) + (double)(b->tv_nsec - a->tv_nsec) / 1e9;
}
int main(void) {
// Known large prime: 1,000,000,007
uint64_t num = 1000000007;
static uint32_t primes[LIMIT / 2]; // pi(1e6) = 78498, so this is ample
size_t count = 0;
struct timespec t0, t1;
printf("Checking if %" PRIu64 " is prime using AVX2...\n", num);
// Time the computation only; printing is done afterwards.
timespec_get(&t0, TIME_UTC);
for (uint32_t n = 0; n <= LIMIT; n++)
if (is_prime_avx2(n)) primes[count++] = n;
timespec_get(&t1, TIME_UTC);
if (is_prime_avx2(num))
printf("%" PRIu64 " is a PRIME number.\n", num);
else
printf("%" PRIu64 " is a COMPOSITE number.\n", num);
for (size_t i = 0; i < count; i++)
printf("%" PRIu32 "\n", primes[i]);
fprintf(stderr, "Found %zu primes from 0 to %u in %.3f ms\n",
count, LIMIT, elapsed(&t0, &t1) * 1000.0);
return 0;
}