2010-01-21 23 views
9

que estoy tratando de contar el número de dígitos de un número en Clojure de la siguiente manera: recibo una StackOverflowError incluso para números de 2 dígitosStackOverflow mientras dígitos conteo

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

Pero si reemplazo/con marcada brecha continuación, funciona durante al menos 93. Pero ninguna de las técnicas trabaja para:

93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 

en primer lugar, me gustaría saber cómo llevar a cabo la división del estilo C en Clojure. Cuando lo hago (/ x y) obtengo un Ratio y no un Integer. ¿Cuál es la manera de hacerlo?

En segundo lugar, hay una forma de API para convertir este número en un vector de dígitos y conteo de llamadas en él.

Gracias,
Ajay G

+2

No sé nada de Clojure, pero ¿no debería haber alguna forma de convertir el número en una cadena y luego obtener la longitud de la cuerda? Casi todos los otros idiomas en los que puedo pensar tiene tal función. – ewall

+0

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

Respuesta

3

Según this page, puede realizar una división entera en Clojure usando quot:

(quot n 10) 
3

Clojure intenta "hacer lo correcto", con operaciones numéricas y Nunca pierde precisión. entonces cuando su dispositivo dice 17/10 el resultado es la fracción 17/10 (diecisiete décimas) no 1. Por defecto, no se perderá información en ninguna de las operaciones numéricas. En casos como este se puede lanzar de forma explícita distancia la precisión adicional con (quote x 10) o puede emitir el resultado a un int (int (/ 17 10))

a la segunda pregunta aquí hay un pequeño truco:

(count (str 257)) 

Una buena manera de evitar soplar la pila con recursión en Clojure es usar otras funciones de orden superior en lugar de recurrencia.

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

No hay optimización de la llamada de cola en Clojure. Tienes que usar el formulario especial recur.

E.g.:

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

Sin embargo, en respuesta a la segunda pregunta: sí, y esta es la forma:

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

En el código original, la llamada no está ni siquiera en posición de la cola Entonces, este código también fallaría en cualquier otro idioma. – kotarak

8

Es por esto que usted está teniendo 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) 

Este es el corregir:

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

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

Esta es la expresión y sted buscando:

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

Esta es hacer trampa:

user> (count (str 10923)) 
5 

Ésta es la función que estaba tratando de escribir (pero cuidado, será desbordamiento de pila para un gran número):

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

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

Sin embargo, es hasta el desafío:

user> (num-digits 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000) 

158 

Esta versión de esa función no soplará 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 

Todas las versiones son interesantes a su manera. ¡Buena pregunta!