14
\$\begingroup\$

Leonardo da Pisano a.k.a Fibonacci was instrumental in bringing the Hindu-Arabic numeral system into Europe. Before that, mathematicians there worked in base sixty with Roman numerals.

For example, the square root of two might be approximated as: one and twenty-four parts of sixty and fifty-one parts of three-thousand-six-hundred, and written as: i xxiv li, with the scaling determined by context. At the time, “nothingness” was known (i.e. zero), but had no standard representation in this number system.

Had Fibonacci ignored these new-fangled decimal digits he encountered during his travels, he surely would have addressed the deficiencies in the current system. This improved system we'll call Fibonacci’s sexagesimals.

Your task is to write a program, function or code snippet which takes a floating point number in ASCII or binary format and outputs in base sixty Roman numerals. The input can be file, console, command line or function argument and output can be file or console, whichever is easiest.

The output can be upper or lower case, and should include these improvements:

  • use n or N to indicate null meaning a place has no value, i.e. “zero” (a problem with the system)
  • use e or E to indicate et corresponding to the sexagesimal point (another problem with the system)
  • use a middle dot · or an asterisk * to separate groups of Roman numerals (yet another problem with the system)

Assume the input will be floating point with mantissa not greater than lix·lix·lix·lix·lix. Fractions less than n·e·n·n·n·n·i can be ignored. So, provided the input has these restrictions, at most ten groups of Roman numerals with one e can be outputted.

Numbers less than i should have a leading n·e to ensure the context is clear.

Some examples: inputoutput

  • 0n
  • 1i
  • 60i·n
  • 0.1n·e·vi
  • 3600i·n·n
  • 10.5x·e·xxx
  • 16777215i·xvii·xl·xx·xv
  • 3.1415926536iii·e·viii·xxix·xliv·n·xlvii

The output should avoid unnecessary leading in the mantissa part, isolated e, or trailing ·n in the fractional part of the output. So for example, n·n·n·n·i, i·e, and i·e·n·n·n·n·n are incorrect outputs for an input of 1.

Differences of plus or minus n·e·n·n·n·n·i in the output are within tolerances and acceptable.

The input is any legal floating point in the language of your choice, so can include positive or negative exponents as long as the input doesn't fall outside the range specified above.

And finally, Roman numeral built-ins are allowed!

\$\endgroup\$
  • 1
    \$\begingroup\$ As much as I love the history, fibonacci is reserved specifically for the fibonacci sequence, unless you'd like to change the tag wiki... \$\endgroup\$ – Addison Crump Feb 6 '16 at 0:00
  • \$\begingroup\$ Tag is for "Leonardo Fibonacci is mostly known for the fibonacci sequence (0, 1, 1, 2, 3, 5, 8, 13, ...).", so would say it's meant for the person. \$\endgroup\$ – Yimin Rong Feb 6 '16 at 3:31
  • \$\begingroup\$ I think this challenge should have a bit of info on how roman numerals work and the process involved, just to be self-contained. \$\endgroup\$ – Liam Feb 6 '16 at 17:50
  • 1
    \$\begingroup\$ That's not the intended use. I have edited the tag wiki excerpt to reflect this. \$\endgroup\$ – Dennis Feb 8 '16 at 2:29
2
\$\begingroup\$

Python 3, 323 319 320 bytes

This answer implements Fibonacci's sexagesimals with the delimiter * and without regard for Kolmogorov complexity in the lists of Roman numerals (for now, at least). Attempts were made to join the while and for loop under which the Roman numerals are generated under one loop, but those attempts have not yet met with success. Any golfing tips and suggestions are welcome and appreciated.

Edit: Bug fixing and golfing.

Edit: More bug fixing.

def f(x):
 v=divmod;f=x%1;n=int(x);d=",I,II,III,IV,V,VI,VII,VIII,IX".split(",");t=",X,XX,XXX,XL,L".split(",");z=["N"];a=f>0;s=z*0**n+["E"]*a
 while n:n,m=v(n,60);j,k=v(m,10);s=[z,[t[j]+d[k]]][m>0]+s
 for i in range(5*a):m,f=v(f*60,1);j,k=v(int(m),10);s+=[z,[t[j]+d[k]]][m>0]
 while s[-1:]==z*a:s.pop()
 return"*".join(s)

Ungolfed:

def f(x):
    integ = int(x)
    frac = x % 1
    units=",I,II,III,IV,V,VI,VII,VIII,IX".split(",")
    tens=",X,XX,XXX,XL,L".split(",")
    zero = ["N"]
    output = []
    a = frac != 0
    if integ == 0:
        output += z
    if a:
        output += ["E"]
    while integ > 0:
        integ, digit = divmod(integ, 60)
        j, k = divmod(int(digit), 10)
        if digit:
            output += [tens[j], units[k]]
        else:
            output += zero
    for i in range(5*a):
        digit, frac = divmod(frac*60, 1)
        j, k = divmod(int(digit), 10)
        if digit:
            output += [tens[j], units[k]]
        else:
            output += zero
    while output[-1:] == zero * a:
        output.pop()
    return "*".join(output)
\$\endgroup\$
3
\$\begingroup\$

C – 584 bytes

Non-competing (obviously), but to serve as inspiration:

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
char*f(int z){static char r[8];char*l[]={"","I","II","III","IV","V","VI","VII","VIII","IX"},*h[]={"","X","XX","XXX","XL","L"};if(!z)return"N";sprintf(r,"%s%s",h[z/10],l[z%10]);return r;}int main(int c,char**v){char*s="";int i,j,z[10],k=60;long x;double d,y;y=modf(atof(v[1]),&d);x=d;for(i=4;i>=0;i--){z[i]=x%k;x/=k;}for(i=5;i<=9;i++){z[i]=(y*=k);y-=z[i];}for(i=0;!z[i]&&i<4;i++);for(;i<5;i++){printf("%s%s",s,f(z[i]));s="*";}for(j=9;!z[j]&&j>=i;j--);if(i<=j)printf("*E");for(;i<=j;i++)printf("*%s",f(z[i]));printf("\n");return 0;}

Save as fs.c, build with gcc -o fs fs.c -lm, and run as ./fs <arg>.

Test cases:

$ ./fs 0
N
$ ./fs 1
I
$ ./fs 60
I*N
$ ./fs 0.1
N*E*VI
$ ./fs 3600
I*N*N
$ ./fs 10.5
X*E*XXX
$ ./fs 16777215
I*XVII*XL*XX*XV
$ ./fs 3.1415926536
III*E*VIII*XXIX*XLIV*N*XLVII

Largest mantissa and fraction:

$ ./fs 777599999
LIX*LIX*LIX*LIX*LIX
$ ./fs 0.999999998713992
N*E*LIX*LIX*LIX*LIX*LIX

I'm using double as the working type, so the largest mantissa and fraction combined exceeds the native accuracy of that type. If I used long double instead it could handle it.

\$\endgroup\$
  • \$\begingroup\$ int main doesn't have to return 0. \$\endgroup\$ – Zacharý Aug 1 '17 at 13:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.