Dobrar a fração contínua de um número

21

Sua tarefa é, dada x, saída 2*x. Fácil né !? Mas há um problema: xserá dado como uma fração contínua (possivelmente infinita) e a saída deve ser uma fração contínua. A entrada é garantida como um número algébrico real, cujo grau é no máximo 2.

Entrada : a fração continuada de x. Isso é dividido em 3 partes: a parte inteira, o prefixo e a parte repetida. A parte inteira consiste em um único inteiro. O prefixo e a parte de repetição são (possivelmente vazios) matrizes de números inteiros positivos que descrevem o prefixo e a parte de repetição da fração continuada. Por exemplo, a entrada (3, [1], [2, 4])representa a fração continuada [3; 1, 2, 4, 2, 4, ...].

Se a parte repetida estiver vazia, isso indica um número racional. Por exemplo, (3, [1, 2], [])representa [3; 1, 2] = 11/3. Você deve aceitar as duas formas de um número racional (ou seja (3, [1, 1, 1], []), que [3; 1, 1, 1] = 11/3também deve ser uma entrada válida).

Saída : gera a fração contínua de duas vezes a entrada, no mesmo formato da entrada. Se a saída for racional, você poderá gerar uma das formas da fração continuada. Contanto que a resposta seja equivalente à resposta correta, tudo bem; nenhuma "compressão" é necessária; portanto, a parte infinita pode ser "desenrolada" um pouco (por exemplo, [1; 4, 2, 3, 2, 3...]pode ser escrita (1, [4], [2, 3])ou (1, [4, 2, 3], [2, 3])). Todas as respostas devem ser exatas.

Casos de teste : a coluna exata do formulário é fornecida por conveniência.

Input               Exact Form       Output
(0, [] [])          0                (0, [] []) or (-1, [1], [])
(-5, [1, 1], [])    -4.5             (-9, [], []) or (-10, [1], [])
(3, [1, 2], [])     11/3             (7, [3], []) or (7, [2, 1], [])
(1, [], [2])        sqrt(2)          (2, [], [1, 4])
(-1, [2], [2, 1])   -1/sqrt(3)       (-2, [1, 5], [2, 6])

E, finalmente, um caso de teste um pouco maior para assegurar a precisão: (0, [1], [6, 1, 3, 1, 42, 1, 3, 1, 6, 2]) --> (1, [], [1, 2, 1, 8, 1, 20, 1, 8, 1, 2, 1, 2]).

O menor código vence!

Dica : Você pode executar aritmética de maneira bastante direta nas frações contínuas, conforme descrito aqui . Dobrar uma fração continuada é apenas um caso especial desse algoritmo (embora a parte mais complicada seja encontrar quando a fração continuada se repete).

soktinpk
fonte
@Pavel Não, você deve poder especificar a entrada apenas com base no número inteiro, no prefixo e nas partes repetidas, e não como Sqrt[2].
soktinpk
Desculpe, isso foi um erro da minha parte. Aqui está o link com a fração contínua real como entrada: tio.run/##y00syUjNTSzJTE78n2b73zk/ryQzrzQ1xa0oMbkkMz8v2kjLrSg/…
Pavel
1
[3; 1, 1, 1]estaria (3, [1, 1, 1], [])no formato de entrada que estamos usando - portanto, a pergunta provavelmente deve mencioná-la nesse formato (no terceiro parágrafo), apenas para garantir clareza.
sundar - Restabelece Monica
2
Quais são as restrições de como a saída deve ser minimizada? Por exemplo, seria (-2, [1, 5, 2], [6, 2])uma saída aceitável para entrada (-1, [2], [2, 1])? Que tal (-2, [1, 5, 2, 6, 2, 6], [2, 6])?
22618 Peter Peter

Respostas:

7

Wolfram Language (Mathematica) , 44 bytes

ContinuedFraction[2FromContinuedFraction@#]&

Experimente online!

O Mathematica possui um builtin! Yay! O builtin do Mathematica é super longo. Aww.

As frações contínuas do Mathematica parecem {integer, ...prefix, {...repeating}}

-1 graças a JungHwan Min

Pavel
fonte
4
Você pode omitir o *porque o delimitador padrão do Mathematica, se não houver um, é Times.
JungHwan Min
3
Quando o seu idioma está integrado a tudo, desde pontuação no Scrabble até reconhecimento de cabras , alguns de seus nomes terão que ser "super longos" por necessidade. :)
sundar - Restabelece Monica
1
@ Sundar Não, o Mathematica possui apenas ~ 5.000 builtins. É possível fazer com que cada um tenha 2 bytes no máximo (consulte Mthmtca)
user202729
@ user202729 Mas o Mathematica não teria sido tão popular se fizesse isso: P
mbomb007
3

JavaScript (ES6), 267 bytes

(n,f,r)=>eval(`f=[0,...f];e=i=[0,2,1,0];o=j=[];k=[];m={};while([a,b,c,d]=e,c|d&&o)i*m[s=i+m+(e=c*d&&(q=a/c|0)==(b/d|0)?(o.push(q),[c,d,a-c*q,b-d*q]):1/(++i,[p,...f]=f+f?f:(i=r[0],r),p)?[b,a+b*p,d,c+d*p]:[b,b,d,d])]?k+(o=k)?o=0:(m={})[s]=1:m[s]=1;[2*n+j.shift(),j,k]`)

Aceita 3 argumentos (n = parte inteira, f = prefixo, r = parte repetida). Produz as três partes em uma matriz. Experimente online!

Explicação

É uma implementação bastante direta do algoritmo para calcular a aritmética de fração contínua vinculada no desafio aqui . Termos repetidos são tratados armazenando matrizes intermediárias em uma tabela de pesquisa, aguardando uma duplicata e produzindo os termos até a próxima aparição dessa duplicata. É deselegante e quase dobra os bytes necessários para lidar com frações contínuas, mas não consegui pensar em uma alternativa melhor.

O termo inicial é calculado separadamente para garantir que frações contínuas negativas retenham valores positivos para todos os termos, exceto o primeiro.

Para evitar falsos positivos quando aguardando um ciclo repetido, as lojas tabela de pesquisa de dados da seguinte forma: <index of input repeating part><delimiter><matrix values>.

Observe que a versão golfed usa evalpara salvar 1 byte.

(n, f, r) => {
    f = [0, ...f];                       // use a 0 to chop off the integer part
    e = i = [0,2,1,0];                   // e: matrix with starting values to handle doubling
                                         // 0 + 2x
                                         // ------
                                         // 1 + 0x
                                         // i: tracks index of repeating part; until the function loops through the
                                         // repeating part, i is equivalent to NaN
    o = j = [];                          // o: alias for group of terms currently being computed
                                         // j: output array of non-repeating terms
    k = [];                              // k: output array of repeating terms
    m = {};                              // lookup table
    while ([a,b,c,d] = e, c | d && o)    // destructure matrix
                                         // c | d stops loop if both a/c and b/d equal infinity
        i * m[s = i + m + (              // m also serves as the delimiter; JS will stringify it as "[object Object]"
                                         // if i equals a value that is coerced to NaN, this multiplication
                                         // will be falsy
            e = c * d && (q=a/c|0) == (b/d|0) // checks if either c or d is 0 to avoid converting an Infinity value to 0 using the bitwise or
                ? (o.push(q), [c, d, a - c*q, b - d*q]) // append the output term and compute the new matrix
                : 1/(++i, [p, ...f] = f+f ? f : (i=r[0], r), p) // 1/(... p) checks if p is a valid number
                                         // f+f is a short way to check length of f; if f is an empty
                                         // array, f+f = '' (which is falsy)
                                         // if f is empty, try to replace with r
                                         // if r is empty, the value of i will be set to undefined (e.g. NaN)
                    ? [b, a + b*p, d, c + d*p]
                    : [b,b,d,d]
            )
        ]                                // checks if matrix has been cached in lookup table
            ? k+(o=k)                    // if the repeating part of the output has a value...
                ? o=0                    // o serves as a flag to halt the loop
                : (m={})[s] = 1          // reset lookup table to only hold the first duplicate matrix
            : m[s] = 1;                  // otherwise flag a matrix as seen
    return [2*n + j.shift(), j, k]       // add the doubled integer part to the first term
}
redundância
fonte