Los sexagesimales de Fibonacci

15

Leonardo da Pisano, alias Fibonacci, contribuyó decisivamente a llevar el sistema de numeración hindú-árabe a Europa. Antes de eso, los matemáticos allí trabajaban en base sesenta con números romanos.

Por ejemplo, la raíz cuadrada de dos podría aproximarse como: una y veinticuatro partes de sesenta y cincuenta y una partes de tres mil seiscientos , y se escribiría como: i xxiv li , con la escala determinada por el contexto. En ese momento, se conocía la "nada" ( es decir, cero), pero no tenía una representación estándar en este sistema numérico.

Si Fibonacci hubiera ignorado estos dígitos decimales recién descubiertos que encontró durante sus viajes, seguramente habría abordado las deficiencias en el sistema actual. Este sistema mejorado lo llamaremos sexagesimales de Fibonacci .

Su tarea es escribir un programa, función o fragmento de código que tome un número de coma flotante en formato ASCII o binario y que salga en una base de sesenta números romanos. La entrada puede ser archivo, consola, línea de comando o argumento de función y la salida puede ser archivo o consola, lo que sea más fácil.

La salida puede ser mayúscula o minúscula, y debe incluir estas mejoras:

  • use n o N para indicar nulo, lo que significa que un lugar no tiene valor, es decir , "cero" (un problema con el sistema)
  • use e o E para indicar et correspondiente al punto sexagesimal (otro problema con el sistema)
  • use un punto medio · o un asterisco * para separar grupos de números romanos (otro problema más con el sistema)

Suponga que la entrada será de coma flotante con una mantisa no mayor que lix · lix · lix · lix · lix . Las fracciones inferiores a n · e · n · n · n · n · i pueden ignorarse. Entonces, siempre que la entrada tenga estas restricciones, como máximo se pueden generar diez grupos de números romanos con una e .

Números menores que i debe tener un líder n · e para asegurar el contexto está claro.

Algunos ejemplos: inputsalida

  • 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

La salida debe evitar la entrada innecesaria n · en la parte mantisa, e aislada , o n · final en la parte fraccionaria de la salida. Entonces, por ejemplo, n · n · n · n · i , i · e , e i · e · n · n · n · n · n son salidas incorrectas para una entrada de 1.

Las diferencias de más o menos n · e · n · n · n · n · i en la salida están dentro de las tolerancias y son aceptables.

La entrada es cualquier punto flotante legal en el idioma de su elección, por lo que puede incluir exponentes positivos o negativos siempre que la entrada no quede fuera del rango especificado anteriormente.

¡Y finalmente, se permiten los números romanos incorporados !


fuente
1
Por mucho que me encante la historia, fibonacci está reservado específicamente para la secuencia de fibonacci, a menos que desee cambiar la etiqueta wiki ...
Addison Crump
La etiqueta es para "Leonardo Fibonacci es conocido principalmente por la secuencia de Fibonacci (0, 1, 1, 2, 3, 5, 8, 13, ...)", por lo que diría que está destinado a la persona.
Creo que este desafío debería tener un poco de información sobre cómo funcionan los números romanos y el proceso involucrado, solo para ser autónomo.
Liam
1
Ese no es el uso previsto. He editado el extracto del wiki de la etiqueta para reflejar esto.
Dennis

Respuestas:

1

Python 3, 323 319 320 bytes

Esta respuesta implementa los sexagesimales de Fibonacci con el delimitador *y sin tener en cuenta la complejidad de Kolmogorov en las listas de números romanos (por ahora, al menos). Se hicieron intentos para unirse al bucle whiley forbajo el cual se generan los números romanos en un bucle, pero esos intentos aún no han tenido éxito. Cualquier sugerencia y sugerencia de golf es bienvenida y apreciada.

Editar: corrección de errores y golf.

Editar: Más corrección de errores.

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)

Sin golf:

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)
Sherlock9
fuente
3

C - 584 bytes

No compite (obviamente), pero sirve como inspiración:

#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;}

Guardar como fs.c, construir con gcc -o fs fs.c -lmy ejecutar como ./fs <arg>.

Casos de prueba:

$ ./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

Mayor mantisa y fracción:

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

Lo estoy usando doublecomo tipo de trabajo, por lo que la mayor fracción y mantisa combinadas excede la precisión nativa de ese tipo. Si lo usara long double, podría manejarlo.


fuente
int mainNo tiene que volver 0.
Zacharý
0

Haskell ( 333 322 315 bytes)

No estoy claro si se supone que el último dígito sexagesimal se redondea cuando lo hago o si se permite el truncamiento; esto se trunca, creo que el Python3 también podría hacerlo.

d n f 0=n;d n f x=f x
x!n=60*(x-fromInteger n)
f 0=[];f x=(\n->n:f(x!n))$floor x
l 0=[];l x=(\(d,m)->l d++[m])$divMod x 60
v=[50,40,10,9,5,4,1]
n&i|n==0=""|n>=v!!i=words"l xl x ix v iv i"!!i++(n-v!!i)&i|True=n&(i+1)
q=foldl1(\a x->a++'.':x).map(d"n"(&0))
p x=(\n->d"n"(q.l)n++d""((".e."++).q.take 5.f)(x!n))$floor x

(-9 bytes, ¡gracias H.PWiz ! -2 bytes eliminando wherepor (\->)$, -5 más inventando esta dfunción y jugando a++"."++xal golf a++'.':x).

Sin golf:


-- this function gets called `d` for default
onZero :: (Eq n, Num n) => z -> (n -> z) -> n -> z
onZero def f x 
 | x == 0    = def
 | otherwise = f x 

-- this function gets called `f`
fracPart :: RealFrac a => a -> [Integer]
fracPart x
  | x == 0    = [] 
  | otherwise = n : fracPart (60 * (x - fromInteger n))
    where n = floor x

-- this function gets called `l`
leadPart :: Integral n => n -> [Integer]
leadPart x
  | x == 0    = [] 
  | otherwise = leadPart div ++ [ mod ]
    where (div, mod) = x `divMod` 60

-- these get called `v`
romanValues :: [Integer]
romanValues = [50, 40, 10, 9, 5, 4, 1]

-- these get inlined with `words`, and correspond to the values above
romanLetters :: [String]
romanLetters = ["l", "xl", "x", "ix", "v", "iv", "i"]

-- this becomes (&)
romanNumeralLoop :: Integer -> Int -> String
romanNumeralLoop n i
 | n == 0                  = "" 
 | n >= (romanValues !! i) = (romanLetters !! i) ++ romanNumeralLoop (n - (romanValues !! i)) i
 | otherwise               = romanNumeralLoop n (i + 1)

-- this becomes `q`
concatRomanWithDots :: [Integer] -> String
concatRomanWithDots numbers = concatWithDots (map toRoman numbers)
  where 
    toRoman = onZero "n" (\x -> romanNumeralLoop x 0)
    concatWithDots = foldl1 concatDot
    concatDot acc item = acc ++ "." ++ item

-- this becomes `p`
solve x = onZero "n" elseRomanizeLeadPart n ++ onZero "" elseRomanizeFracPart f
  where
    n = floor x
    f = 60 * (x - fromInteger n) 
    elseRomanizeLeadPart l = concatRomanWithDots (leadPart l)
    elseRomanizeFracPart f = ".e." ++ concatRomanWithDots (take 5 (fracPart f))

El método de convertir números enteros a números romanos fue robado descaradamente de Thomas Ahle en StackOverflow y solo jugó un poco.

CR Drost
fuente
["l","xl","x","ix","v","iv","i"]puede serwords"l xl x ix v iv i"
H.PWiz
@ H.PWiz gracias, incorporado!
CR Drost