Forum: Offtopic [Knobeln] Heute: Zahlentheorie


von D. I. (Gast)


Lesenswert?

In meinen alten Programmiertrainingsunterlagen habe ich folgendes 
Schmankerl entdeckt und möchte euch dazu animieren es zu lösen:

Folgender Satz aus der Zahlentheorie ist bewiesen:

Oder natürlichsprachlich: Zu jeder natürlichen Zahl n exisitiert eine 
natürliche Zahl k so dass die letzten n Ziffern von 2^k nur aus 1en und 
2en bestehen.

Eure Aufgabe besteht nun zu den folgenden gegebenen n's die passenden 
k's zu finden. Um der Sache ein wenig Würze zu verleihen soll immer das 
kleinstmöglichste k gefunden werden.

Da ich ein genügsamer Mensch bin reicht es mir wenn ihr die k's findet 
für

Und da ich noch dazu ein sehr freundlicher Mensch bin, gibts die ersten 
beiden k's gratis:

Der erste mit der kompletten richtigen Lösung, darf auf seinen E-Pen*s 
1cm bis 2cm addieren :)

Edit: Es ist sowohl "händisch" als auch "programmiertechnisch" erlaubt, 
die Lösung zu finden. Aber ich stelle mir ersteres sehr mühsam vor ;)

von Uhu U. (uhu)


Lesenswert?

Damit kannst du dir deine Verlängerung berechnen:
1
def t(n)
2
  k = 1
3
  i = 1
4
  p = 10 ** n
5
  while true
6
    i = i * 2
7
    s = (i % p).to_s
8
    return k if s.length == n && s =~ /^[12]+$/
9
    k = k + 1
10
  end
11
end

Dauert ein wenig, aber das Resultatmuster sieht interessant aus.

von Nils S. (tcatm)


Lesenswert?

1
@@ -1,11 +1,14 @@
2
 def t(n)
3
   k = 1
4
-  i = 1
5
+  i = 2
6
   p = 10 ** n
7
   while true
8
-    i = i * 2
9
+    i = i * 16
10
     s = (i % p).to_s
11
     return k if s.length == n && s =~ /^[12]+$/
12
-    k = k + 1
13
+    k = k + 4
14
   end
15
 end
Dauert schonmal ein klein wenig weniger... (12s vs. 49s für n = 9)

von Uhu U. (uhu)


Lesenswert?

Für 11 rötelt hier ein Kern schon 30 Minuten - das Problem ist etwas 
unübersichtlich...

von Nils S. (tcatm)


Lesenswert?

Huch, da hat sich ein Fehler bei mir eingeschlichen. k muss noch mit 5 
initialisiert werden und für n = 1 kann die Funktion dann natürlich kein 
Ergebnis mehr finden.

von Uhu U. (uhu)


Lesenswert?

Hast du für 11 schon was rausgekriegt? Meine erste Version hat jetzt mit 
fast einer Stunde CPU immer noch nichts gefunden.

Mir scheint, daß man da noch etwas zahlentheoretischen Hirnschmalz 
investieren muß...

von Nils S. (tcatm)


Lesenswert?

Jop, 11 hab ich. 12 ist schwerer, ich optimiere erstmal den Algo für 1 
bis 11 auf ein paar Sekunden. Tipp: Teilbarkeitsregeln und 
Potenzgesetze. Damit kannst du die zu überprüfenden k enorm Einschränken 
bzw. (Vermutung) wenn du es vollständig ausformulierst alle k direkt 
berechnen.

von D. I. (Gast)


Lesenswert?

Schön auf Resonanz zu stoßen :)
Netter erster Versuch ;) aber dass ihr so einfach davonkommt, das konnte 
ich natürlich nicht zulassen :)

von Andreas F. (aferber)


Angehängte Dateien:

Lesenswert?

Ihr solltet euch mal nach Algorithmen für diskrete Logarithmen umsehen, 
damit hängt das Problem letztlich zusammen soweit ich sehen kann. Eine 
allgemeine schnelle Lösung dafür gibt es nicht, nicht umsonst werden die 
für einige asymmetrische Cryptoalgorithmen eingesetzt. Ich will aber 
nicht ausschliessen dass es in diesem Spezialfall vielleicht einen Trick 
gibt.

Ausserdem ist bei dem vorliegenden naiven Ansatz modulare Exponentiation 
in der Schleife schneller als die Multiplikation plus Modulo, da es 
dafür optimierte Algorithmen gibt.

Mein schnell hingeschmiertes Perl-Script (siehe Attachment, mit 
Rückgriff auf die GMP-Lib und ihre Funktion für modulare Exponentiation) 
berechnet mit einem Kern bis n=10 in 3,8 Sekunden und bis n=11 in ca. 
100 Sekunden, weiter hab' ich's nicht laufen lassen (bzw. irgendwo bei 
k=2*10^8 abgebrochen).

Für weiteres Nachdenken ist mir zu warm ;-)

Andreas

von Nils S. (tcatm)


Lesenswert?

Langsam wirds. Für n = 1 bis 10 braucht meiner nun nur noch 102ms. Ab n 
= 11 meckert Ruby, dass die Datentypen zu klein werden. Muss mir mal 
eine geeigneteres Format für die Potenzen ausdenken.

Prinzipiell geh ich das Problem nun rückwärts an: Ich erzeuge immer 
längere Ketten aus 1en und 2en, die auf 2^n passen.

von Nils S. (tcatm)


Lesenswert?

Ich glaub ich habs...
1
$ time ruby knobeln.rb 
2
1 => 1
3
2 => 9
4
3 => 89
5
4 => 89
6
5 => 589
7
6 => 3089
8
7 => 3089
9
8 => 3089
10
9 => 315589
11
10 => 315589
12
11 => 8128089
13
12 => 164378089
14
13 => 945628089
15
14 => 1922190589
16
15 => 11687815589
17
16 => 109344065589
18
17 => 231414378089
19
18 => 1452117503089
20
19 => 4503875315589
21
20 => 65539031565589
22
21 => 141832976878089
23
22 => 1667711883128089
24
23 => 3575060515940589
25
24 => 32185290008128089
26
25 => 222920153289378089
27
26 => 222920153289378089
28
27 => 222920153289378089
29
28 => 24064778063445628089
30
29 => 83669422838836253089
31
30 => 679715870592742503089
32
31 => 3659948109362273753089
33
32 => 7385238407824187815589
34
33 => 7385238407824187815589
35
34 => 7385238407824187815589
36
35 => 1870030387638781219065589
37
36 => 6526643260716173797190589
38
37 => 6526643260716173797190589
39
38 => 181149626001118395476878089
40
39 => 763226235135792467742503089
41
40 => 763226235135792467742503089
42
41 => 763226235135792467742503089
43
42 => 73522802376970051500945628089
44
43 => 73522802376970051500945628089
45
44 => 3711501609468683003161101878089
46
45 => 21901395644927247761461883128089
47
46 => 112850865822220071552965789378089
48
47 => 340224541265452131031725555003089
49
48 => 1477092918481612428425524383128089
50
49 => 4319263861522013171910021453440589
51
50 => 18530118576724016889332506805003089
52
53
real  0m0.033s
54
user  0m0.030s
55
sys  0m0.010s

von D. I. (Gast)


Lesenswert?

Sieht gut aus :) Es steht dir frei ob du auch den Algorithmus dazu 
erzählen möchtest oder ob du die anderen noch tüfteln lassen willst ;)

von D. I. (Gast)


Angehängte Dateien:

Lesenswert?

Ein trivialer Algorithmus, der allerdings nicht das minimale k findet 
(das ist die Crux), funktioniert wie folgt:

- Bestimme die ersten beiden k's so dass gilt k1 < k2 => n1 < n2
- Berechne die Differenz k2-k1


- Addiere diese Differenz solange auf k2, bis man ein k2_neu erhält bei 
dem gilt: k2 < k2_neu => n2 < n2_neu
- setze k1 = k2 und k2 = k2_neu
- Berechne die Differenz k2-k1;

So kann man in ein paar Sekunden bis n = 100 rechnen (siehe Datei), aber 
leider nicht minimal.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Hab's auch raus, aber Nils war schneller :)
1
$ time python nk.py 
2
1 1
3
2 9
4
3 89
5
4 89
6
5 589
7
6 3089
8
7 3089
9
8 3089
10
9 315589
11
10 315589
12
11 8128089
13
12 164378089
14
13 945628089
15
14 1922190589
16
15 11687815589
17
16 109344065589
18
17 231414378089
19
18 1452117503089
20
19 4503875315589
21
20 65539031565589
22
21 141832976878089
23
22 1667711883128089
24
23 3575060515940589
25
24 32185290008128089
26
25 222920153289378089
27
26 222920153289378089
28
27 222920153289378089
29
28 24064778063445628089
30
29 83669422838836253089
31
30 679715870592742503089
32
31 3659948109362273753089
33
32 7385238407824187815589
34
33 7385238407824187815589
35
34 7385238407824187815589
36
35 1870030387638781219065589
37
36 6526643260716173797190589
38
37 6526643260716173797190589
39
38 181149626001118395476878089
40
39 763226235135792467742503089
41
40 763226235135792467742503089
42
41 763226235135792467742503089
43
42 73522802376970051500945628089
44
43 73522802376970051500945628089
45
44 3711501609468683003161101878089
46
45 21901395644927247761461883128089
47
46 112850865822220071552965789378089
48
47 340224541265452131031725555003089
49
48 1477092918481612428425524383128089
50
49 4319263861522013171910021453440589
51
50 18530118576724016889332506805003089
52
53
real    0m0.028s
54
user    0m0.023s
55
sys     0m0.003s

Ich schätze, ich habe einen ähnlichen Algorithmus wie Nils, deswegen
auch die ähnliche Laufzeit.

Da den Code auf Anhieb sowieso keiner verstehen wird, poste ich ihn
hier mal:
1
nmax = 50
2
3
def only12(k, n):
4
  sk = str(k)[-n:]
5
  return len(sk) >= n and sk.count('1') + sk.count('2') == len(sk)
6
7
p10nmax = 10 ** nmax
8
k = 1
9
p2k = 2 ** k
10
f = 4
11
p2f = 2 ** f
12
print 1, 1
13
for n in range(2, nmax+1):
14
  while not only12(p2k, n):
15
    k += f
16
    p2k = p2k * p2f % p10nmax
17
  f *= 5
18
  p2f = p2f ** 5 % p10nmax
19
  print n, k

Wer also noch weiter tüfteln will, einfach nicht so genau hinschauen ;-)

von D. I. (Gast)


Lesenswert?

Yo Yalu, so ist es, quasi Musterlösung :) aber Nils war in der Tat 
schneller, d.h. 1cm für dich, 2cm für Nils :D

In den nächsten Tagen folgt dann wieder eins

von Yalu X. (yalu) (Moderator)


Lesenswert?

Für nmax=1000 braucht's gute 5s.
1
k(1000) =
2
615518781133550927510466866560333743905276469414384071264775976996005261
3
582333424319169262744569107203933909361398767112744041716987032548389396
4
865721149211989700277761744700088281526981978660685104481509534097152083
5
798849174934153949598921020219299137483196605381824600377210207048355959
6
118105502326334547495384673753323864726827644650703466356156319492521379
7
682428275201262134907960967634887658195264018797348236155773958687977059
8
474419550906257366056229915615067527218040720408353328787880060032847746
9
927391316869927283585312014157952623949696812057481086276896651244409107
10
902992111507870787820359137244857060839675634572294938878098506151681269
11
336043213294287160464665102314138635395739226878089

Der nächste Schritt wäre jetzt natürlich, einen geschlossenen Ausdruck
für k(n) zu finden. Aber ich glaube, das spare ich mir, zumindest für
heute ;-)

PS: Ich habe gestern ebenfalls ein Rätsel gepostet, was aber evtl. im
Analogtechnikforum etwas verloren gegangen ist:

  Beitrag "Widerstandsknobelei"

Vielleicht hat ja der eine oder andere Lust, dort mal vorbeizuschauen.
Die einfachere erste Teilaufgabe ist bereits gelöst, die zweite sucht
noch nach einem klugen Kopf :)

von D. I. (Gast)


Lesenswert?

Was ist denn das für ein Programm? Händisch macht das nicht gerade Fun 
;)

von Yalu X. (yalu) (Moderator)


Lesenswert?

D. I. schrieb:
> Was ist denn das für ein Programm?

Welches meinst du?

von D. I. (Gast)


Lesenswert?

Yalu X. schrieb:
> D. I. schrieb:
>> Was ist denn das für ein Programm?
>
> Welches meinst du?

Das mit dem man die Widerstände verschalten kann und automatisch die 
Ströme berechnen

von Yalu X. (yalu) (Moderator)


Lesenswert?

D. I. schrieb:
>> Welches meinst du?
>
> Das mit dem man die Widerstände verschalten kann und automatisch die
> Ströme berechnen

Achso, das ist LTSpice, eine Spice-Implementation von Linear Technology:

  http://www.linear.com/designtools/software/#Spice

Das hilft aber bei der zweiten Teilaufgabe, wo auch der Gesamtwiderstand
vorgegeben ist nicht, so arg viel, weil man den Gesamtwiderstand mit
Spice zwar ermitteln kann, man aber sehr viele Schaltungen eingeben und
simulieren müsste, um irgendwann den richtigen Wert zu treffen. Da kommt
man wahrscheinlich schneller zum Ziel, wenn man sich den Algorithmus zur
Berechnung der Ströme selbst schreibt, wobei man sich dabei noch die
Tatsache zunutze machen kann, dass alle Widerstände gleich groß sind.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.