Table of Contents

Title Page/Table of Contents -- Economics 101, a Novel

Economics 101, A Novel (A College and Desert Island Love Story) by Joel Matthew Rees (Copyright 2016-2021, Joel Matthew Rees.) A...

Wednesday, May 5, 2021

Economics 101, a Novel, ch 1 pt 4b -- Hexadecimal Clock Time

Previous: Letters Home Table of Contents


It's not essential to the story to understand how Xhilr time compares to Earth time -- which is a good thing, because, as I've mentioned, the distances are relativistic, and what with biochemistry differences and such, comparison really isn't meaningful. So this chapter really isn't essential. (You can skip it if you're so inclined.)

But the sixteen-hour, well, sixteen chip, clock ...

I considered sweeping hexadecimal time under the rug along with a lot of other differences that would interfere with the flow of the story. But, well, I'm a geek.

Whether you divide the day into sixteen chippu or twenty-four hours, it doesn't change the thermodynamics -- the flow of consciousness through time. All that changes is where you set the markers and how many you set.

(Hey, there have been experiments in decimal time in recent history on our earth, for what that's worth. Not as popular as the other experiments in decimal metrics, somehow.)

So I could have just translated their hexadecimal time to 24/12 hour time, and it probably wouldn't have interfered too much with telling the story. 

But, since I'm such a geek, I thought I should give you some more detail about how a hexadecimal clock translates to a twenty-four hour clock, in addition to the two clocks I keep showing you.

  

(You should note that the one on the right is not quite the clock Nystrom used as the clock of his tonal numbering system in our world. Close, but not quite.)

First, let's look at a chart of the relationship between days, hours, minutes, and seconds in the familiar 24-hour clock. This is stuff you know, although you usually don't think about it in this kind of detail. The detail isn't really important, it's just here for reference:

24-hour
Day
Per-day Per-hour Per-minute Per-second
Seconds 24×602
= 86400
602
= 3600
60 1
Minutes 24×60
= 1440
60 1 1/60
Hours 24
1 1/60
1/3600
Days 1 1/24
1/1440 1/86400

 

Now let's look at the hexadecimal clock vs. hexadecimal hour, etc. Again, nobody's going to test you on the numbers, they're just here for reference. But you might want to notice that these are all regular fractions in powers of sixteen. You'll also notice that the hexadecimal second is a tiny bit larger fraction of a day than the 24-hour clock second (1/65536 > 1/86400). 

(And you might think about whether you'd want to use this kind of clock on Earth.):

16-hour
Day
Per-day Per-
long hour
Per-
long minute
Per-
short minute
Per-
hexadecimal
second
Seconds 164
= 65536
163
= 4096
162
= 256
16
1
Short
Minutes
163
= 4096
162
= 256
16 1 1/16
Long
Minutes
162
= 256
16
1 1/16
1/256
Long
Hours
16
1 1/16
1/256
1/4096
Days 1 1/16
1/256 1/4096 1/65536

 

Comparing hexadecimal time units to their nearest twenty-four hour day units, we can write the following table of equivalences:

  • 1 long hour (hexadecimal hour) is 90 minutes, or 1 1/2 hours
  • 1 long minute is 5.625 minutes (5 5/8)
  • 1 short minute is about 21.1 seconds (21.09375) 
  • 1 hexadecimal second is about 1.3 seconds (1.318359375)

------

If you want to see the actual math, here it is (with reductions and inverse factors for reference):

  • 24 hours == 16 long hours (or 3:2) --
    (2/3 lhr/hr)
    1 1/2 hr/lhr × 60 min/hr
    => exactly 90 minutes per long hour
  • 1440 minutes == 256 long minutes (or 45:8) --
    (8/45 lmin/min)
    45/8 min/lmin
    => exactly 5.625 minutes per long minute
  • 1440 minutes == 4096 short minutes (or 45:128) --
    (128/45 shmin/min)
    45/128 min/shmin × 60 sec/min (45×15=675 => 675/32)
    => exactly 21.09375 seconds per short minute 
  • 86400 seconds == 65536 hexadecimal seconds (or 675:512)
    (512/675 hexsec/sec)
    675/512 sec/hexsec
    => exactly 1.318359375 seconds per hexadecimal second 

A convenient aspect of pure hexadecimal time notation is that the fraction point can come anywhere, and the digits don't change:

  • 8.8hexclock, or 8:80hex, is a half a hexadecimal hour past noon (12:45:0024hr),
    and 88sixteen long minutes is 8.8sixteen hexadecimal hours.
  • 8.1hexclock, or 8:10hex, is a long minute past noon (12:05:37.524hr),
    and 81sixteen long minutes is 8.1sixteen hexadecimal hours.
  • 8.08hexclock, or 8:08hex, is half a long minute past noon (12:02:48.7524hr),
    and 808sixteen short minutes is 80.8sixteen long minutes.
  • 8.01hexclock, or 8:01hex, is a short minute past noon (about 12:00:21.124hr),
    and 801sixteen short minutes is 8.01sixteen hexadecimal hours.
  • 8.008hexclock,  or 8:00:80hex is half a short minute past noon (about 12:00:10.624hr).
  • 8.001hexclock, or 8:00:1hex, is a hexadecimal second past noon (about 12:00:01.3224hr). 
  • 8.0008hexclock, or 8:00:08hex is half a hexadecimal second past noon (about 12:00:00.6624hr).
  • Etc.

You may find these factorizations useful in calculating the above:

  • 24=(23)(3)
  • 60=(22)(3)(5)
  • 1440=(25)(32)(5)
  • (4096=212)
  • 1440:4096
    (32)(5):(27)
    45:128
  • 86400=(27)(33)(52)
  • 65536=(216)
    86400:65536
    (33)(52):(29)
    675:512

     ------

    Now, for Bobbie and Karel,

    • A long hour, one sixteenth of a day, is a chip, the digit before the first delimiter in their equivalent of colon notation --
      8: is noon to the long/hexadecimal hour, or to the chip.
    • A long minute, one sixteenth of a chip, is a gohb, the first digit after the first colon equivalent in their notation --
      8:0 is noon, to the long minute, or gohb.
    • A short minute, one sixteenth of a gohb, is a bun, the second digit after the first colon equivalent --
      8:00 is noon, to the short minute, or bun.
    • A hexadecimal second, one sixteenth of a bun, is a tic. This will be the first digit after the second colon --
      8:00:0 is noon, to the hexadecimal second, or tic.
    • One sixteenth of a tic is a shæn, which is rarely written in non-technical use --
      8:00:00 is noon, to the shæn. 
    • One sixteenth of a shæn is ... oh, never mind, that's 1/256 of a hexadecimal second, and it sounds like a swear word in English. We won't need it. Not in this novel. I think.
    But remember, a day on Xhilr is not a day on the Earth. Converting 24 hour time to hexadecimal time doesn't convert Earth time to Xhilr time. Nor does converting hexadecimal time to 24 hour time convert Xhilr time to ours.

    I did try to calculate it out once using hyperfine transitions, but they apparently found rubidium and caesium too difficult to work with, using other elements for their atomic clocks -- which at once adds uncertainty to the math and raises questions about how meaningful it really is to try to compare time there with time here.

    For what it's worth, I got a result of a bit more than 91 earth minutes to a chip. That makes their day a bit more than one percent longer than ours, which is an uncomfortable coincidence, making me even more suspicious of my results.

    Even though it looks pretty close, it's light years away.

    I have a tool for converting between the hexadecimal clock and the twenty-four hour clock, as long as you keep both measurements on the same planet. 

    I've written it in several languages, just for fun. I use whichever is convenient. These are all command line tools, just to keep things simple. 

    *****

    The first version was written in the the arbitrary precision Basic Calculator tool, bc, that is part of most Unix and Unix-like OS distributions that include a command line:

    ----------


    /* Q&D bc definitions for converting between hex and 24:60 time.
    ** Joel Matthew Rees, May 2021, Amagasaki, Japan
    ** Copyright claimed, all rights reserved.
    ** Permission granted to use this source code for personal
    ** or small-group educational purposes.
    */ define intpart( f ) { auto oldscale, part; oldscale = scale; scale = 0; part = f / 1; scale = oldscale; return part; } /* Keep it functional no matter what ibase is set to: */ k6 = 2 + 2 + 2; k10 = 2 * 2 * 2 + 2; k12 = ( 2 + 1 ) * 2 * 2; k16 = 2 * 2 * 2 * 2; k24 = 2 * k12; k60 = k6 * k10; k256 = k16 * k16; m60perday = k24 * k60; m256perday = k16 * k256; define tohexmin( h, m ) {
    return ( ( h * k60 + m ) * m256perday ) / m60perday;
    } kto16 = m256perday / m60perday; kto16epsilon = m60perday/( k10 ^ ( scale - 1 ) ) define tohextime( h, m ) { auto hexminutes, hexhours, oldobase, xmino; hexminutes = tohexmin( h, m ); hexhours = intpart( ( hexminutes + kto16epsilon ) / k256 ); xmino = intpart( hexminutes - hexhours * k256 ); oldobase = obase; obase = k16; print hexhours, ":", xmino, "\n"; obase = oldobase; return hexminutes; }
    define to24min( xh, xm ) {
    return ( ( xh * k256 + xm ) * m60perday ) / m256perday
    } kto24epsilon = m256perday/( k10 ^ ( scale - 1 ) ) kto24 = m60perday / m256perday; define to24time( xh, xm ) { auto minutes, hours, oldobase, mino; minutes = to24min( xh, xm ); hours = intpart( ( minutes + kto24epsilon ) / k60 ); mino = intpart( minutes - hours * k60 ); oldobase = obase; obase = k10; print hours, ":", mino, "\n"; obase = oldobase; return minutes }

    ----------

    Start up a bc session in your terminal window, with the library option (for scale): 

    bc -l

    You should get a copyright notice. If it's a gnu bc, you should also get a license notice. After that you get  a flashing cursor on a new line. Come back here, select the source and copy it. Go back to the terminal window and paste it in (probably using a right-click context menu). Or you can type it in if you want to focus on understanding the source code.

    Then you can use tohextime() and to24time() as in the examples below. It's a little tricky. Making it more user friendly would make the algorithm harder to read in the source.

    Note that the input uses a comma, per bc's function call syntax.

    Note also that the output is a clock time in the appropriate base, with a colon separator, followed by a fractional time in the current output base.

    Watch the use of ibase to switch back and forth between hexadecimal and decimal input, and the use of obase to get the hexadecimal fraction output:

    tohextime(8,34)
    5:B6
    1462.04444444444444444444
    ibase=16
    to24time(5,B6)
    8:33
    513.98437500000000000000
    ibase=5+5
    obase=16
    tohextime(8,34.0444444)
    5:B6
    5B6.2BBDBF6D7BCFDEE31
    obase=10
    ibase=16
    to24time(5,B6.2BBDC)
    8:34
    514.04444296875000000000  

    As you can see in this example, even though bc is an arbitrary precision calculator, I have only carried the calculations out to the minutes and short/hexadecimal minutes. So it will sometimes be off one or two in the last column. You can use the fractional output to fudge that, as can also be seen in the example.

    (The reason I use "ibase=5+5" to switch back to decimal is not obvious until you consider what "ibase=10" means when ibase is set to 16 -- or anything besides ten.)

     

    *****

     

    The next version I wrote was in Forth, because I have the gforth interpreter installed on my Android phone. It should work with no or minimal modification on a variety of Forth interpreters, including most 16-bit interpreters. It may be necessary to look up your interpreter's version of mixed-precision */MOD and /MOD .

    I did this one in integer math, to keep it simpler and make it as portable as possible to other Forth interpreters and OSses:

    ---------- 

    ( Q&D Forth definitions for converting between hex time and 24:60 time. )
    ( Joel Matthew Rees, May 2021, Amagasaki, Japan )
    ( Copyright claimed, all rights reserved. )
    ( Permission granted to use this source code for personal )
    ( or small-group educational purposes. )
    decimal 24 60 * constant m60perday m60perday 2 / constant halfm60perday 16 256 * constant m256perday m256perday 2 / constant halfm256perday : to16min ( hours minutes --- hexminutes ) swap 60 * + m256perday m60perday */mod swap halfm60perday < 0= if 1+ then ; ( Note output order inverted from input. ) : to16time ( hours minutes --- hexminutes hexhours ) to16min 256 /mod ; : to60min ( hexhours hexminutes --- minutes ) swap 256 * + m60perday m256perday */mod swap halfm256perday < 0= if 1+ then ; ( Note output order inverted from input. ) : to24time ( hexhours hexminutes --- minutes hours ) to60min 60 /mod ;

    ----------

    Again, you'll start up your Forth interpreter, either in a terminal session or as a terminal session. Then you'll select the source from above, copy it, and paste it into the terminal session, probably using the right-click context menu. Or, again, typing it in will give you a chance to familiarize yourself with the source code. 

    If your interpreter is case-sensitive and requires the built-in words to be upper case, and you don't want to type it in by hand, you can paste the source into a text editor, save it as something like "hextime.fs", and convert the source to upper-case easily with the Unix-like OS command-line tool tr:

    tr [a-z] [A-Z] < hextime.fs > hextimeU.fs

    Use it as follows, typing the hours or long hours, followed by the minutes, then the conversion function:

    8 34 to16time . . 5 182  ok
    8 34 to16time hex . . 5 B6  ok
    5 B6 to24time decimal . . 8 34  ok
    23 59 to16time hex . . F FD  ok
    F FD to24time decimal . . 23 59  ok
    

    Rather than directly storing the desired numeric conversion base in BASE, as

    16 BASE !

    5 5 + BASE !

    you can use HEX to switch to hexadecimal base, and DECIMAL to switch to decimal. These are provided in Forth for basically for the same reason you used ibase=5+5 instead of ibase=10 to switch back to decimal in bc

     

    *****

     

    The third version I wrote was in C, just because I was feeling frisky or something. It can be compiled with any ANSI standard C compiler (not C++), and linked to the standard C library. Apple's clang and the widely available gcc should work just fine. 

    For some versions of Small C, or for pre-ANSI C, certain modifications may be necessary, you'll probably know which.

    I really should have factored it out more carefully, and tried harder to fix the errors in the final digit, but floating point C is just too easy to write like this:

    ----------

    /* A q&d C program for converting between hexadecimal time and 24:60 time:
    ** Joel Matthew Rees, May 2021, Amagasaki, Japan
    ** Copyright claimed, all rights reserved.
    ** Permission granted to use this source code for personal
    ** or small-group educational purposes.
    */
    
    
    #include <stdio.h>
    #include <stddef.h>
    #include <stdlib.h>
    
    
    int main( int argc, char * argv[] )
    {
       if ( argc < 2 
            || ( ( argv[ 1 ][ 0 ] == '-' ) && ( argv[ 1 ][ 1 ] == '?' ) ) )
       {
          printf( "usage: %s { <24hr-time> | -x <hextime> }\n", argv[ 0 ] );
          return EXIT_SUCCESS;
       }
       else if ( argv[ 1 ][ 0 ] == '-' && argv[ 1 ][ 1 ] == 'x' )
       { /* from hex time to 24 hour time */
          double dayfrac = 0.0;
          double minutes = 0.0;
          long time = 0;
          char * parse = NULL;
    
          if ( argc > 2 )
          {
             time = strtol( argv[ 2 ], &parse, 16 );
             if ( parse > argv[ 2 ] && * parse == ':' )
             {
                char * parse2 = NULL;
    
                dayfrac += time / 16.0;
                time = strtol( ++parse, &parse2, 16 );
                if ( parse2 > parse )
                {
                   dayfrac += time / ( 16.0 * 256.0 );
                }
             }
          }
          dayfrac *= 24.0;
          time = (long) ( dayfrac + 1.0 / 120.0 );
          dayfrac -= time;
          minutes = dayfrac * 60.0;
          printf( "%ld:%02ld\n", time, (long) ( minutes + 0.5 ) );
          printf( "minutes: %g\n", minutes );
       }
       else 
       {
          double dayfrac = 0.0;
          double xminutes = 0.0;
          long time = 0;
          char * parse = NULL;
    
          if ( argc > 1 )
          {
             time = strtol( argv[ 1 ], &parse, 10 );
             if ( parse > argv[ 1 ] && * parse == ':' )
             {
                char * parse2 = NULL;
    
                dayfrac += time / 24.0;
                time = strtol( ++parse, &parse2, 10 );
                if ( parse2 > parse )
                {
                   dayfrac += time / ( 24.0 * 60.0 );
                }
             }
          }
          dayfrac *= 16.0;
          time = (long) ( dayfrac + 1.0 / 512.0 );
          dayfrac -= time;
          xminutes = dayfrac * 256.0;
          printf( "%lX:%02lX\n", time, (long) ( xminutes + 0.5 ) );
          printf( "hexadecimal minutes (decimal): %g\n", xminutes );
       }
    }
    
    

    ----------

     Select the source and copy it, paste it into a text editor, save it as something like "hextime.c", and compile it with something like 

    $ cc -Wall -o hextime hextime.c

    I parse the time from the command-line parameters, so use the colon in the clock time parameter when calling the program. 

    Use the -x option to convert from hexadecimal time to 24 hour time:

    $ ./hextime 8:34
    5:B6
    hexadecimal minutes (decimal): 182.044
    $ ./hextime -x 5:B6
    8:34
    minutes: 33.9844
    $ ./hextime 17:00
    B:55
    hexadecimal minutes (decimal): 85.3333
    $ ./hextime -x B:55
    17:00
    minutes: -0.117188
    $ ./hextime 23:59
    F:FD
    hexadecimal minutes (decimal): 253.156
    $ ./hextime -x F:FD
    23:59
    minutes: 58.9453
    


     *****


    Okay, here's a C program using integer math, just because I could. Some people say I waste my time, but it helps me gain confidence that the programs here are more-or-less correct.

    Structurally, the calculations follow the Forth code, while the argument parsing follows the floating point C version.

    It may also help you follow the formulae being used. If so, it was doubly worth it:

    ----------

    /* A q&d C program for converting between hexadecimal time and 24:60 time
    ** using integer math:
    ** Joel Matthew Rees, May 2021, Amagasaki, Japan
    ** Copyright claimed, all rights reserved.
    ** Permission granted to use this source code for personal
    ** or small-group educational purposes.
    */
    
    
    #include <stdio.h>
    #include <stddef.h>
    #include <stdlib.h>
    
    
    #define M60perDAY 	( 24 * 60 )
    #define HalfM60perDAY 	( M60perDAY / 2 )
    #define M256perDAY	( 16 * 256 )
    #define HalfM256perDAY	( M256perDAY / 2 )
    
    
    long tohexminutes( long hours, long minutes )
    {
       long dminutes = hours * 60 + minutes;
       long minprod = dminutes * M256perDAY;
       long xminutes = minprod / M60perDAY;
       long remainder = minprod % M60perDAY;
       if ( remainder >= HalfM60perDAY )
       {
          ++xminutes;
       }
       return xminutes;
    }
    
    
    long to60minutes( int xhours, int xminutes )
    {
       long dminutes = xhours * 256 + xminutes;
       long minprod = dminutes * M60perDAY;
       long minutes = minprod / M256perDAY;
       long remainder = minprod % M256perDAY;
       if ( remainder >= HalfM256perDAY )
       {
          ++minutes;
       }
       return minutes;
    }
    
    
    int main( int argc, char * argv[] )
    {
       if ( argc < 2 
            || ( ( argv[ 1 ][ 0 ] == '-' ) && ( argv[ 1 ][ 1 ] == '?' ) ) )
       {
          printf( "usage: %s { <24hr-time> | -x <hextime> }\n", argv[ 0 ] );
          return EXIT_SUCCESS;
       }
       else if ( argv[ 1 ][ 0 ] == '-' && argv[ 1 ][ 1 ] == 'x' )
       { /* from hex time to 24 hour time */
          long xhours = 0;
          long xminutes = 0;
          char * parse = NULL;
          long hours = 0;
          long minutes = 0;
    
          if ( argc > 2 )
          {
             xhours = strtol( argv[ 2 ], &parse, 16 );
             if ( parse > argv[ 2 ] && * parse == ':' )
             {
                char * parse2 = NULL;
    
                xminutes = strtol( ++parse, &parse2, 16 );
             }
          }
          minutes = to60minutes( xhours, xminutes );
          hours = minutes / 60;
          minutes %= 60;
          printf( "%ld:%02ld\n", hours, minutes );
       }
       else 
       {
          long hours = 0;
          long minutes = 0;
          char * parse = NULL;
          long xhours = 0;
          long xminutes = 0;
    
          if ( argc > 1 )
          {
             hours = strtol( argv[ 1 ], &parse, 10 );
             if ( parse > argv[ 1 ] && * parse == ':' )
             {
                char * parse2 = NULL;
    
                minutes = strtol( ++parse, &parse2, 10 );
             }
          }
          xminutes = tohexminutes( hours, minutes );
          xhours = xminutes / 256;
          xminutes %= 256;
          printf( "%lX:%02lX\n", xhours, xminutes );
       }
    }
    
      

    -----------

    To use it, copy and paste it into a text editor document, save, compile, and run it in a similar fashion as the floating point C version, above.


    *****

     

    I have not thoroughly tested all the above, but they are accurate enough for my use in this story.  If I needed accuracy to the seconds, it would be fairly straightforward to extend the accuracy that far on modern hardware, but would require implementing full 32-bit math on older 16-bit Forth interpreters. (Modern is 64-bit, but 32-bit Forths would have no problem.)

    This is a service chapter -- a freebie. 

    We now return you to the story.





    Table of Contents Next: Talking about Missions



      

    You can find more discussion of hexadecimal math in my Math and English blog, here: https://math-and-english.blogspot.com/2018/03/games-with-time-units.html

    No comments:

    Post a Comment

    Keep it on topic, please.