Podwojony ułamek liczby

21

Twoim zadaniem jest dane xwyjście 2*x. Łatwe, prawda !? Ale jest pewien haczyk: xzostanie podany jako (być może nieskończony) ciągły ułamek , a wyjście musi być ułamkiem ciągłym. Dane wejściowe są gwarantowaną rzeczywistą liczbą algebraiczną, której stopień wynosi co najwyżej 2.

Wkład : ciągły ułamek x. Jest on podzielony na 3 części: część całkowitą, przedrostek i część powtarzającą się. Część całkowita składa się z jednej liczby całkowitej. Przedrostek i powtarzająca się część są (być może pustymi) tablicami liczb całkowitych dodatnich, które opisują przedrostek i powtarzającą się część ciągłej części. Na przykład dane wejściowe (3, [1], [2, 4])reprezentują ciągły ułamek [3; 1, 2, 4, 2, 4, ...].

Jeśli powtarzająca się część jest pusta, oznacza to liczbę wymierną. Na przykład (3, [1, 2], [])reprezentuje [3; 1, 2] = 11/3. Musisz zaakceptować obie formy liczby wymiernej (tzn. (3, [1, 1, 1], [])Która [3; 1, 1, 1] = 11/3powinna być również poprawnym wejściem).

Wyjście : wyjście ciągłego ułamka dwukrotności wejścia, w tym samym formacie co wejście. Jeśli dane wyjściowe są racjonalne, możesz wypisać dowolną formę ciągłego ułamka. Tak długo, jak odpowiedź jest odpowiednikiem poprawnej, jest w porządku; „kompresja” nie jest konieczna, więc nieskończona część może być „rozwinięta” nieco (np. [1; 4, 2, 3, 2, 3...]może zostać napisana (1, [4], [2, 3])lub (1, [4, 2, 3], [2, 3])). Wszystkie odpowiedzi muszą być dokładne.

Przypadki testowe : Dokładna kolumna formularza jest podana dla wygody.

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

I wreszcie nieco większy przypadek testowy, aby zapewnić precyzję: (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]).

Najkrótszy kod wygrywa!

Wskazówka : Możesz wykonywać arytmetykę w dość prosty sposób na ciągłych ułamkach, jak opisano tutaj . Podwojenie ciągłego ułamka jest tylko specjalnym przypadkiem tego algorytmu (choć trudną częścią może być znalezienie, kiedy ciągły ułamek powtarza się).

soktinpk
źródło
@Pavel Nie, musisz być w stanie określić dane wejściowe wyłącznie na podstawie liczby całkowitej, prefiksu i powtarzających się części, a nie jako Sqrt[2].
soktinpk
Przepraszam, to był błąd z mojej strony. Oto link z faktyczną kontynuacją frakcji jako danych wejściowych: tio.run
Pavel
1
[3; 1, 1, 1]byłby (3, [1, 1, 1], [])w formacie wejściowym, którego używamy - więc pytanie powinno prawdopodobnie zawierać wzmiankę o tym formacie (w trzecim akapicie), aby zapewnić przejrzystość.
Sundar - Przywróć Monikę
2
Jakie są ograniczenia dotyczące zminimalizowania wyników? Np. Czy (-2, [1, 5, 2], [6, 2])dane wyjściowe byłyby do przyjęcia (-1, [2], [2, 1])? Jak o (-2, [1, 5, 2, 6, 2, 6], [2, 6])?
Peter Taylor

Odpowiedzi:

7

Wolfram Language (Mathematica) , 44 bajty

ContinuedFraction[2FromContinuedFraction@#]&

Wypróbuj online!

Mathematica ma wbudowane! Tak! Wbudowane oprogramowanie Mathematica jest bardzo długie. Aww.

Ciągłe ułamki Mathematiki wyglądają {integer, ...prefix, {...repeating}}

-1 dzięki JungHwan Min

Pavel
źródło
4
Możesz pominąć, *ponieważ domyślnym ogranicznikiem Mathematiki, jeśli nie jest, jest Times.
JungHwan Min
3
Gdy język ma poleceń wbudowanych do wszystkiego, od Scrabble punktacji do uznania Goat , niektóre z ich nazwami będą musiały być „super długi” z konieczności. :)
zegar słoneczny - Przywróć Monikę
1
@ Sundar Nie, Mathematica ma tylko ~ 5000 wbudowanych wersji. Możliwe jest, aby każdy wbudowany maksymalnie 2 bajty (patrz Mthmtca)
202729
@ user202729 Ale Mathematica nie byłaby tak popularna, gdyby to zrobiła: P
mbomb007
3

JavaScript (ES6), 267 bajtów

(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]`)

Akceptuje 3 argumenty (n = część całkowita, f = przedrostek, r = część powtarzająca się). Wysyła trzy części z tablicy. Wypróbuj online!

Wyjaśnienie

Jest to dość bezpośrednia implementacja algorytmu obliczania ciągłej arytmetyki ułamkowej powiązanej z wyzwaniem tutaj . Powtarzające się terminy są obsługiwane przez przechowywanie pośrednich macierzy w tabeli odnośników, czekanie na duplikat i generowanie terminów do następnego pojawienia się tego duplikatu. Jest nieelegancki i prawie podwaja bajty potrzebne do obsługi ciągłych frakcji, ale nie mogłem wymyślić lepszej alternatywy.

Termin wiodący jest obliczany osobno, aby zapewnić, że ujemne ciągłe frakcje zachowują wartości dodatnie dla wszystkich terminów z wyjątkiem pierwszego.

Aby uniknąć fałszywych alarmów, gdy w oczekiwaniu na powtarzającym się cyklu, przechowuje tablicę przeglądową danych, jak następuje: <index of input repeating part><delimiter><matrix values>.

Zauważ, że wersja golfowa używa evaldo zapisania 1 bajtu.

(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
}
nadmiar
źródło