qual è un modo efficace per trovare i decimali ripetuti


24

Sto cercando di trovare un algoritmo efficiente in Java per trovare la parte decimale ripetuta di due numeri interi ae bdove a/b.

per esempio. 5/7 = 0.714258 714258 ....

Attualmente conosco solo il metodo della divisione lunga.


2
Quindi hai a = 5 eb = 7, e puoi calcolare a / b in virgola mobile abbastanza facilmente, ma quello che vuoi sapere è che si ripete dopo 6 cifre decimali?
Sparr,

Risposte:


10

Credo che ci siano due approcci generali qui, puoi essenzialmente "forza bruta" cercare la stringa ripetuta più lunga o puoi risolverla come un problema di teoria dei numeri.

È passato molto tempo da quando ho riscontrato questo problema, ma un caso speciale (1 / n) è il problema n. 26 su Project Euler, quindi potresti essere in grado di trovare maggiori informazioni cercando soluzioni efficienti per quel nome specifico. Una ricerca ci porta al sito Web di Eli Bendersky, dove spiega la sua soluzione . Ecco alcune delle teorie dalla pagina delle espansioni decimali di Mathworld :

Ogni frazione non regolare m/nè periodica e ha un periodo lambda(n)indipendente da m, che è n-1 lungo al massimo di cifre. Se nè relativamente primo a 10, allora il periodo lambda(n)di m/nè un divisore di phi(n)e ha al massimo phi(n)cifre, dove phiè la funzione totient. Si scopre che lambda(n)è l' ordine moltiplicativo di 10 (mod n) (Glaisher 1878, Lehmer 1941). Il numero di cifre nella parte ripetuta dell'espansione decimale di un numero razionale può anche essere trovato direttamente dall'ordine moltiplicativo del suo denominatore.

La mia teoria dei numeri è un po 'arrugginita al momento, quindi il meglio che posso fare è indicarti quella direzione.


8

Lascia n < d, e stai cercando di capire la parte ripetitiva di n/d. Sia pil numero di cifre nella parte ripetuta: quindi n/d = R * 10^(-p) + R * 10^(-2p) + ... = R * ((10^-p)^1 + (10^-p)^2 + ...). La parte tra parentesi è una serie geometrica, uguale a 1/(10^p - 1).

Così n / d = R / (10^p - 1). Riorganizzare per ottenere R = n * (10^p - 1) / d. Per trovare R, ppassa da 1 a infinito e fermati non appena si ddivide uniformemente n * (10^p - 1).

Ecco un'implementazione in Python:

def f(n, d):
    x = n * 9
    z = x
    k = 1
    while z % d:
        z = z * 10 + x
        k += 1
    return k, z / d

( ktiene traccia della lunghezza della sequenza ripetuta, in modo da poter distinguere tra 1/9 e 1/99, ad esempio)

Si noti che questa implementazione (ironicamente) viene ripetuta per sempre se l'espansione decimale è finita, ma termina se è infinita! Puoi verificare questo caso, perché n/davrà una rappresentazione decimale finita solo se dsono presenti anche tutti i fattori primi che non sono 2 o 5 n.


1
Questa risposta sembra corretta. Il metodo si basa sulla seguente "regola": 0.123123... = 123/999 0.714258714258... = 714258/999999 (=5/7)ecc.
VIENI DAL

4
Fallisce casi come 1/6 o 5/12: \
razpeitia,

1
@razpeitia Ho fatto qualcosa di simile, ma lavorando in tutti i casi (inclusa la divisione di numeri interi). Check out: codepad.org/hKboFPd2
Tigran Saluev

Ho realizzato un'implementazione javascript simile a quella di @TigranSaluev su github.com/Macil/cycle-division
Macil

2

Lunga divisione? : /

Trasforma il risultato in una stringa e quindi applica questo algoritmo . Usa BigDecimal se la tua stringa non è abbastanza lunga con tipi normali.


4
"Trasformalo in una stringa" potrebbe richiedere calcoli di precisione arbitrari e una stringa molto lunga per calcolare due copie della parte ripetitiva della stringa (e come fai a sapere quando interrompere il calcolo? .12121231212121231212123 ... sarebbe un problema)
Sparr,

@Sparr La lunghezza della ripetizione è sempre inferiore al denominatore.

@MichaelT Non ne ero a conoscenza. Se vero, la precisione non è precisamente "arbitraria", ma può essere arbitrariamente alta a seconda del denominatore.
Sparr,


Non penso che l'algoritmo a cui ti colleghi funzionerebbe senza modifiche. Include ripetizioni che si sovrappongono e cerca in tutta la stringa (non solo per corrispondenze consecutive). Ad esempio, la sottostringa ripetuta più lunga in "banana" è "ana".
Web_Designer il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.