Entwickler-Ecke
Algorithmen, Optimierung und Assembler - Alternierende Quersumme
Marco D. - Sa 18.11.06 14:37
Titel: Alternierende Quersumme
Ich muss die alternierende Quersumme einer Zahl berechnen. Das macht die Routine Foo:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| function Foo(int: integer): integer; var i: integer; s: string; begin result := 0; for i := 1 to 5 do begin if (i mod 2 = 0) then begin s := inttostr(int); result := result + strtoint(s[5 - i]) end else begin s := inttostr(int); result := result - strtoint(s[5 - i]) end; end; end;
procedure TForm1.Button1Click(Sender: TObject); begin showmessage(inttostr(Foo(36036))); end; |
Aber es kommt immer am Ende des letzten Durchlaufes der for-Schleife eine Meldung:
Zitat: |
---------------------------
Benachrichtigung über Debugger-Exception
---------------------------
Im Projekt Project1.exe ist eine Exception der Klasse EConvertError aufgetreten. Meldung: ''
---------------------------
OK Hilfe
---------------------------
|
Das kann ich mir nicht erklären. :gruebel:
Mehr über das Verfahren gibts
hier [
http://de.wikipedia.org/wiki/Quersumme#Alternierende_Quersumme].
Marc. - Sa 18.11.06 14:49
Ein String beginnt immer bei 1.
So nun läuft dein i von 1 bis 5 - letzlich steht da also:
Delphi-Quelltext
1:
| result := result - strtoint(s[5 - 5]) |
5 - 5 ist null, daher nicht definiert ;)
grüße marc
Marco D. - Sa 18.11.06 14:52
Marc. hat folgendes geschrieben: |
Ein String beginnt immer bei 1.
So nun läuft dein i von 1 bis 5 - letzlich steht da also:
Delphi-Quelltext 1:
| result := result - strtoint(s[5 - 5]) |
5 - 5 ist null, daher nicht definiert ;)
grüße marc |
:autsch: Klar! Also muss die Schleife von 0-4 gehen?
Marco D. - Sa 18.11.06 14:52
Perfekt es klappt!
Marc. - Sa 18.11.06 14:54
Oder du ziehst nicht i von 5 ab, sondern von 6:
Delphi-Quelltext
1:
| result := result - strtoint(s[6 - i]) |
6 - 1 = 5
6 - 2 = 4
...
6 - 5 = 1
//edit: kommt zwars selbe raus, allerdings negativ ;)
Marco D. - Sa 18.11.06 14:58
Marc. hat folgendes geschrieben: |
Oder du ziehst nicht i von 5 ab, sondern von 6:
Delphi-Quelltext 1:
| result := result - strtoint(s[6 - i]) |
6 - 1 = 5
6 - 2 = 4
...
6 - 5 = 1
//edit: kommt zwars selbe raus, allerdings negativ ;) |
Ich muss das Prinzip nochmal neu überdenken, vielleicht kann man die Schleife noch optimieren. ;)
Kann man das ganze auch lösen, ohne Stringroutinen zu benutzen? Wie könnte man dann z.B. auf die 5 Ziffer zugreifen?
Moderiert von
AXMD: Beiträge zusammengefasst
Delete - Sa 18.11.06 17:10
yep, mit einen datentyp der die werte auf einen festen platz stellt, z.b. BCD (binary coded decimal). <HTH>
Marco D. - Sa 18.11.06 17:30
Grenzgaenger hat folgendes geschrieben: |
yep, mit einen datentyp der die werte auf einen festen platz stellt, z.b. BCD (binary coded decimal). <HTH> |
Noch nie von gehört. Kannst du mir das mal bitte erklären? :p
Delete - Sa 18.11.06 17:45
hier sind je 2 Ziffern in einem byte codiert im high und low nibble. der processor kennt das format und kann damit normal rechnen. das bcd format wird normal für kaufmännische anwendungen eingesetzt, da hier der prozessor nicht keine rundungsdifferenzen auftreten, im gegendsatz zu fliesskommazahlen. kannst ja mal kurz im netz (z. B.
http://de.wikipedia.org/wiki/BCD-Code) lurken unter BCD oder in der delphi hilfe.
alternativ hier einen etwas optimierteren code deiner routine
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| FUNCTION Foo(int: INTEGER): INTEGER; VAR i, l: INTEGER; s: string; BEGIN s := IntToStr(int); l := length(s); result := 0; FOR i := 1 TO l DO IF (i MOD 2 = 0) THEN result := result - (INTEGER(s[1 + l - i]) - 48) ELSE result := result + (INTEGER(s[1 + l - i]) - 48); END; |
//Edit: Klammern ergänzt
Marco D. - Sa 18.11.06 17:52
Delphi-Quelltext
1:
| Result := Result - INTEGER(s[1 + l - i]) - 48 |
Würdest du mir diese Zeile bitte erklären? Vor allem die 48.
Und warum ermittelst du die Länge von s
bevor s die Zahl zugewiesen wird? Was genau ist denn bei diesem Verfahren nun der Vorteil?
Delete - Sa 18.11.06 18:02
hast recht, das mit der längengabe, hat sich 'n fehler beim layouten eingeschlichen, der ist korrigiert.
das mit dem 48 lässt sich aufklären mit 'n blick auf
http://www.torsten-horn.de/techdocs/ascii.htm, da ich jetzt einfach die zahl, die im string steht manuell umrechne, damit erspare ich mir den aufwand über den strtoint... das integer sagt dass es sich um kein zeichen sondern um einen integer handelt, wenn ich von dem integer dann 48 abziehe komme ich ganz normal auf den wert der ziffer... das andere ist die indexierung. plus 1, da der string jetzt ab 1 und nicht mehr bei 0 beginnt, ist hier für den index eine stelle hinzuzufügen.
<HTH>
Marco D. - Sa 18.11.06 18:06
Grenzgaenger hat folgendes geschrieben: |
hast recht, das mit der längengabe, hat sich 'n fehler beim layouten eingeschlichen, der ist korrigiert.
das mit dem 48 lässt sich aufklären mit 'n blick auf http://www.torsten-horn.de/techdocs/ascii.htm, da ich jetzt einfach die zahl, die im string steht manuell umrechne, damit erspare ich mir den aufwand über den strtoint... das integer sagt dass es sich um kein zeichen sondern um einen integer handelt, wenn ich von dem integer dann 48 abziehe komme ich ganz normal auf den wert der ziffer... das andere ist die indexierung. plus 1, da der string jetzt ab 1 und nicht mehr bei 0 beginnt, ist hier für den index eine stelle hinzuzufügen.
<HTH> |
Danke, ich schau's mir mal an. ;)
Martok - So 19.11.06 15:47
Marco D. hat folgendes geschrieben: |
Kann man das ganze auch lösen, ohne Stringroutinen zu benutzen? Wie könnte man dann z.B. auf die 5 Ziffer zugreifen? |
Ich weiß nicht, ob dus noch brauchst, aber ich hab hier ne Funktion. Frage ist, ob damit irgendwas schneller wird.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| function GetStelle(X:int64; St:byte):byte; var f:double; begin f:= X; while st>0 do begin f:= f / 10; dec(st); end; Result:= trunc(Frac(f)*10); end; |
Meine Testergebnisse:
Quelltext
1: 2: 3: 4: 5: 6:
| 4. Stelle von 13549586 ist 9 6. Stelle von 13549586 ist 5 15. Stelle von 13549586 ist 0 0. Stelle von 13549586 ist 0 1000000 Durchlaeufe Stelle 8.... 196,957007397027 ms |
Optimieren könnte man noch, indem man durch 10^St dividiert, statt einzeln. Wirklich schneller ist das aber auch nicht, die 1 Million Durchläufe kommt dann auf 168 ms.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| uses Math;
function GetStelle2(X:int64; St:byte):byte; var f:double; begin f:= x*Power(10,-st); Result:= trunc(Frac(f)*10); end; |
Marco D. - So 19.11.06 15:50
Danke, aber das hat sich erledigt. ;)
wulfskin - So 19.11.06 16:53
Martok hat folgendes geschrieben: |
4. Stelle von 13549586 ist 9 |
Mhhhh, ich seh die vier an vierter Stelle....
Martok - So 19.11.06 19:08
Die Stellen werden von hinten gezählt, wie immer ;)
Quelltext
1: 2:
| 4. Stelle von 13549586 ist 9 87654321 |
wulfskin - So 19.11.06 19:12
Martok hat folgendes geschrieben: |
Die Stellen werden von hinten gezählt, wie immer ;)
Quelltext 1: 2:
| 4. Stelle von 13549586 ist 9 87654321 | |
Sorry, da hab ich vor lauter Bäumen den Wald nicht gesehen. Hab in der zweiten Zeile geschaut und da hat es nach meiner Logik gestimmt.
Oh man, ich geh jetzt schlafen. Danke!
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!