Seite 1 von 2

Euro in Cent umwandeln in einer Miniversion

Verfasst: 20.05.2008 21:29
von hjbremer
Für alle die Euro-Beträge aus einer Liste mit formatierten Zahlen in Cent umwandeln müssen um dann mit Ganzzahlen weiterrechnen wollen.
Es wird vorausgesetzt, das jede Zahl 2 Kommastellen hat.

Hier meine Miniversion im Vergleich zu 3 anderen Standardversionen.

Fällt jemandem etwas schnelleres ein, so möge er mir dies unbedingt mitteilen, denn ich muß meine Liste mit über 5000 Zeilen häufig neu berechnen. Ich habe die Daten aber nicht in Feldern zusätzlich abgelegt. Ist mir zu aufwändig.

Code: Alles auswählen

Procedure uc(euro$)

    ProcedureReturn ValF(euro$)*100 

EndProcedure

Procedure uc0(euro$)

    ProcedureReturn Val(ReplaceString(euro$,".","",1)) 

EndProcedure

Procedure uc1(euro$)

    ProcedureReturn Val(RemoveString(euro$,".",1)) 

EndProcedure

Procedure uc2(euro$)

    *z = @euro$
    lg = Len(euro$) -3
    
    CopyMemory(*z,*z+1,lg)
    PokeC(*z,' ')
    
    ProcedureReturn Val(euro$)

EndProcedure

;Test ohne Debugger !!!

max = 100000

a=GetTickCount_() 
 For j = 1 To max
   cent = uc("61023.45")
 Next
b=GetTickCount_()-a 

a=GetTickCount_() 
 For j = 1 To max
   cent0 = uc0("61023.45")
 Next
c=GetTickCount_()-a 

a=GetTickCount_() 
 For j = 1 To max
   cent1 = uc1("61023.45")
 Next
d=GetTickCount_()-a 

a=GetTickCount_() 
 For j = 1 To max
   cent2 = uc2("61023.45")
 Next
e=GetTickCount_()-a 

MessageRequester("",Str(cent)+" Normal  ="+Str(b)+#LF$+Str(cent0)+" Replace ="+Str(c)+#LF$+Str(cent1)+" Remove ="+Str(d)+#LF$+Str(cent2)+" Memory ="+Str(e)) 

Verfasst: 20.05.2008 23:11
von AND51
Kleine Beschreibung wäre zu jeder Prozedur angebracht; du musst außerdem auch vernünftige namen für die prozeduren vergeben. Durch kürze Prozedurnamen wird deine Prozedur sowieso nicht schneller und "zu viel zu tippen" gibt's auch nicht als Ausrede, da das Autovervollständigen schon erfunden wurde.

Ich arbeite gerade an Verbesserungen und werde gleich Posten.
Bin sicher, da kann man noch was rausholen.

Schimpfen muss ich auch:
uc0() - Wozu gibt's da RemoveString(), um etwas zu entfernen? :wink:


// Edit:
> Ist mir zu aufwändig
Du liest einen Betrag als String aus der Liste, konvertierst sie zum Rechnen in eine Zahl und dann hinterher wieder zurück in einen String? Performance, leb wohl... :lol:

Verfasst: 20.05.2008 23:25
von hjbremer
mit Liste ist ein ListIconGadget gemeint und da liefert PB nur Strings zurück oder ?

und Removestring siehe uc1 !

Verfasst: 20.05.2008 23:40
von AND51
Aber GetGadgetItemData() nicht, wenn du das Data Feld mitbenutzen würdest, sofern möglich.
Nix Beschreibung, jetzt hab ich verstanden: ALLE Prozeduren wandeln in Cent um und du willst die schnellste. Jetzt verstehe ich auch den Unterschied zwischen uc0 ohne und uc1 mit RemoveString.

Sorry, das habe ich jetzt erst verstanden. Eine Prozedur habe ich schon fertig, ca. 8x schneller als uc0. Tüftle noch.

Übrigens: Deine letzte Prozedur funzt nicht... Du verschiebst alle zeichen im Buffer 1 nach rechts?
3 Fehler:

1. Die Speicherbereiche überlappen sich - MoveMemory() ist hier sicherer, wenn auch langsamer
2. Du verschiebst alle Zeichen um 1 nach rechts OHNE den Speicher zu re-allokieren (ReAllocateMemory()); BÖÖÖSE
3. Du setzt vor die ganze Zahl ein Leerzeichen? Wozu, damit Val() immer 0 zurückgibt?

Verfasst: 21.05.2008 00:10
von AND51
Macht Platz für den Gewinner:

Code: Alles auswählen

Procedure EurToCnt(Euro$)
	Protected *digit2.Character=@Euro$+MemoryStringLength(@Euro$)<<#PB_Compiler_Unicode-SizeOf(Character)
	Protected *digit1.Character=*digit2-SizeOf(Character)
	Protected *comma.Character=*digit1-SizeOf(Character)
	Swap *comma\c, *digit2\c
	Swap *comma\c, *digit1\c
	ProcedureReturn Val(Euro$)
EndProcedure

Debug EurToCnt("61023.45")
Hatt erst 2 prozeduren, diese hier war aber in 2 von 3 Fällen schneller.

Speedtest bei 100.000 rpm:
  • Normal = 313
    Replace= 93
    Remove = 79
    EurToCnt = 62
Speedtest bei 1.048.576 rpm:
  • Normal = 4375
    Replace= 1343
    Remove = 1078
    EurToCnt = 813
Speedtest bei 16.777.216 rpm:
  • Normal = 74297
    Replace= 18063
    Remove = 13047
    EurToCnt = 10625
Memory entfällt, da diese Prozedur nicht funktioniert. Der Gewinner ist... tadaaaa... jedes Mal ICH! :lol:

Verfasst: 21.05.2008 21:36
von hjbremer
Deine geniale Version etwas schneller

Code: Alles auswählen

Procedure EurToCnt(*mem) 
   Protected *digit2.Character=*mem+MemoryStringLength(*mem)<<#PB_Compiler_Unicode-SizeOf(Character) 
   Protected *digit1.Character=*digit2-SizeOf(Character) 
   Protected *comma.Character=*digit1-SizeOf(Character) 
   Swap *comma\c, *digit2\c 
   Swap *comma\c, *digit1\c 
EndProcedure 

   euro$= "61023.45"
   *zeiger = @euro$
   EurToCnt(*zeiger)
   cent = Val(euro$)
   Debug cent
   
Und da dir meine CopyMemory Version nicht gefällt
hier im Prinzip das Gleiche nur anders und genau so schnell wie oben.

Code: Alles auswählen

Structure ZahlenFormatC
 c.c[0]
EndStructure 
 
Procedure EurToCnt1(*z.ZahlenFormatC) 
   
   lg = MemoryStringLength(*z) - 1
   
   *z\c[lg-2] = *z\c[lg-1] 
   *z\c[lg-1] = *z\c[lg] 
   *z\c[lg]   = 0 
   
EndProcedure 

   euro$= "61023.45"
   *zeiger = @euro$
   EurToCnt1(*zeiger)
   cent = Val(euro$)
   Debug cent
   
Ich denke noch schneller wird man nur noch mit Assembler Befehlen. Ein Schwachpunkt ist MemoryStringLength. Ich kenn mich damit leider nicht aus, aber es gibt doch den Befehl _strstr. Gibt es nicht vielleicht sowas wie _strlen ?

Verfasst: 21.05.2008 22:14
von AND51
Irre ich mich, oder hast du bei meiner Prozedur im Prinzip nur das Val() + das Return ausgegliedert?
P.S.: Deine 2. Version ist soweit ich das sehe, vom Prinzip her ähnlich wie meine, oder?

MemoryStringLength ist schon okay, die Alternative wäre StringByteLength, aber letzteres arbeitet ohne Pointer und ist daher hier ungeeignet.

P.S.: Deine 2. Version funktioniert nur im ASCII-Modus, sie wird in Unicode nicht funktionieren. statt in der ersten Zeile -1 zu rechnen, nimm lieber -SIzeOf(Character)

Verfasst: 21.05.2008 22:44
von edel
Solch eine Funktion hat doch ueberhaupt keinen Nutzen. Was nuetzt die
Geschwindigkeit wenn die Sicherheit darunter zu leiden hat?

Verfasst: 22.05.2008 00:10
von AND51
edel, du hättest nur dann Recht, wenn hjbremer hier —wie immer in der Code-Tipps-Tricks-Ecke— einen Universalcode veröffentlichen würde.

Der Code hat sehr wohl einen Nutzen, schon mal die "Aufgabenstellung" gelesen? Wohl kaum!
Er sucht hier nach einer möglichst schnellen Prozedur für genau sein Problem: Eine Liste mit String-basierten Eurowerten, die immer 2 Nachkommastellen haben, in Cent umzuwandeln.
Die hier geposteten Codes dürften also nur exakt auf sein Problem zutreffen.

Natürlich hat er in das falsche Subforum gepostet. Aber da kein Mod den Thread hier mal nach Allgemein verschoben hat und du auch noch nach dem nicht vorhandenen allgemeinen Nutzen fragst, kann man davon ausgehen,
dass niemand außer mir sich diesen Thread durchgelesen hat.

Verfasst: 22.05.2008 01:09
von edel
AND51 hat geschrieben:bla, bla bla bla bla bla, bla bla bla —bla bla bla bla bla-bla-bla-bla— bla bla bla bla.

bla bla bla bla bla bla bla, bla bla bla "bla" bla? bla bla!
bla bla bla bla bla bla bla bla bla bla bla bla: bla bla bla bla-bla bla, bla bla bla bla bla, bla bla bla.
bla bla bla bla bla bla bla bla bla bla bla bla.

bla bla bla bla bla bla bla bla. bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla, bla bla bla bla,
bla bla bla bla bla bla bla bla bla.
Bitte?
Naja, da kann man ja nur hoffen das wenigstens du verstehst, was da steht.