2010-01-21 13 views
9

Sto cercando di contare il numero di cifre in un numero in Clojure come segue: ho uno StackOverflowError anche per 2 numeri di cifraStackOverflow mentre le cifre di conteggio

(defn num-digits [n] 
    (if (= 0 n) 
    0 
    (inc (num-digits (/ n 10))))) 
(println (num-digits 93)) 

Ma se sostituisco/con incontrollato-divide poi funziona per almeno 93. Ma né delle tecniche lavora per:

93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 

in primo luogo, vorrei sapere come eseguire la divisione in stile C in Clojure. Ogni volta che faccio (/ x y) ottengo un rapporto e non un intero. Qual è il modo di farlo?

In secondo luogo, c'è un modo API per convertire questo numero in un vettore di cifre e contare su di esso.

Grazie,
Ajay G

+2

Non so nulla di Clojure, ma non dovrebbe esserci un modo per convertire il numero in una stringa e quindi ottenere solo la lunghezza della stringa? Quasi ogni altra lingua che riesco a pensare ha una tale funzione. – ewall

+0

log10: https://stackoverflow.com/questions/27229987/can-i-know-how-many-digits-a-number-is-without-count-it – coredump

risposta

3

Secondo this page, è possibile eseguire divisione intera in Clojure utilizzando quot:

(quot n 10) 
3

Clojure tenta di "fare la cosa giusta", con operazioni numeriche e mai perdere la precisione. così quando il dispositivo dice 17/10 il risultato è la frazione 17/10 (diciassette decimi) non 1. Per impostazione predefinita nessuna informazione verrà persa in nessuna delle operazioni numeriche. In casi come questo è possibile in modo esplicito buttare via la precisione in più con (quote x 10) o si può lanciare il risultato ad un int (int (/ 17 10))

per la seconda domanda, ecco un piccolo hack:

(count (str 257)) 

Un buon modo per evitare di far saltare la pila con la ricorsione in Clojure significa utilizzare altre funzioni di ordine superiore invece di ricorsione.

(count (take-while pos? (iterate #(quot % 10) 257)))) 
4

Non c'è ottimizzazione di chiamata di coda in Clojure. Devi usare il modulo speciale recur.

E.g.:

(defn num-digits [n] 
    (loop [n n 
     cnt 0] 
    (if (= 0 n) 
     cnt 
     (recur (quot n 10) (inc cnt))))) 

Ma in risposta alla tua seconda domanda: sì, e questo è il modo:

(defn num-digits [n] (count (str n))) 
+0

Nel codice originale la chiamata non è nemmeno in posizione di coda. Quindi questo codice fallirebbe in ogni altra lingua altrettanto bene. – kotarak

8

Questo è il motivo per cui hai un problema:

user> (take 10 (iterate #(/ % 10) 10923)) 

(10923 10923/10 10923/100 10923/1000 10923/10000 10923/100000 10923/1000000 10923/10000000 10923/100000000 10923/1000000000) 

Questa è la fix:

user> (take 10 (iterate #(quot % 10) 10923)) 

(10923 1092 109 10 1 0 0 0 0 0) 

Questa è l'espressione y ou're alla ricerca di:

user> (count (take-while #(not (zero? %)) (iterate #(quot % 10) 10923))) 
5 

Questo è barare:

user> (count (str 10923)) 
5 

Questa è la funzione che si stava tentando di scrivere (ma attenzione, sarà impilare troppo pieno per un gran numero):

user> (defn num-digits [n] 
     (if (= 0 n) 
      0 
      (inc (num-digits (quot n 10))))) 

#'user/num-digits 
user> (num-digits 10923) 
5 

Tuttavia, è all'altezza della sfida:

user> (num-digits 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000) 

158 

Questa versione di tale funzione non farà saltare pila:

user> (defn num-digits-tail-recursion 
     ([n count] 
      (if (= 0 n) 
      count 
      (recur (quot n 10) (inc count)))) 
     ([n] (num-digits-tail-recursion n 0))) 
#'user/num-digits-tail-recursion 
user> (num-digits-tail-recursion 10923) 
5 

Tutte le versioni sono interessanti a modo loro. Buona domanda!

Problemi correlati