"The forgotten number system" - Numberphile
"The Cistercian Numerals was created in the middle ages as a number system." - Crack the code
There is one glyph for each number from 0 to 9999... Hmm, perfect alignment for a double byte encoding (codelen=2) that would be rendered by a custom font built with PROC GFONT.
Build the custom font and a custom format
/* The forgotten number system * https://www.youtube.com/watch?v=9p55Qgt7Ciw&ab_channel=Numberphile * * The 4 digit number notation of the Order of Cistercians * * Coded: Richard DeVenezia, Nov 2020 */ /* Digit glyphs, https://www.youtube.com/watch?v=9p55Qgt7Ciw&t=463s 10 | 1 ____|____ | 1000 | 100 1's place glyph parts _ _ _ _ | | |_ |\ |/ |/ | | | | |_| |_| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 0 1 2 3 4 5 6 7 8 9 Tidbit: glyphs of combination 5 = 1 + 4 7 = 1 + 6 8 = 2 + 6 9 = 1 + 2 + 6 10's place mirrors 1's in y 100's place mirrors 1's in x 1000's place mirrors 1's in x and y */ data strokes; length digit 8; input digit x1 y1 x2 y2; datalines; 1 1 4 2 4 2 1 3 2 3 3 1 4 2 3 4 1 3 2 4 5 1 3 2 4 5 1 4 2 4 6 2 4 2 3 7 1 4 2 4 7 2 4 2 3 8 1 3 2 3 8 2 3 2 4 9 1 4 2 4 9 2 4 2 3 9 2 3 1 3 ; data fontdata; declare hash strokes (dataset:'strokes', multidata:'yes', ordered:'yes'); strokes.defineKey('digit'); strokes.defineData('x1', 'y1', 'x2', 'y2'); strokes.defineDone(); call missing (digit, x1, y1, x2, y2); do n = 0 to 9999; k = n; d3 = int ( k / 1000 ); k + ( -d3 * 1000 ); d2 = int ( k / 100 ) ; k + ( -d2 * 100 ); d1 = int ( k / 10 ); k + ( -d1 * 10 ); d0 = k; /* * mapping of decimal digits to hex nibbles (BCD'ish), offset digit by 03x to avoid 'unprintables` * digit nibble * 0 3 * 1 4 * 2 5 * 3 6 * 4 7 * 5 8 * 6 9 * 7 A * 8 B * 9 C * * 4 nibbles -> 2 bytes -> 2 characters (i.e. a codelen=2 char in GFONT parlance) */ c1 = byte((d3+3)*16+d2+3); /* 1000's and 100's */ c2 = byte((d1+3)*16+d0+3); /* 10's and 1's */ char = c1||c2; segment = 1; x = 1; y = 0; output; x = 1; y = 4; output; do while ( strokes.do_over(key:d0) = 0 ); /* 1's */ segment + 1; x = x1; y = y1; output; x = x2; y = y2; output; end; do while ( strokes.do_over(key:d1) = 0 ); /* 10's */ segment + 1; x = 2 - x1; y = y1; output; x = 2 - x2; y = y2; output; end; do while ( strokes.do_over(key:d2) = 0 ); /* 100's */ segment + 1; x = x1; y = 4 - y1; output; x = x2; y = 4 - y2; output; end; do while ( strokes.do_over(key:d3) = 0 ); /* 1000's */ segment + 1; x = 2 - x1; y = 4 - y1; output; x = 2 - x2; y = 4 - y2; output; end; end; stop; format _numeric_ 4.; drop k d0-d3 digit x1 y1 x2 y2; run; data formatdata; set fontdata; by n; if first.n; retain fmtname 'cisterci'; rename n=start char=label; keep n char fmtname; run; %if %sysfunc(libref(GFONT0)) ne 0 %then %do; libname gfont0 "%sysfunc(pathname(WORK))"; %end; proc gfont nodisplay data=fontdata name=cisterci resolution=2 uniform codelen=2; proc format cntlin=formatdata; run;
Show the digits
%macro cistercian_digits; data anno_digits; length style color $8 size 8 text $10; retain xsys ysys '5' function 'LABEL'; do _r = 1 to 4; z = 10**(_r-1); x = 0; y = 100 - _r * 100/5; * placement of row labels 20% 40% 60% 80%; size = 1.25; style = ''; position = '>'; text = catx("'",z,"s"); * row labels 1's, 10's, 100's, 1000's; output; do _c = 1 to 10; x = _c * 100/11 + 2; size = 4; style = 'CISTERCI'; position = '+'; text = put ( z * (_c-1), cisterci.); y = 100 - _r * 100/5; output; size = 1.25; style = ''; * clear style, reset font to ftext= session option; y = 100 - _r * 100/5 - 7; color = 'grey'; output; text = put(text, $hex4.); size = .9; y = y - 2; color = 'grey'; output; color = ''; end; end; * column labels at bottom of image (digits 0 to 9); y = 5; do _c = 1 to 10; x = _c * 100/11 + 2; size = 1.25; style = ''; text = cats(_c-1); output; end; format z x y size 6.2; drop _:; run; filename cisterci 'cistercian_digits.png'; goptions xpixels=600 ypixels=600 gsfname=cisterci ftext="Arial" goutmode=replace; ods html file='Cistercian_digits.html' nogtitle; proc ganno anno=anno_digits name="Cistercian Digits" gout=work.gseg; title1 h=12pt f='Arial' "Custom font - $2. and $HEX4. mappings to glyphs for a single"; title2 h=12pt f='Arial' "Cistercian digit at 0, 1, 2, and 3 powers of 10"; run; ods html close; %mend cistercian_digits; %cistercian_digits;
All the numbers
Download attached program for macro.
%cistercian_numbers (page_having=sum(num in (2020)) > 0);
Very cool post!
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.