Collatz branches in C
A complete program. Standard C, a compiler, and the rule behind the shape.

Run it in three steps.
- Save the source.
Download collatz.c into a folder on your computer.
- Compile it.
In that folder, run this with GCC or Clang:
cc -std=c11 -O2 collatz.c -lm -o collatz - Make the image.
./collatzOpen
collatz.svgin a browser to see the result.
On Windows with GCC, name the executable collatz.exe and run it from the same folder.
How the picture is built
For starts 2 through STARTS, repeatedly halve an even value or replace an odd value by 3n+1. Reverse each completed trajectory from 1, and turn by ±TURN according to the next value’s parity. Overlay the fitted unit-step paths.
Make it your own
STARTS=300; CAP=2000 values per trajectory; TURN=11 degrees. Try turn angles from 7 to 17 degrees.
Only trajectories reaching 1 within CAP are drawn. The program checks unsigned 64-bit overflow before 3n+1. All default starts complete, but this finite visualization does not establish the unsolved universal Collatz conjecture. Each run produces one image; use Graphic mode for the interactive animation.
/* Arithmos: collatz
* Compile: cc -std=c11 -O2 collatz.c -lm -o collatz
* Run: ./collatz
* Output: collatz.svg (open this file in a browser)
* Optional output path: ./collatz my-image.svg
* Edit the constants in draw() to explore another case.
*/
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static FILE *nt_out;
#define NT_PI 3.14159265358979323846
/* The small SVG writer keeps this program free of graphics dependencies.
* Coordinates are pixels on a 1000 x 700 drawing surface.
* t runs from 0 to 1 through mint, blue, rose, and gold.
*/
static inline void nt_color(double t, char hex[8]) {
const double stops[4][3] = {
{91,227,201}, {128,146,240}, {218,138,220}, {244,200,127}
};
t = fmax(0.0, fmin(1.0,t)) * 3.0;
int band = (int)fmin(2.0,floor(t));
double blend = t - band;
int r[3];
for (int k=0;k<3;k++) r[k]=(int)lround(stops[band][k]*(1.0-blend)+stops[band+1][k]*blend);
snprintf(hex,8,"#%02x%02x%02x",r[0],r[1],r[2]);
}
static inline void nt_line(double x,double y,double X,double Y,double t,double alpha,double width) {
char color[8];nt_color(t,color);
fprintf(nt_out,"<path d=\"M%.3f %.3f L%.3f %.3f\" fill=\"none\" stroke=\"%s\" stroke-opacity=\"%.3f\" stroke-width=\"%.3f\"/>\n",x,y,X,Y,color,alpha,width);
}
static inline void nt_dot(double x,double y,double r,double t,double alpha) {
char color[8];nt_color(t,color);
fprintf(nt_out,"<circle cx=\"%.3f\" cy=\"%.3f\" r=\"%.3f\" fill=\"%s\" fill-opacity=\"%.3f\"/>\n",x,y,r,color,alpha);
}
static inline void nt_circle(double x,double y,double r,double t,double alpha,double width) {
char color[8];nt_color(t,color);
fprintf(nt_out,"<circle cx=\"%.3f\" cy=\"%.3f\" r=\"%.3f\" fill=\"none\" stroke=\"%s\" stroke-opacity=\"%.3f\" stroke-width=\"%.3f\"/>\n",x,y,r,color,alpha,width);
}
static inline void nt_rect(double x,double y,double w,double h,double t,double alpha) {
char color[8];nt_color(t,color);
fprintf(nt_out,"<rect x=\"%.3f\" y=\"%.3f\" width=\"%.3f\" height=\"%.3f\" fill=\"%s\" fill-opacity=\"%.3f\"/>\n",x,y,w,h,color,alpha);
}
static inline void nt_text(double x,double y,const char *text) {
fprintf(nt_out,"<text x=\"%.3f\" y=\"%.3f\" fill=\"#ededf3\" font-family=\"monospace\" font-size=\"16\">",x,y);
for (;*text;text++) {
if (*text=='&') fputs("&",nt_out);
else if (*text=='<') fputs("<",nt_out);
else if (*text=='>') fputs(">",nt_out);
else fputc(*text,nt_out);
}
fputs("</text>\n",nt_out);
}
static inline int nt_gcd(int a,int b) {a=abs(a);b=abs(b);while(b){int r=a%b;a=b;b=r;}return a;}
static inline int nt_prime(int n) {if(n<2)return 0;for(int d=2;d<=n/d;d++)if(n%d==0)return 0;return 1;}
/* Only trajectories reaching 1 within CAP are rendered. Unsigned overflow is
checked before 3n+1. Finite examples do not prove the Collatz conjecture. */
static int nt_collatz_chain(uint64_t start,uint64_t *chain,int cap) {
int n=0;uint64_t value=start;
while(n<cap) {
chain[n++]=value;if(value==1)return n;
if(value&1U) {
if(value>(UINT64_MAX-1)/3)return 0;
value=3*value+1;
} else value/=2;
}
return 0;
}
static void draw(void) {
enum { STARTS=300, CAP=2000 };
const double TURN=11.0*NT_PI/180.0; /* Editable turn angle, in degrees. */
uint64_t chain[CAP];
double xmin=0,xmax=0,ymin=0,ymax=0,scale=1,mx=0,my=0;
/* First pass fits every path; second pass draws the same exact rules. */
for(int pass=0;pass<2;++pass) {
if(pass){scale=fmin(900/fmax(1,xmax-xmin),580/fmax(1,ymax-ymin));
mx=.5*(xmin+xmax);my=.5*(ymin+ymax);}
for(int start=2;start<=STARTS;++start) {
int count=nt_collatz_chain((uint64_t)start,chain,CAP);
if(!count)continue;
double x=0,y=0,heading=-NT_PI/2;
char color[8];nt_color(start/(double)STARTS,color);
if(pass)fprintf(nt_out,"<path d=\"M%.3f %.3f",500-mx*scale,340-my*scale);
/* Reverse the trajectory from 1; predecessor parity bends it. */
for(int j=count-2;j>=0;--j) {
heading+=(chain[j]&1U)?-TURN:TURN;
x+=cos(heading);y+=sin(heading);
if(!pass) {
if(x<xmin)xmin=x;if(x>xmax)xmax=x;
if(y<ymin)ymin=y;if(y>ymax)ymax=y;
} else fprintf(nt_out," L%.3f %.3f",500+(x-mx)*scale,340+(y-my)*scale);
}
if(pass)fprintf(nt_out,"\" fill=\"none\" stroke=\"%s\" stroke-opacity=\"0.18\" stroke-width=\"1.15\"/>\n",color);
}
}
nt_text(50,675,"Collatz: reverse finite trajectories; parity supplies each bend");
}
int main(int argc, char **argv) {
if (argc > 2) {
fprintf(stderr, "Usage: %s [OUTPUT.svg]\n", argv[0]);
return EXIT_FAILURE;
}
const char *filename = argc == 2 ? argv[1] : "collatz.svg";
nt_out = fopen(filename, "wb");
if (!nt_out) { perror(filename); return EXIT_FAILURE; }
fputs("<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1000\" height=\"700\" viewBox=\"0 0 1000 700\">\n"
"<rect width=\"1000\" height=\"700\" fill=\"#171721\"/>\n", nt_out);
draw();
fputs("</svg>\n", nt_out);
int failed = ferror(nt_out);
if (fclose(nt_out) != 0) failed = 1;
if (failed) { fputs("Could not finish writing the image.\n", stderr); return EXIT_FAILURE; }
printf("Wrote %s\n", filename);
return EXIT_SUCCESS;
}