BookmarkSubscribeRSS Feed
RichardDeVen
Barite | Level 11

"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.

cisterci_digits.png

 

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);

RichardADeVenezia_0-1605556059513.png

 

1 REPLY 1

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 1 reply
  • 1137 views
  • 11 likes
  • 2 in conversation