1votos

Emulando a Dik T. Winter en F#

por josejuan hace 5 años

Ésta va para juan ;) Una traslación de la de javascript, corriendo bajo mono va notablemente más lenta que la de javascript. Corriendo en .Net de MS probablemente vaya mejor y seguro que depurando se puede mejorar.

Un número de N dígitos es narcisista si la suma de las potencias N-ésimas de sus dígitos es él mismo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
open System 
 
let calculate n = 
    let powers = Array.map (fun z -> bigint.Pow (z, n)) [|0I..9I|] 
    let L = bigint.Pow (10I, n - 1) 
    let isNarcissistic m = 
            let rec sumDown q s = 
                let d, r = bigint.DivRem (q, 10I) 
                if q < 1I 
                    then s 
                    else sumDown d (powers.[r |> int] + s) 
            m = sumDown m 0I 
    let rec combinations acc d ds = 
                if d = 10 
                    then 
                        if isNarcissistic acc 
                            then [acc] 
                            else [] 
                    else 
                        let p = powers.[d] 
                        let b = d + 1 
                        let reduce (ds', acc', rs') x = 
                                let rs'' = List.filter (fun x -> x >= L) <| List.concat [combinations acc' b ds'; rs'] 
                                (ds' - 1, acc' + p, rs'') 
                        let ds', acc', rs = List.fold reduce (ds, acc, []) [0..ds] 
                        rs 
    set <| combinations 0I 0 n 
 
 
[<EntryPoint>] 
let main args = 
    let n = Int32.Parse(args.[0]) 
    printf "==[ n := %i ]==========\n" n 
    let t0 = DateTime.UtcNow 
    Seq.iter (fun n -> printf "%s, " (n.ToString())) <| calculate n 
    printf "\n" 
    let t1 = DateTime.UtcNow 
    printf "%f mS\n" ((t1 - t0).TotalMilliseconds) 
 
 
 
 
// ejemplo en un phenom 2,7GHz =============================== 
 
$ for i in 1 2 3 4 5 6 7 8 9; do mono imap.exe $i; done 
==[ n := 1 ]========== 
1, 2, 3, 4, 5, 6, 7, 8, 9,  
65.983000 mS 
==[ n := 2 ]========== 
 
61.623000 mS 
==[ n := 3 ]========== 
153, 370, 371, 407,  
66.058000 mS 
==[ n := 4 ]========== 
1634, 8208, 9474,  
68.045000 mS 
==[ n := 5 ]========== 
54748, 92727, 93084,  
75.805000 mS 
==[ n := 6 ]========== 
548834,  
91.753000 mS 
==[ n := 7 ]========== 
1741725, 4210818, 9800817, 9926315,  
131.894000 mS 
==[ n := 8 ]========== 
24678050, 24678051, 88593477,  
222.502000 mS 
==[ n := 9 ]========== 
146511208, 472335975, 534494836, 912985153,  
409.642000 mS 
2 comentarios
0votos

Escrito por jmgomez hace 5 años

I like it! Pero habría que probarlo compilado, con ngen o mono y aot
0votos

Escrito por josejuan hace 5 años

¡Que barbaridad! el mismo código compilado con VS2013 sobre .Net 4.0 le toma (para N=9) 3,7 ¡segundos!, compilado release optimizado para 64bits. A ver `Any CPU`... bueno, ahora son "sólo" 1,8 segundos pero sigue siendo muchísimo ¡a mi (siempre humilde) Atom a 1,67 GHz le toma también 1,8!.

No, si va a ir mejor la versión mono...

Pero bueno, es justo decir que tampoco mi código será el mejor posible (para el mismo código).

Comenta la solución

Tienes que identificarte para poder publicar tu comentario.