Ulam spirals are a favourite topic because I saw them myself by accident when I first ran this code across the number line. It is super cool and was the thing that made me want to make this website.
This version is not particularly dense plotting only 100,000 primes but you can still see the diagonal white lines crossing the page. The more primes the more obvious the pattern (below 1,000,000). You hit a pixelation limit anyway but it just is obvious that there is a diagonal pattern which seems impossible given that primes are supposedly occurring at intervals that aren't known.
The code is perhaps the best code on the site just because it renders something that I believe is significant. Ulam Spirals are an underrated secret sauce.
C++ Implementation
This program uses SDL2 to render the Ulam spiral visualization. You'll need to have SDL2 and SDL2_image installed, along with a primes.h header file containing your prime number data.
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include <vector>
#include <cmath>
#include "primes.h"
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;
// Direction vectors for spiral movement
const int dx[] = {1, 0, -1, 0}; // right, up, left, down
const int dy[] = {0, -1, 0, 1};
int main(int argc, char* args[]) {
// Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
std::cerr << "SDL could not initialize! SDL_Error: " << SDL_GetError() << std::endl;
return 1;
}
// Create window
SDL_Window* window = SDL_CreateWindow("Ulam Spiral",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (window == nullptr) {
std::cerr << "Window could not be created! SDL_Error: " << SDL_GetError() << std::endl;
return 1;
}
// Create renderer
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
// Create texture for rendering
SDL_Texture* texture = SDL_CreateTexture(renderer,
SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,
SCREEN_WIDTH, SCREEN_HEIGHT);
SDL_SetRenderTarget(renderer, texture);
// Fill with white background
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer);
// Set color for prime points (red)
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
// Start from center
int x = SCREEN_WIDTH / 2;
int y = SCREEN_HEIGHT / 2;
int direction = 0;
int steps_in_direction = 1;
int steps_taken = 0;
int turns = 0;
// Plot primes in spiral pattern
for (int n = 1; n <= 1000000 && x >= 0 && x < SCREEN_WIDTH && y >= 0 && y < SCREEN_HEIGHT; n++) {
// Check if n is prime
if (isPrime(n)) {
SDL_RenderDrawPoint(renderer, x, y);
}
// Move in current direction
x += dx[direction];
y += dy[direction];
steps_taken++;
// Check if we need to turn
if (steps_taken == steps_in_direction) {
steps_taken = 0;
direction = (direction + 1) % 4;
turns++;
// Increase step count every two turns
if (turns % 2 == 0) {
steps_in_direction++;
}
}
}
// Draw grid overlay (optional)
SDL_SetRenderDrawColor(renderer, 200, 200, 200, 128);
for (int i = 0; i < SCREEN_WIDTH; i += 10) {
for (int j = 0; j < SCREEN_HEIGHT; j += 10) {
SDL_RenderDrawPoint(renderer, i, j);
}
}
// Reset render target and display
SDL_SetRenderTarget(renderer, nullptr);
SDL_RenderCopy(renderer, texture, nullptr, nullptr);
SDL_RenderPresent(renderer);
// Save to PNG
SDL_Surface* surface = SDL_CreateRGBSurface(0, SCREEN_WIDTH, SCREEN_HEIGHT, 32,
0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
SDL_RenderReadPixels(renderer, nullptr, SDL_PIXELFORMAT_ARGB8888,
surface->pixels, surface->pitch);
IMG_SavePNG(surface, "ulam_spiral.png");
SDL_FreeSurface(surface);
std::cout << "Ulam spiral saved to ulam_spiral.png" << std::endl;
// Event loop
bool quit = false;
SDL_Event e;
while (!quit) {
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT) {
quit = true;
}
}
}
// Cleanup
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
Compiling
To compile this code, you'll need SDL2 and SDL2_image installed:
# macOS (with Homebrew)
brew install sdl2 sdl2_image
# Compile
g++ -std=c++17 ulam_spiral.cpp -o ulam_spiral \
-I/usr/local/include -L/usr/local/lib \
-lSDL2 -lSDL2_image
# Run
./ulam_spiral