String auf Zahl prüfen in Inline-Assembler

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    Unsere Datenschutzerklärung wurde aktualisiert. Mit der Nutzung unseres Forums akzeptierst Du unsere Datenschutzerklärung. Du bestätigst zudem, dass Du mindestens 16 Jahre alt bist.

    • String auf Zahl prüfen in Inline-Assembler

      Hi,
      da ich keine Ahnung von Assembler habe...:
      Kann jemand eine Funktion erstellen, mit der ich bei einem String prüfen kann ob er nur Zahlen enthält, also nur aus Ziffern und gegebenenfalls einem - davor, keine Kommas? Rückgabewert 1 oder 0 reicht.
      Ich hab so eine Funktion in reinem Profan, aber muss die teilweise 25000 Mal aufrufen, was entsprechend dauert. Wäre Assembler da überhaupt schneller?
      XProfan-Semiprofi (XProfan X4a+XPIA+LemonEd)
      Ryzen 1700X/MSI B350 PC MATE/16GB RAM@2933MHz/Radeon HD7770 OC/Creative X-Fi XTreme Music/65TB HDD+256GB Samsung 960 EVO/28" Samsung 4k
      XBox Classic/360S/One S/One X Scorpio Edition/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84) auf 60" 4k/3D LG
      OnePlus 7 8GB/256GB
      jacdelad.bplaced.net
    • Mal ein kleiner Versuch ;-)

      Quellcode

      1. CLS
      2. Declare String Meldung, Wert
      3. Declare Int Ergebnis
      4. Wert = "15,346789"
      5. ASM "IsNum", 1
      6. PUSH ESI
      7. MOV ESI, par1 // Stringadresse nach ESI
      8. XOR EAX, EAX // Register löschen
      9. schleife:
      10. LODSB // Byte von [ESI] nach AL
      11. OR AL, AL
      12. JZ ende
      13. CMP AL, $39 // vergleiche 39h
      14. JG raus0 // wenn größer, Abbruch
      15. CMP AL, $2C // vergleiche Komma
      16. JZ istkomma // JA, weiter
      17. CMP AL, $2E // vergleiche Punkt, auskommentieren, wenn nur auf Komma geprüft werden soll
      18. JZ istkomma // JA,weiter, auskommentieren, wenn nur auf Komma geprüft werden soll
      19. CMP AL, $30
      20. JNL schleife
      21. raus0: // ist keine Zahl
      22. XOR EAX, EAX // Register löschen => Rückgabewert 0
      23. JMP ok
      24. istkomma:
      25. ADD AH, 1 // Anzahl erkannter Kommas zählen
      26. JMP schleife
      27. ende:
      28. CMP AH, 2 // Anzahl Kommas
      29. JAE dkomma // 2 oder mehr
      30. MOV EAX, 1 // für gültige Zahl Rückgabewert 1 setzen
      31. JMP OK
      32. dkomma:
      33. MOV EAX, -1
      34. ok:
      35. POP ESI
      36. ENDASM
      37. Ergebnis = IsNum(Addr(Wert))
      38. If Ergebnis
      39. Meldung = "ist eine Zahl"
      40. Case Ergebnis = -1 : Meldung = Meldung + " mehrere Kommas!"
      41. Else
      42. Meldung = "enthält andere Zeichen"
      43. EndIf
      44. Print "Zahlentest " + Wert + " " + Meldung
      45. WaitInput
      Alles anzeigen
      Es wird in der ASM-Funktion ein nullterminierter String erwartet. Als Komma kann das Komma oder gleichberechtigt der Punkt stehen. Unpassende Zeilen nötigenfalls auskommentieren mit // davor oder ganz löschen. Rückgabe ist 1, wenn es eine Zahl ist oder -1, wenn mehrere Kommas enthalten sind. Sind andere Zeichen enthalten, ist die Rückgabe 0. Kommas können an beliebiger Stelle innerhalb des Strings auftreten.
      Dürfte auf jeden Fall schneller sein als reiner Profan-Code.

      Gruß Volkmar
    • Hallo Volkmar,
      danke. Es geht mir um Ganzzahlen, also ohne Komma. Und das erste Zeichen darf auch ein "-" sein, also in Prinzip ein stinknormales Integer. Kannst du deine Routine bitte nochmal mofifizieren, da ich wirklich Null Ahnung von Assembler habe?
      XProfan-Semiprofi (XProfan X4a+XPIA+LemonEd)
      Ryzen 1700X/MSI B350 PC MATE/16GB RAM@2933MHz/Radeon HD7770 OC/Creative X-Fi XTreme Music/65TB HDD+256GB Samsung 960 EVO/28" Samsung 4k
      XBox Classic/360S/One S/One X Scorpio Edition/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84) auf 60" 4k/3D LG
      OnePlus 7 8GB/256GB
      jacdelad.bplaced.net
    • Vielen Dank im Voraus. Eine andere Frage folgt dann gleich danach... :oops:
      XProfan-Semiprofi (XProfan X4a+XPIA+LemonEd)
      Ryzen 1700X/MSI B350 PC MATE/16GB RAM@2933MHz/Radeon HD7770 OC/Creative X-Fi XTreme Music/65TB HDD+256GB Samsung 960 EVO/28" Samsung 4k
      XBox Classic/360S/One S/One X Scorpio Edition/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84) auf 60" 4k/3D LG
      OnePlus 7 8GB/256GB
      jacdelad.bplaced.net
    • Jetzt sind nur die Ziffern 0 bis 9 erlaubt, das Minus kann nur als erstes Zeichen auftreten, sonst ist es ein Fehler. Rückgabewert 0 = Fehler, 1 = gültiger Int

      Quellcode

      1. CLS
      2. Declare String Meldung, Wert
      3. Declare Int Ergebnis
      4. Wert = "1534a6789"
      5. ASM "IsInt", 1
      6. PUSH ESI
      7. MOV ESI, par1 // Stringadresse nach ESI
      8. XOR EAX, EAX // Register löschen
      9. LODSB // lade erste Ziffer von [ESI] nach AL
      10. OR AL, AL
      11. JZ ende
      12. CMP AL, $2d // vergleiche 2Dh (Minus)
      13. JNZ weiter
      14. schleife:
      15. LODSB // Byte von [ESI] nach AL
      16. weiter:
      17. OR AL, AL
      18. JZ ende
      19. CMP AL, $39 // vergleiche 39h
      20. JG raus0 // wenn größer, Abbruch
      21. CMP AL, $30 // vergleiche 30h
      22. JNL schleife // wenn nicht kleiner, weiter
      23. raus0: // ist keine Zahl
      24. XOR EAX, EAX // Register löschen => Rückgabewert 0
      25. JMP ok
      26. ende:
      27. MOV EAX, 1
      28. ok:
      29. POP ESI
      30. ENDASM
      31. Ergebnis = IsInt(Addr(Wert))
      32. If Ergebnis
      33. Meldung = "ist ein Integer"
      34. Else
      35. Meldung = "enthält andere Zeichen"
      36. EndIf
      37. Print "Zahlentest " + Wert + " " + Meldung
      38. WaitInput
      Alles anzeigen


      Gruß Volkmar
    • Vielen Dank,
      es funktioniert. Ich bin von 2.6 auf 2.2 Sekunden runter. Mit Between() statt > und < auf 2 Sekunden.
      Wenn ich so frech sein darf:
      - Eine Modifikation: Der String darf nur Ziffern enthalten, ohne "-".
      - Eine Modifikation: Der String darf nicht bloß ein "-" sein, sonst wird 0 zurückgegeben.
      - Eine modifizierte Variante mit 2 Parametern: der zu prüfende String und ein String, der alle gültigen Zeichen enthält.
      XProfan-Semiprofi (XProfan X4a+XPIA+LemonEd)
      Ryzen 1700X/MSI B350 PC MATE/16GB RAM@2933MHz/Radeon HD7770 OC/Creative X-Fi XTreme Music/65TB HDD+256GB Samsung 960 EVO/28" Samsung 4k
      XBox Classic/360S/One S/One X Scorpio Edition/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84) auf 60" 4k/3D LG
      OnePlus 7 8GB/256GB
      jacdelad.bplaced.net
    • Erst mal eine Korrektur zur IsInt

      Quellcode

      1. ASM "IsInt", 1
      2. PUSH ESI
      3. MOV ESI, par1 // Stringadresse nach ESI
      4. XOR EAX, EAX // Register löschen
      5. OR ESI, ESI // Wenn Leerstring
      6. JZ raus0 // raus
      7. LODSB // lade erste Ziffer von [ESI] nach AL
      8. OR AL, AL
      9. JZ ende
      10. CMP AL, $2d // vergleiche 2Dh (Minus)
      11. JNZ weiter
      12. schleife:
      13. LODSB // Byte von [ESI] nach AL
      14. weiter:
      15. OR AL, AL
      16. JZ ende
      17. CMP AL, $39 // vergleiche 39h
      18. JG raus0 // wenn größer, Abbruch
      19. CMP AL, $30 // vergleiche 30h
      20. JNL schleife // wenn nicht kleiner, weiter
      21. raus0: // ist keine Zahl
      22. XOR EAX, EAX // Register löschen => Rückgabewert 0
      23. JMP ok
      24. ende:
      25. MOV EAX, 1
      26. ok:
      27. POP ESI
      28. ENDASM
      Alles anzeigen


      Bitte die vorherige Form ersetzen. Die stürzt ab, wenn ein Leerstring übergeben wird.

      IsIntL prüft auf Länge, es muß bei einem führenden - mindestens eine gültige Ziffer folgen. Kann allerdings auch 0 sein, auf Ausblenden führender Nullen habe ich verzichtet.

      Quellcode

      1. ASM "IsIntL", 1
      2. PUSH ESI
      3. PUSH EBX
      4. MOV ESI, par1 // Stringadresse nach ESI
      5. XOR EAX, EAX // Register löschen
      6. XOR EBX, EBX // Stellenzähler löschen
      7. OR ESI, ESI // Wenn Leerstring
      8. JZ raus0 // raus
      9. LODSB // lade erste Ziffer von [ESI] nach AL
      10. OR AL, AL
      11. JZ raus0
      12. CMP AL, $2d // vergleiche 2Dh (Minus)
      13. JNZ weiter
      14. schleife:
      15. LODSB // Byte von [ESI] nach AL
      16. weiter:
      17. OR AL, AL
      18. JZ ende
      19. CMP AL, $39 // vergleiche 39h
      20. JG raus0 // wenn größer, Abbruch
      21. CMP AL, $30 // vergleiche 30h
      22. JL raus0 // wenn kleiner, Abbruch
      23. INC EBX // Ziffernstelle zählen
      24. JMP schleife
      25. raus0: // ist keine Zahl
      26. XOR EAX, EAX // Register löschen => Rückgabewert 0
      27. JMP ok
      28. ende:
      29. XOR EAX, EAX
      30. OR EBX, EBX // Wenn Stellenzähler leer
      31. JZ ok // raus
      32. MOV EAX, 1 // sonst Rückgabe auf 1 setzen
      33. ok:
      34. POP EBX
      35. POP ESI
      36. ENDASM
      Alles anzeigen

      IsNum erlaubt nur die Ziffern 0 bis 9

      Quellcode

      1. ASM "IsNum", 1
      2. PUSH ESI
      3. MOV ESI, par1 // Stringadresse nach ESI
      4. XOR EAX, EAX // Register löschen
      5. OR ESI, ESI // wenn Leerstring
      6. JZ raus0 // raus
      7. schleife:
      8. LODSB // Byte von [ESI] nach AL
      9. weiter:
      10. OR AL, AL
      11. JZ ende
      12. CMP AL, $39 // vergleiche 39h
      13. JG raus0 // wenn größer, Abbruch
      14. CMP AL, $30 // vergleiche 30h
      15. JNL schleife // wenn nicht kleiner, weiter
      16. raus0: // ist keine Zahl
      17. XOR EAX, EAX // Register löschen => Rückgabewert 0
      18. JMP ok
      19. ende:
      20. MOV EAX, 1
      21. ok:
      22. POP ESI
      23. ENDASM
      Alles anzeigen


      Und dann noch eine Funktion, da soll der Vorrat an gültigen Zeichen als zweiter String vorgegeben werden, wenn ich richtig verstanden habe. Dauert dann noch etwas, kommen erst im Laufe des Abends dazu.
      Auf das Profan-Drumherum habe ich hier mal verzichtet, damit die Codes nicht zu lang werden. War ja nur zum Prüfen, Du baust es ja ohnehin bei Dir ein ;-)

      Gruß Volkmar
    • @Volkmar: Danke für die neuen Funktionen. IsIntL drückt meinen Test nochmal auf 1.7 Sekunden (weil ich mir die Prüfung, ob der String nur aus einem "-" besteht, spare), das ist genial.
      @p.specht: Bestimmt, aber ich führe die Funktion zum Teil 25000 mal aus und etliche anderen noch dazu. Keine Ahnung was wirklich schneller ist. Es geht um ein Prgramm, was mir meine neue Arbeit erleichtern soll und die Rechner bei mir auf Arbeit sind...nun ja...leicht antik. Ich selbst besitze einen Ryzen 7 1700X, das sind's 2.5 Sekunden, aber auf Arbeit wird schnell eine Viertelminute draus.
      XProfan-Semiprofi (XProfan X4a+XPIA+LemonEd)
      Ryzen 1700X/MSI B350 PC MATE/16GB RAM@2933MHz/Radeon HD7770 OC/Creative X-Fi XTreme Music/65TB HDD+256GB Samsung 960 EVO/28" Samsung 4k
      XBox Classic/360S/One S/One X Scorpio Edition/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84) auf 60" 4k/3D LG
      OnePlus 7 8GB/256GB
      jacdelad.bplaced.net
    • Und nun mal noch Einen. Gestern Abend wollte er nicht mehr, aber nach dem Morgenkaffee habe ich mein Problem gesehen ;-)

      Erster String ist der zu prüfende String und der zweite String enthält die Liste der gültigen Zeichen. Das Ergebnis ist 1, wenn jedes Zeichen aus String 1 an irgend einer Position in String 2 enthalten ist. Alle anderen Fälle liefern 0


      Quellcode

      1. CLS
      2. Declare String Meldung, Wert, Ref
      3. Declare Int Ergebnis
      4. Wert = "11231ab2312e"
      5. Ref = "12345abcde"
      6. ASM "CharTest", 2
      7. PUSH ESI
      8. PUSH EDI
      9. PUSH EDX
      10. MOV ESI, par1 // Stringadresse nach ESI
      11. MOV EDI, par2 // Stringadresse Referenz nach EDI
      12. OR ESI, ESI // Test auf Leerstring
      13. JZ fehler
      14. OR EDI, EDI // Test auf Leerstring
      15. JZ fehler
      16. XOR EAX, EAX // Register löschen
      17. MOV EDX, EDI // Referenzadresse merken
      18. schleife:
      19. MOV EDI, EDX // gemerkte Referenzadresse laden für neuen Durchlauf
      20. LODSB
      21. OR AL, AL // Stringende
      22. jz ok
      23. ischleife:
      24. MOV AH, [EDI] // Byte von Referenz
      25. OR AH, AH // wenn 0
      26. JZ fehler // nicht gefunden, Fehler
      27. CMP AL, AH // Zeichen testen
      28. JZ schleife // ist gültig, nächstes Zeichen
      29. INC EDI // sonst innere Schleife hochzählen
      30. JMP ischleife // und innen weiter
      31. Fehler:
      32. XOR EAX, EAX
      33. JMP raus
      34. ok:
      35. MOV EAX, 1
      36. raus:
      37. POP EDX
      38. POP EDI
      39. POP ESI
      40. ENDASM
      41. Ergebnis = CharTest(Addr(Wert), Addr(Ref))
      42. If Ergebnis
      43. Meldung = "ist gültig"
      44. Else
      45. Meldung = "enthält andere Zeichen"
      46. EndIf
      47. Print "Zahlentest " + Wert + " " + Meldung
      48. WaitInput
      Alles anzeigen



      Gruß Volkmar
    • Wow, vielen Dank, werde ich gleich testen. Das sind die Dinge die ich mal in einem anderen Thread meinte mit "Assemblerfunktionen sammeln" bzw. eine Bibliothek erzeugen.
      XProfan-Semiprofi (XProfan X4a+XPIA+LemonEd)
      Ryzen 1700X/MSI B350 PC MATE/16GB RAM@2933MHz/Radeon HD7770 OC/Creative X-Fi XTreme Music/65TB HDD+256GB Samsung 960 EVO/28" Samsung 4k
      XBox Classic/360S/One S/One X Scorpio Edition/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84) auf 60" 4k/3D LG
      OnePlus 7 8GB/256GB
      jacdelad.bplaced.net
    • Ist das eventuell auch in Assembler umsetzbar?

      Quellcode

      1. proc ValidLine
      2. Parameters p$
      3. casenot InStr("\t",p$):Return 0
      4. declare valid%,q$
      5. whileloop 8
      6. q$=SubStr$(p$,&Loop,"\t")
      7. if q$=""
      8. valid%=SetBit(valid%,&Loop,1)
      9. else
      10. Select &Loop
      11. CaseOf 3,4
      12. if Not(IsIntL(Addr(q$)))
      13. valid%=SetBit(valid%,&Loop,1)
      14. endif
      15. CaseOf 5
      16. ifnot IsIntL(Addr(q$)) AND Between(Val(q$),0,359)
      17. Inc valid%,32
      18. endif
      19. CaseOf 7,8
      20. if q$<>"0"
      21. valid%=SetBit(valid%,&Loop,1)
      22. endif
      23. EndSelect
      24. endwhile
      25. endif
      26. Return valid%
      27. endproc
      Alles anzeigen
      Die Funktion testet einen String, der aus 8 Teilstücken, getrennt durch \t bestehen soll wobei einige Abschnitte nur Zahlen enthalten dürfen und die letzten beiden 0 sein müssen.
      XProfan-Semiprofi (XProfan X4a+XPIA+LemonEd)
      Ryzen 1700X/MSI B350 PC MATE/16GB RAM@2933MHz/Radeon HD7770 OC/Creative X-Fi XTreme Music/65TB HDD+256GB Samsung 960 EVO/28" Samsung 4k
      XBox Classic/360S/One S/One X Scorpio Edition/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84) auf 60" 4k/3D LG
      OnePlus 7 8GB/256GB
      jacdelad.bplaced.net
    • Nur wenn du viel Zeit und Lust hast, ich hab schon ein bisschen ein schlechtes Gewissen hier Leute für mein Projekt einzuspannen.
      XProfan-Semiprofi (XProfan X4a+XPIA+LemonEd)
      Ryzen 1700X/MSI B350 PC MATE/16GB RAM@2933MHz/Radeon HD7770 OC/Creative X-Fi XTreme Music/65TB HDD+256GB Samsung 960 EVO/28" Samsung 4k
      XBox Classic/360S/One S/One X Scorpio Edition/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84) auf 60" 4k/3D LG
      OnePlus 7 8GB/256GB
      jacdelad.bplaced.net
    • Hallo Heinz,
      hab ich und muss ich mal probieren.

      In meinem Test dauert das Einlesen und Verarbeiten einer Cad-Datei etwa 2.4 Sekunden. Wenn ich ValidLine für jede Zeile weglasse, dann komme ich auf 0.8 Sekunden. Ich kann leider nicht zu sehr ins Detail gehen, da das Programm für meine Arbeit ist und da kommt natürlich das Betriebsgeheimnis ins Spiel...

      Vielleicht wäre die Funktion noch besser (* am Anfang leitet einen Kommentar ein):

      Quellcode

      1. proc ValidLine
      2. Parameters p$
      3. declare valid%,q$
      4. whileloop 8
      5. q$=SubStr$(p$,&Loop,"\t")
      6. if q$=""
      7. valid%=SetBit(valid%,&Loop,1)
      8. else
      9. Select &Loop
      10. CaseOf 3,4
      11. if Not(IsIntL(Addr(q$)))
      12. valid%=SetBit(valid%,&Loop,1)
      13. endif
      14. CaseOf 5
      15. ifnot IsIntL(Addr(q$)) AND Between(Val(q$),0,359)
      16. Inc valid%,32
      17. endif
      18. CaseOf 7,8
      19. if q$<>"0"
      20. valid%=SetBit(valid%,&Loop,1)
      21. endif
      22. EndSelect
      23. endwhile
      24. endif
      25. Return valid%
      26. endproc
      Alles anzeigen
      ... auf \t wird schon im Programm geprüft.
      XProfan-Semiprofi (XProfan X4a+XPIA+LemonEd)
      Ryzen 1700X/MSI B350 PC MATE/16GB RAM@2933MHz/Radeon HD7770 OC/Creative X-Fi XTreme Music/65TB HDD+256GB Samsung 960 EVO/28" Samsung 4k
      XBox Classic/360S/One S/One X Scorpio Edition/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84) auf 60" 4k/3D LG
      OnePlus 7 8GB/256GB
      jacdelad.bplaced.net
    • Match ist leider langsamer und ein Move hat irgendwie auch nicht geholfen.
      XProfan-Semiprofi (XProfan X4a+XPIA+LemonEd)
      Ryzen 1700X/MSI B350 PC MATE/16GB RAM@2933MHz/Radeon HD7770 OC/Creative X-Fi XTreme Music/65TB HDD+256GB Samsung 960 EVO/28" Samsung 4k
      XBox Classic/360S/One S/One X Scorpio Edition/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84) auf 60" 4k/3D LG
      OnePlus 7 8GB/256GB
      jacdelad.bplaced.net

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Jac de Lad ()

    • Aktuelle Variante:

      Quellcode

      1. proc ValidLine
      2. Parameters q$
      3. declare valid%,a$[],loop&
      4. a$[]=Explode(q$,"\t")
      5. For loop&,0,7
      6. if a$[loop&]=""
      7. valid%=SetBit(valid%,Loop&,1)
      8. else
      9. Select Loop&
      10. CaseOf 2,3
      11. ifnot IsIntL(Addr(a$[loop&]))
      12. valid%=SetBit(valid%,Loop&,1)
      13. endif
      14. CaseOf 4
      15. ifnot IsIntL(Addr(a$[loop&])) AND Between(Val(a$[loop&]),0,359)
      16. Inc valid%,16
      17. endif
      18. CaseOf 6,7
      19. if a$[loop&]<>"0"
      20. valid%=SetBit(valid%,Loop&,1)
      21. endif
      22. EndSelect
      23. EndFor
      24. endif
      25. Return valid%
      26. endproc
      Alles anzeigen
      Explode hat was gebracht, genauso wie beim Bit 0 beginnen statt bei 1. Das Auslesen im Hauptprogramm wurde natürlich auch angepasst. Alles in Allem spare ich so nochmal etwa 200 Millisekunden, nicht schlecht.
      XProfan-Semiprofi (XProfan X4a+XPIA+LemonEd)
      Ryzen 1700X/MSI B350 PC MATE/16GB RAM@2933MHz/Radeon HD7770 OC/Creative X-Fi XTreme Music/65TB HDD+256GB Samsung 960 EVO/28" Samsung 4k
      XBox Classic/360S/One S/One X Scorpio Edition/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84) auf 60" 4k/3D LG
      OnePlus 7 8GB/256GB
      jacdelad.bplaced.net