Converting rational numbers to an “alien” data format For a story I'm writing, I needed to convert 101⅐ (101 + 1/7 if that doesn’t show up for you) into base 47.

Expressing an integer in some base brings back memories of first learning how to program back in the days of 8-bit systems; it’s a fairly easy exercise. Doing so using a floating-point format is a bit harder, though. The final twist, identifying the repeating digits, is more challenging to do elegantly.

So I thought I’d do it in a different language from what I’m used to, just for fun and learning the new dialect.  And I thought it would be good to share, so here I am.  The vast majority of the posts here are (char or byte of source) code golf, but I’m more interested in an elegant expression in the target language.  Cyclomatic complexity isn’t a category, but atomic-code-golf is pretty close.



The program should take a rational number in a natural way, such as supplying three integers on the command line of the script invocation or standard input.  This does not count towards the score (nor does the error checking and defaults if you give it one value only).  The function (or part that is counted for score) should receive the three values; e.g. 101,1,7 for the example above.

The output is a sequence of code points that are transliterated into text output as follows:


digits 0 through 9 inclusive:  ‘0’ through ‘9’ in the normal way
digits 10 through 46: express as ‘[10]’ through ‘[46]’
negative sign: the normal ASCII ‘-’
separator: ‘:’
prefix: ‘#’


A number starts with the prefix ‘#’ and has up to three parts, separated by ‘:’.  Leading parts are omitted if zero.

The basic natural number (BNN) is encoded using the digits in base 47, outputted in little-endian.  That is, 99181 = 11×470 + 42×471 + 44×472 so the digits, in order output, are [11][42][44].

The last (possibly only) part of a number is an integer, which is a leading ‘-’ if the value is negative, followed by the digits of the BNN.  So, 99181 would be encoded as #[11][42][44] and −99181 would be encoded as #-[11][42][44].

The middle part, if needed, is an exponent as for scientific notation.  It states which power of the base (position) is the first digit listed.  In the case of integers, this is 470 so the 0-valued part is omitted.

Suppose you divide that by 47, shifting the radix point by one.  That is, 99181 ÷ 47 is the same digits but starting with 47−1; that is, 11×47−1 + 42×470 + 44×471, and the output becomes #-1:[11][42][44].  There are two parts, the first is the encoding for the integer −1, and the second is the digits as before.

Now it comes out so neat only if you divide by some power of 47.  Normally, a rational number made of small components will end up with a repeating sequence of digits.  In decimal, for example, ⅓ is .3333… and ⅐ (1/7) is .142857142857142857…  in the first case one digit repeats, in the second case 6 digits repeat.

In the alien real number format, the first part, if present, states how many digits are to be repeated.  So, the number 8½ would have a single digit [23] repeating forever, so we just encode one of them and state that 1 repeats: #1:-1:[23]8.  The first part is 1 (the encoded BNN for the value 1) which means that one digit is to be repeated.  The second part (negative sign and BNN) indicates that the first digit given is the 47-1 position.  The third part is the two digits needed: 26×47-1 + 8×470.



Somebody should check my results, but I think the correct output for (101 1 7) is:
#6:-6:[20][13][40][26][33]672.
Batch, 531 bytes

@echo off
set q=
set s=
set m=
if %1 lss 0 set m=-
set/ai=%m%%1,n=%2,d=%3,p=0
:i
set/ar=i%%47,i/=47
if %r% gtr 9 set r=[%r%]
set s=%s%%r%
if %i% gtr 0 goto i
:p
if %n%==0 goto n
set/ao=n,g=d%%47
if %g% gtr 0 goto g
set/ap+=1,d/=47,r=n/d,n%%=d
if %r% gtr 9 set r=[%r%]
set s=%r%%s%
goto p
:g
set/aq+=1,p+=1,r=n*47/d,n=n*47%%d
if %r% gtr 9 set r=[%r%]
set s=%r%%s%
if %n% neq %o% goto g
if %q% gtr 9 set q=[%q%]
set q=%q%:
:n
if %p% gtr 9 (set q=%q%-[%p%]:)else if %p% gtr 0 set q=%q%-%p%:
echo #%q%%m%%s%


Takes three parameters, whole number, numerator, denominator representing a mixed number in its lowest terms.