Pascal fractals in C
A complete program. Standard C, a compiler, and the rule behind the shape.

Run it in three steps.
- Save the source.
Download pascal.c into a folder on your computer.
- Compile it.
In that folder, run this with GCC or Clang:
cc -std=c11 -O2 pascal.c -lm -o pascal - Make the image.
./pascalOpen
pascal.svgin a browser to see the result.
On Windows with GCC, name the executable pascal.exe and run it from the same folder.
How the picture is built
Construct Pascal rows by adding the two neighbors above, reducing every result modulo MODULUS. Draw a small triangle at each nonzero residue. Modulo two, the recursively repeated parity pattern is the Sierpinski arrangement.
Make it your own
ROWS=128; MODULUS=2. Try moduli 3, 5, or 7 and row counts near powers of the chosen prime.
Only residues are computed, avoiding full binomial coefficient overflow. Different or composite moduli produce different structures. Use a small modulus so the sum of two residues fits int; very large ROWS uses large stack arrays. Each run produces one image; use Graphic mode for the interactive animation.
/* Arithmos: pascal
* Compile: cc -std=c11 -O2 pascal.c -lm -o pascal
* Run: ./pascal
* Output: pascal.svg (open this file in a browser)
* Optional output path: ./pascal 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;}
/* Pascal triangle modulo MODULUS. Compute residues directly to avoid
enormous binomial coefficients. Edit MODULUS (>=2) and ROWS. */
static void draw(void) {
enum { ROWS=128, MODULUS=2 };
int row[ROWS+1]={0},next[ROWS+1]={0};row[0]=1;
if(MODULUS<2){nt_text(50,80,"MODULUS must be at least 2.");return;}
double unit=fmin(900.0/ROWS,580.0/(ROWS*sqrt(3.0)/2)),top=50;
for(int r=0;r<ROWS;++r) {
for(int k=0;k<=r;++k)if(row[k]) {
double x=500+(k-r/2.0)*unit,y=top+r*unit*sqrt(3.0)/2;
double t=.7*(row[k]-1)/fmax(1,MODULUS-2)+.3*r/ROWS;
char color[8];nt_color(t,color);
fprintf(nt_out,"<path d=\"M%.4f %.4f L%.4f %.4f L%.4f %.4f Z\" fill=\"%s\" fill-opacity=\".94\"/>\n",
x,y,x+unit*.48,y+unit*.81,x-unit*.48,y+unit*.81,color);
}
next[0]=next[r+1]=1;
for(int k=1;k<=r;++k)next[k]=(row[k-1]+row[k])%MODULUS;
memcpy(row,next,(r+2)*sizeof *row);
}
nt_text(50,675,"Nonzero remainders are colored; modulo 2 produces the Sierpinski parity pattern.");
}
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] : "pascal.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;
}