Sexagesimals de Fibonacci


15

Leonardo da Pisano, também conhecido como Fibonacci, foi fundamental para trazer o sistema numérico hindu-árabe para a Europa. Antes disso, os matemáticos trabalhavam na base sessenta com algarismos romanos.

Por exemplo, a raiz quadrada de dois pode ser aproximada como: uma e vinte e quatro partes de sessenta e cinquenta e uma partes de três mil e seiscentos e escrita como: i xxiv li , com a escala determinada pelo contexto. Na época, o “nada” era conhecido ( ou seja, zero), mas não tinha representação padrão nesse sistema numérico.

Se Fibonacci tivesse ignorado esses dígitos decimais que encontrara durante suas viagens, ele certamente teria abordado as deficiências no sistema atual. Esse sistema aprimorado chamaremos de sexagesimais de Fibonacci .

Sua tarefa é escrever um programa, função ou snippet de código que use um número de ponto flutuante no formato ASCII ou binário e faça a saída em sessenta algarismos romanos base. A entrada pode ser arquivo, console, argumento de linha de comando ou função e a saída pode ser arquivo ou console, o que for mais fácil.

A saída pode ser maiúscula ou minúscula e deve incluir estas melhorias:

  • use n ou N para indicar nulo, o que significa que um local não tem valor, ou seja , "zero" (um problema com o sistema)
  • use e ou E para indicar et correspondente ao ponto sexagesimal (outro problema com o sistema)
  • use um ponto do meio · ou um asterisco * para separar grupos de algarismos romanos (mais um problema com o sistema)

Suponha que a entrada será um ponto flutuante com mantissa não superior a lix · lix · lix · lix · lix . Frações menores que n · e · n · n · n · n · i podem ser ignoradas. Portanto, desde que a entrada tenha essas restrições, no máximo dez grupos de algarismos romanos com um e podem ser gerados.

Números menores que i deve ter um líder e n · para garantir o contexto é claro.

Alguns exemplos: 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

A saída deve evitar n · inicial desnecessário na parte da mantissa, e isolado ou rastreio · n na parte fracionária da saída. Assim, por exemplo, n · · n n n · · i , i · E , e i · e · · n n n · · · n n são saídas incorrectos para uma entrada de 1.

Diferenças de mais ou menos n · e · n · n · n · n · i na saída estão dentro das tolerâncias e são aceitáveis.

A entrada é qualquer ponto flutuante legal no idioma de sua escolha, portanto, pode incluir expoentes positivos ou negativos, desde que a entrada não fique fora do intervalo especificado acima.

E, finalmente, os números romanos embutidos são permitidos!


1
Tanto quanto eu amo a história, fibonacci é reservado especificamente para a seqüência de Fibonacci, a menos que você gostaria de mudar o wiki tag ...
Addison Crump

Tag is for "Leonardo Fibonacci é conhecido principalmente pela sequência de fibonacci (0, 1, 1, 2, 3, 5, 8, 13, ...).", Então diria que é para a pessoa.

Eu acho que esse desafio deve ter um pouco de informação sobre como os números romanos funcionam e o processo envolvido, apenas para ser independente.
Liam

1
Esse não é o uso pretendido. Eu editei o trecho da tag wiki para refletir isso.
Dennis

Respostas:


1

Python 3, 323 319 320 bytes

Esta resposta implementa os sexagesimais de Fibonacci com o delimitador *e sem considerar a complexidade de Kolmogorov nas listas de algarismos romanos (por enquanto, pelo menos por enquanto). Tentativas foram feitas para unir o loop whilee forsob o qual os números romanos são gerados em um loop, mas essas tentativas ainda não foram bem-sucedidas. Todas as dicas e sugestões de golfe são bem-vindas e apreciadas.

Edit: Reparação de bugs e golfe.

Edit: Mais correção de bugs.

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)

3

C - 584 bytes

Não concorrente (obviamente), mas para servir de inspiração:

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

Salve como fs.c, construa com gcc -o fs fs.c -lme execute como ./fs <arg>.

Casos de teste:

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

Maior mantissa e fração:

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

Como estou usando doubleo tipo de trabalho, a maior mantissa e fração combinada excede a precisão nativa desse tipo. Se eu usasse long double, poderia lidar com isso.


int mainnão precisa retornar 0.
Zachary

0

Haskell ( 333 322 315 bytes)

Não estou claro se o último dígito sexagesimal deve ser arredondado quando o faço ou se o truncamento é permitido; isso trunca, acho que o Python3 pode também?

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, graças a H.PWiz ! -2 bytes ao eliminar wherepor (\->)$, -5 mais ao inventar esta dfunção e jogar golfea++"."++x paraa++'.':x .)

Ungolfed:


-- 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))

O método de conversão de números inteiros em algarismos romanos foi roubado descaradamente de Thomas Ahle no StackOverflow e apenas jogou um pouco de golfe.


["l","xl","x","ix","v","iv","i"] pode ser words"l xl x ix v iv i"
H.PWiz

@ H.PWiz obrigado, incorporado!
CR Drost
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.