"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!
April 27 – 30 | Gaylord Texan | Grapevine, Texas
Walk in ready to learn. Walk out ready to deliver. This is the data and AI conference you can't afford to miss.
Register now and lock in 2025 pricing—just $495!
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.