Hallo Tomás,

Am 29.07.2017 um 23:45 schrieb tomas@tuxteam.de:
On Sat, Jul 29, 2017 at 09:49:21AM +0200, Urs Liska wrote:

[...]

> Im Moment sind es zwei unterschiedlich geartete Fragen:
> 1)
> Bei der Aufgabe, Substrings zu hashen, komme ich einfach nicht über
> einen Testfall hinweg, bei dem der Algorithmus zu lange braucht. Hier
> muss es entweder eine Optimierung geben, die ich nicht gefunden habe
> (z.B. dass unnötig String-Kopien erzeugt werden oder es eine unnötige
> Schleife gibt) oder einen Sonderfall, der meinen Algorithmus in die Ecke
> (bzw. in einen Kreis) treibt):
> https://git.openlilylib.org/uliska/algorithms-and-datastructures/issues/3

Ich vermisse einige Moduli (%) in precompute_hashes. Z.B. muss

  y = self._rn_dx ** p_len

eine ziemlich grosse Zahl sein,

stimmt.
Ich glaube, hier sieht man, wie ich schwimme. Ich war eigentlich von Varianten mit deutlich mehr %-Operationen ausgegangen und hatte dann gedacht, dass diese vielleicht unnötig Zeit kosten. Wahrscheinlich habe ich da dann in die falsche Richtung "verbessert" - eben, weil ich die Sache nicht völlig durchschaue.

Vielen Dank für deine Überlegungen und Ausführungen, die mich hoffentlich in eine bessere Richtung lenken - allerdings nicht mehr heute Abend, da ist mir das doch zu kompliziert.
Ein Mentor hat im Forum übrigens geschrieben, dass sich alle, die Probleme mit der Laufzeit haben, sich mal "Schnelleres Modulo" (https://en.wikipedia.org/wiki/Fermat's_little_theorem) anschauen sollten.

Ich melde mich, falls es weitere Erkenntnisse gibt.
HG
Urs

bei einem mässig (~100) langem Pattern
(im Assignment faseln die von bis 10^5), selbst wenn _rn_dx so klein
ist wie bei Dir (2) (was ich ein wenig bedrohlich finde, ich weiss
nicht, wie sich das auf das Kollissionsverhalten des Hashes auswirkt).

Python kommt mit grossen Zahlen zwar klar, aber sie sind teuer (auf
meiner Gurke kippt die Zeit bei mir von 0.8 auf über 4 (Sekunden):

  >>> for i in range(60, 100, 1):
  ...   def f():
  ...     return 2**i
  ...   timeit.timeit(f)
  ...   print(i)
  ...
  0.8464090824127197
  60
  0.8901400566101074
  61
  0.8901631832122803
  62
  4.829195976257324
  63
  3.9598159790039062
  64
  4.131256103515625
  65

Da sieht man auch, wieviele Bits sich Python bei einem 64 bit-System als
tag bits reserviert, nämlich 3. Ab 2^62 muss Python die Maschinenintegers
verlassen und "lange Integers" nehmen. Schick aber langsam.

Vielleicht ist eine Exponentiation in der Schleife, mit Modulo dazwischen
richtig. Ganz luxuriös wäre "modular exponentiation" [1], aber ich glaube,
die Fussgängermethode wird ausreichen (ein erster Test bei mir liefert:
eher nicht -- uh, oh):

  >>> def mexp(x, y):
  ...   e = x
  ...   for i in range(1, y, 1):
  ...     e = (e*x) % 1000000009
  ...   return e
  ...
  >>> mexp(2, 6)
  64
  >>> def f():
  ...   return mexp(17, 100)
  ...
  >>> timeit.timeit(f)
  27.922509908676147

Entweder übersehe ich etwas, oder es braucht tatsächlich [1].

Ganz fies wird, wenn Du das "unmodulierte" y weiter unten für jedes Character
in der Schleife nimmst: dann muss Python jedes einfache Integer in ein
"fettes" verwandeln...

So viel kriege ich noch heute Abend zusammen.

Fazit: teste Dein Programm mit richtig langen Strings (pattern length
100 oder so).

lg
-- t
> _______________________________________________ > Freiburger Linux User Group > Mail an die Liste: flug@lug-freiburg.de > Mailingliste verwalten (u.a. abbestellen): https://lug-freiburg.de/mailman/listinfo/flug

--
ul@openlilylib.org
https://openlilylib.org
http://lilypondblog.org