Fibonacci’s sexagesimals
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.
APL (Dyalog Unicode), 90 bytes (using classic ⎕AV
)
⎕CY'dfns'
'(·E)?(·N)*·$'⎕R''∊'·',⍨¨¯5(↓,'E',↑)'N'@(0=≢¨)⊢roman'I'⍴⍨¨d↑⍨-6⌈≢d←60⊥⍣¯1⌊⎕×60*5
Try it online!
A full program that takes a number (actually any expression that evaluates to a single number is fine) from stdin and prints the result to stdout. Uses uppercase letters and middle dot as digit separator. The middle dot allows to shorten the regex at the end (since it doesn't need to be escaped, unlike *
), and the middle dot is in the classic character set.
How it works
⎕CY'dfns' ⍝ Load the dfns library to access `roman`
⌊⎕×60*5 ⍝ Multiply input by 60^5 and floor (to do things over integers)
60⊥⍣¯1 ⍝ Convert to base 60 using as many base-60 digits as needed
d← ⍝ Assign to d
d↑⍨-6⌈≢ ⍝ Pad with zeros to get 6 digits if there were fewer
'I'⍴⍨¨ ⍝ Convert each number to that many copies of 'I'
⊢roman ⍝ Normalize the Roman numeral
'N'@(0=≢¨) ⍝ Insert 'N' at zero digits (normalized result is empty)
¯5(↓,'E',↑) ⍝ Insert 'E' at 5 places from the end
∊'·',⍨¨ ⍝ Append a center dot to each numeral and flatten
'(·E)?(·N)*·$'⎕R'' ⍝ Regex replace to remove trailing E/Ns