[C++] string in long umwandeln

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

  • [C++] string in long umwandeln

    Hi,
    ich habe mir gedacht aus Lust und Laune ein Verschlüsselungsprogramm zu entwickeln. Zu einem kann es binär dingens in eine Zahl umwandeln und umgekehrt.
    Problem: Um z.B. die Letzte Stelle anzuschauen, hab ich mir eine Funktion gemacht, womit man auch Positionen von Zahlen ausfindig machen kann. Vorgehensweise: zahl in string umwandeln mit string.at() position ausgeben und wieder als Zahl zurückgeben.
    Spoiler anzeigen

    Quellcode

    1. int numb_at(int numb, int pos){
    2. string n = in_string(numb);
    3. n = n.at(pos);
    4. numb = in_int(n);
    5. return numb;
    6. }

    Klappt auch. Als ich aber die Zahl 11010001100 hatte kam ein Fehler, der kommt wenn man mit at zu weit geht, also wenn man 3 buchstaben hat aber die 4. Position haben will. wenn ich die letzte 0 weg lasse kommt der nich-

    ich hoffe ihr habt da etwas Erfahrung :rolleyes:

    edit: meine Funktion in_string ist fehlerhaft.
    edit2: weis jemand wie man eine convertierung von intenger in string macht
    Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
    Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

    Willst du mit mir auf Discord Chatten/Quatschen?
    Meine Husi's Tutorial Reihe

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von husi012 ()

  • Dein oben geposteter Code scheint nicht das Problem zu sein, (ohne die Fehlermeldung genau zu kennen) tippe ich auf einen falschen index (scheint nach kurzer Webrecherche ziemlich common zu sein).

    sollte laut stackoverflow relativ easy mit:

    Quellcode

    1. std::string s = std::to_string(42);

    gehen


    EDIT:

    habe doch glatt den comment darunter überlesen:
    to_string not a member of std

    sollte wie folgt lösbar sein:

    Quellcode

    1. #include <string>


    i think, therefore 私 は.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von domis4 ()

  • hab ich auch schon gesehen, aber komischerweise kennt der die Funktion nicht.
    Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
    Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

    Willst du mit mir auf Discord Chatten/Quatschen?
    Meine Husi's Tutorial Reihe
  • ​edit2: weis jemand wie man eine convertierung von intenger in string macht

    Das kann man mit Stringstreams machen:

    Quellcode

    1. ostringstream my_stream;
    2. my_stream << your_number; // your_number ist die Zahl die du konvertieren möchtest
    3. my_stream.str() // Liefert dann den String bestehend aus den Ziffern deiner Zahl

  • Ok mein code war das selbe mit stringstream. Ich werds mal ausprobieren
    Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
    Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

    Willst du mit mir auf Discord Chatten/Quatschen?
    Meine Husi's Tutorial Reihe
  • Habe ich damals für eine eigene String Klasse geschrieben. Habe es mal kurz in eine statische Funktion umgeschrieben. War jedenfalls viel Arbeit sowas selbst zu schreiben, besonders die Zeile 38.

    Quellcode

    1. wchar_t* int_to_wchar_t(int s_number, unsigned char places)
    2. {
    3. bool neg = false;
    4. if(s_number < 0)
    5. {
    6. s_number = -s_number;
    7. neg = true;
    8. }
    9. unsigned int number = s_number;
    10. unsigned int size;
    11. if(number == 0)
    12. size = 0;
    13. else if(number < 10)
    14. size = 1;
    15. else if(number < 100)
    16. size = 2;
    17. else if(number < 1000)
    18. size = 3;
    19. else if(number < 10000)
    20. size = 4;
    21. else if(number < 100000)
    22. size = 5;
    23. else if(number < 1000000)
    24. size = 6;
    25. else if(number < 10000000)
    26. size = 7;
    27. else if(number < 100000000)
    28. size = 8;
    29. else if(number < 1000000000)
    30. size = 9;
    31. else
    32. size = 10;
    33. if(size < places)
    34. size = places;
    35. const wchar_t *dezi[] = {L"1",L"2",L"4",L"8",L"61",L"23",L"46",L"821",L"652",L"215",L"4201",L"8402",L"6904",L"2918",L"48361",L"86723",L"63556",L"270131",L"441262",L"882425",L"6758401",L"2517902",L"4034914",L"8068838",L"61277761",L"23445533",L"46880176",L"827712431",L"654534862",L"219078635",L"4281473701"};
    36. unsigned int ui_len = size+neg;
    37. wchar_t *wc_data = new wchar_t[ui_len+1];
    38. for(unsigned int i=0;i<ui_len;i++)
    39. wc_data[i] = L'0';
    40. wc_data[ui_len] = 0;
    41. for(unsigned int i=0; i<31; i++)
    42. {
    43. if(number & 1)
    44. {
    45. for(unsigned int j=0;dezi[i][j]; j++)
    46. {
    47. wc_data[ui_len-j-1] += dezi[i][j]-L'0';
    48. if(wc_data[ui_len-j-1] > L'9')
    49. {
    50. wc_data[ui_len-j-1] -= 10;
    51. wc_data[ui_len-j-2] += 1;
    52. }
    53. }
    54. }
    55. number >>= 1;
    56. }
    57. if(neg)
    58. wc_data[0] = L'-';
    59. return wc_data;
    60. }
    Alles anzeigen

  • Nochmal kurz was zu std::to_string:
    Das ist eine Funktion in <string>, die für alle elementaren Datentypen einmal überladen ist und sie in einen std::string umwandeln kann - so wie es die C-Funktion sprintf(char* buf, const char* format, ...), mit entsprechend eingesetztem Format, tun würde. Wenn's geht, solltest du die gegenüber Stringstreams bevorzugen, das ist nämlich effizienter.

    Allerdings ist sie erst mit C++11 dazu gekommen; du solltest also erst deinen Compiler drauf einstellen, diesen Standard oder C++14 zu benutzen.
  • Chris987 schrieb:

    Quellcode

    1. unsigned int size;
    2. if(number == 0)
    3. size = 0;
    4. else if(number < 10)
    5. size = 1;
    6. else if(number < 100)
    7. size = 2;
    8. else if(number < 1000)
    9. size = 3;
    10. else if(number < 10000)
    11. size = 4;
    12. else if(number < 100000)
    13. size = 5;
    14. else if(number < 1000000)
    15. size = 6;
    16. else if(number < 10000000)
    17. size = 7;
    18. else if(number < 100000000)
    19. size = 8;
    20. else if(number < 1000000000)
    21. size = 9;
    22. else
    23. size = 10;
    24. if(size < places)
    25. size = places;
    Alles anzeigen


    Also, vom ganzen Rest mal abgesehen...log10 wäre bei sowas seeehr hilfreich. Gibt dir dann (nachm runden), die Anzahl Stellen an die zur Darstellung der Zahl nötig sind (in Basis 10). log2 würde dir dann z.B. anzeigen wieviele Bits du benötigst um die Zahl in Binär darzustellen.

  • Ich habe hier ganz bewusst auf log10 verzichtet, da dies eine relativ langsame Funktion ist. Zudem wollte ich von keinen Bibliotheken abhängig sein, auch wenn sie zum Standard gehören. Und sicher gibt es an der ein oder anderen Stelle auch Optimierungsbedarf. Ich habe den Code schon größtenteils in Inlineassembler geschrieben, welche bei dieser Konvertierung nur mit den Registern der CPU auskommt. Diese ist dann sogar schneller als die herkömmlichen Funktionen. Mich würde gerne der Rest interessieren, wo ich etwas einfacher oder/und schneller lösen könnte. Ich hoffe du könntest mich da Aufklären.

  • Jeder halbwegs vernünftige Compiler ersetzt das durch einen(!) entsprechenden ASM Befehl. Und log10 gehört zum C++ Standard, Bist da also nicht von irgendwas großartig "abhängig".
    Die Lösung da oben hat allein schon wegen des ganzen if/else-Trees da verschieden lange Laufzeiten und unnötig viele Branches.

    Das wc_data würde ich durch ein stack basiertes array ersetzen. Verringert die Laufzeit bei häufigen Aufrufen deutlich. Eine maximale Größe ist ja bekannt.
    Könnte man auch static machen, aber dann bekommst du Probleme sobald Threads ins Spiel kommen.

    Ansonsten kann ich spontan nur hieran "meckern": "if(number & 1)". NIE, NIE auf den simplen "ungleich 0" Vergleich in C/C++ verlassen. IMMER ne komplette Bedingung hinschreiben. Also "if((number & 1) != 0)"

    EDIT: bezüglich inline assembler version: auf gar keinen Fall. Wenn du Register forcierst geht all die Optimierung flöten die der Compiler während der register allocation macht. Also so n 1-2 Zeilen inline asm...ok, wenns sein muss. Aber längerer Code? Damit schießt du dir am Ende mehr in den Fuß als du optimierst. (Und Typos korrigiert)

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von rootnode ()

  • Ich habs jetzt mal mit ostringstream ausprobiert und es klappt! :thumbsup: :D
    Tausend und einen Dank und alle

    Edit: Muss ich doch zurück nehmen, bei kleinen Zahlen funktioniert es, aber bei großen kommt eine große negative Zahl raus:(
    Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
    Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

    Willst du mit mir auf Discord Chatten/Quatschen?
    Meine Husi's Tutorial Reihe
  • Integer können nur einen Zahlenraum von −2.147.483.648 bis 2.147.483.647 abdecken. Darüber hinaus entsteht ein Overflow, was eine undefinierte Zahl zur Folge hat. Um größere Zahlen darzustellen benötigt man einen Datentyp wie z.B long.
    Bezüglich nochmal meines Codes: Ich danke erstmal für deine Vorschläge, trotzdem sollte man den eigentlichen Sinn dahinter verstehen. Es ist eine Funktion aus einer selbstgeschriebenen String Klasse welche ich in kurzer Zeit umgeschrieben habe und diese ist auf den Heap angewiesen, weil dort eben keine maximale Größe bekannt ist. Es kann eine einfache Zahl sein, es kann aber auch ein Text mit über 1000 Wörtern sein. Der Heap bietet dafür eine effektive Speicherverwaltung an. Ich habe auch überlegt einen Großen statischen Speicherbereich anzulegen und darauf zurückzugreifen.
    Dann zum Ungleich Null: Es ist völlig gang und gebe eine solche Schreibweise zu haben, da dies zum Standard von C++ gehört. Es hält zudem den Code meiner Ansicht nach übersichtlich und verständlich.
    Und zum Inline Assembler kann ich dir versichern, dass der Code um einiges Schneller ist, selbst mit Codeoptimierung. Ich nutze hierbei VS2012. Es erlaubt einen Strukturen zu bilden welche in C++ nicht existieren. Z.B kann ich einfach das Carry-Flag benutzen bei einer Verschiebung. Das der Code dabei um einiges unübersichtlicher wird ist mir schon klar. Der Code ist jetzt aber wirklich nicht groß. Das mit der register allocation ist, tut mir leid, völliger Unsinn. Dadurch, dass ich nicht auf den Hauptspeicher zugreife, würde er garnicht erst zum Einsatz kommen. Ok gut, ich greife einmal am Anfang darauf zu und dreimal am Ende. Daran kann man aber nichts mehr Optimieren. Dies würde ausgerechnet durchschnittlich auch nur eine Nanosekunde Zeit beanspruchen. Ich glaube das ist absolut vertretbar.
    Ich entschuldige mich dafür, dass ich ein wenig Off-Topic werde.

  • Moment...das ERGEBNIS deiner int-to-string Methode kann ein Text mit über 1000 Wörtern sein? Dann ist da aber ganz gründlich was schiefgegangen.
    Aber okay. Akzeptieren wir mal dass du uuuunbedingt den Heap benötigst. Warum dann kein std::vector als Container? Wenn du mir schon mit dem C++ Standard anreitest?
    Bezüglich des ungleich Null Vergleichs: also...zum "Standard" gehört es eher nicht das so zu schreiben. Es ist erlaubt, aber zum "Standard" bzw. eher zu den guten Praktiken gehört das schon lange nicht mehr. Oder willst du mit sowas als Argument auch goto benutzen?

    Du manipulierst/verlässt dich manuell aufs Carry-Flag? Are you serious?

    Und das mit der register allocation ist, tut mir leid, kein Unsinn. Es ist dabei völlig egal ob du in deinem Code auf den RAM zugreifst oder nicht. Es geht dabei um die REGISTER, wie der Name schon sagt. Sobald du durch inline assembler, manuell feste Register vorgibst, dann zerschießt dir das jegliche Optimierung die der Compiler dir diesbezüglich hinwerfen könnte. Als Lektüre empfehle ich dazu z.B. die Thesis hier christianwimmer.at/Publications/Wimmer04a/Wimmer04a.pdf
    Und ob der Code um einiges schneller ist bezweifle ich. Richtig benchmarken ist gerade bei inline asm kram und so kurzen Funktionen eher schwierig.

    PS: deine Hauptspeicherzugriffe benötigen durchschnittlich eine Nanosekunde? Also DEN Speicher hätt ich gerne. Oder hast du nur 4MB Ram verbraucht und taufst ihn liebevoll L2? (Und selbst dann wäre das schnell)

  • Langsam wird es albern und ich frage mich ob du das extra überliest. Es ist eine Funktion aus einer String Klasse, welche einen eigenen Speicheralgorithmus hat. Die Funktion ist nur eine einfache Entnahme aus dieser Stringklasse und wurde funktionstüchtig geschrieben. Das dies so als einzige Funktion fungiert ist eher suboptimal, das ist mir schon klar. Beim Speicherzugriff war es zugegeben eine sehr grobe Berechnung. Deswegen nochmal die genaue: Ein Takt dauert bei mir 1/(4GHz) = 1/(4*109Hz) = 0,25*10-9s lang. Nun benötigt ein Speicherzugriff 8 Takte, das heißt es sind insgesamt 2*10-9 Sekunden pro Speicherzugriff. Eine Nanosekunde entspricht nun 10-9 Sekunden, was dann wiederum einer Zeit von 2ns enstpricht. Das ist trotzdem noch immer sehr schnell. Im Vergleich benötigt dann ein Registerzugriff nur 2 Takte und im L2 etc. Speicher 4 Takte. Nun wird hier ein Array benutzt um den Text abzuspeichern. Anstatt jetzt jedes Zeichen jedes Mal aus dem Speicher zu lesen greife ich auf drei Register mit der Größe von 32bit zu, da die Zahl wie du schon selbst gesagt hast, maximal 11 Zeichen Groß werden kann. Nun benutze ich anstatt wchar_t einfach nur char, da dies nur 8bit benötigt. Die Zahl benötig jetzt maximal 12 Chars mit dem Nullzeichen, also 96bit. Dies passt perfekt in die drei Register. Nun brauche ich nur noch die drei Register in mein Array zu laden, was jetzt nur noch 24 Takte benötigt. Ich führe also alle Berechnungen in den Registern aus, anstatt das sehr viele Speicherzugriffe auf das Array erfolgen. Um mit solchen Registern auch arbeiten zu können wird Assembler benötigt, eben weil ich keine Kontrolle habe wie der Compiler das Optimiert. Dieser braucht nur einmal eine Sicherheitsüberprüfung einzubauen und alles würde extrem Verlangsamt werden, weil z.B die Register dafür nicht mehr ausreichen. Das dies Risiken birgt ist mir bewusst, weswegen ich mal grob alle Zahlen vom Integer überflogen bin und überprüft habe ob keine Fehler auftreten. Es sind zum Glück keine Fehler aufgetreten. Und nein ich manipuliere nicht das Carry-Flag, ich benutze es nur. Folgendes Beispiel:

    Quellcode

    1. SHR eax, 1
    2. JNC sprungbedinngung
    anstatt

    Quellcode

    1. PUSH ebx
    2. MOV ebx, eax
    3. SHR eax, 1
    4. AND ebx, 00000001h
    5. CMP ebx, 00000000h
    6. POP ebx
    7. JE sprungbedinngung

    Welches die gleiche Wirkung, größere Laufzeiten, mehr Speicherbedarf und weniger Kürze hat. Ich optimiere dort wo der Compiler nicht optimieren kann. Und wenn ich mal 4 festgelegte Register benutze ist das nicht schlimm. Notfalls läd der Compiler die 4 Register auf den Stack und holt sie sich später dann wieder. Das ist kein großer Akt, zudem es eh automatisch bei dem Aufruf der Funktion geschieht. Und keine Angst ich werde goto niemals in c++ benutzen. Wenn ich dann Assembler benutze, erstelle ich mir ein Flussdiagramm um den Überblick nicht zu verlieren. ;) Auch brauchst du nicht immer so hysterisch zu werden. Was für mich zählt ist das Ergebniss und das habe ich gründlich überprüft, dafür gibt es so einige Möglichkeiten.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von Chris987 ()

  • Hmm... kennt jemand noch eine variante mit long oder größerem? Oder geht das auch mit ostringstream?
    Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
    Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

    Willst du mit mir auf Discord Chatten/Quatschen?
    Meine Husi's Tutorial Reihe
  • Eine hilfreiche Funktion für long ist _i64toa_s aus der stdlib.h. Als radix gibt man 10 für das normale Dezimalsystem an. Größere Variablen als long sind dann schwerer zu benutzen, aber ich glaube kaum, dass du Zahlen bis 9 Trillionen brauchst. Dann empfiehlt es sich Variablen mit einem Exponenten wie double zu benutzen.

  • hmm... danke,
    ich habe meine Verschlüsselung schon fertig!
    Problem beim Entschlüsseln kann man max. ein Buchstabe entschlüsseln, da die Verschlüsselung so groß wird, dass das nicht mehr passt. Leider wäre das Problem nach spätestens einem Satz auch bei long der Fall. Ich hab schon versucht so ein Teil zu machen um Strings zu Addieren, nur irgendwo scheiterts. Wisst ihr wo der Fehler liegt?

    Quellcode

    1. string string_plus(string number1, string number2){
    2. int im_sinn,length;
    3. string erg,teil,numb;
    4. if (number1.length() > number2.length()){
    5. numb = number1;
    6. length = number2.length();
    7. }
    8. else{
    9. numb = number2;
    10. length = number1.length();
    11. }
    12. int i;
    13. for(i = 0;i < length-1; i++){
    14. teil = c_in_string(c_in_int(number1.at(i))+c_in_int(number2.at(i))+im_sinn);
    15. im_sinn = in_int(string_copy(teil,0,teil.length()-2)); // -2 ist richtig
    16. teil = in_string(in_int(teil)-im_sinn);
    17. erg = teil+erg;
    18. }
    19. for(i = i;i < numb.length()-1; i++){
    20. teil = c_in_string(c_in_int(numb.at(i))+im_sinn);
    21. im_sinn = 0;
    22. erg = teil+erg;
    23. }
    24. return erg;
    25. }
    Alles anzeigen

    c_in_string
    ist ein char in string umwandeln
    Es wird 0 ausgegeben, wenn z.B. ich 10 und 10 eingebe und sonst auch, wenn ich was anderes eingebe
    Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
    Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

    Willst du mit mir auf Discord Chatten/Quatschen?
    Meine Husi's Tutorial Reihe
  • Chris987 schrieb:

    Langsam wird es albern und ich frage mich ob du das extra überliest. Es ist eine Funktion aus einer String Klasse, welche einen eigenen Speicheralgorithmus hat.


    Aha. Du hast also entweder "wchar_t *wc_data = new wchar_t[ui_len+1];" überladen oder machst in deiner "eigenen Speicherverwaltung" dennoch irgendwas dynamisches obwohl hier selbst ein statisches array ausreichen würde?

    Chris987 schrieb:

    Beim Speicherzugriff war es zugegeben eine sehr grobe Berechnung. Deswegen nochmal die genaue: Ein Takt dauert bei mir 1/(4GHz) = 1/(4*109Hz) = 0,25*10-9s lang. Nun benötigt ein Speicherzugriff 8 Takte, das heißt es sind insgesamt 2*10-9 Sekunden pro Speicherzugriff. Eine Nanosekunde entspricht nun 10-9 Sekunden, was dann wiederum einer Zeit von 2ns enstpricht. Das ist trotzdem noch immer sehr schnell. Im Vergleich benötigt dann ein Registerzugriff nur 2 Takte und im L2 etc. Speicher 4 Takte.


    Au weia...hast du mal die Datenrate deines Bus ins Spiel gebracht? Oder so Dinge wie Cache Miss und noch schlimmer, Page Miss? Da kommen *deutlich* mehr Zyklen auf dich zu. Aber hey, ich mein ja nur. Hinzu kommt, dass RAM Zugriff nicht nur von den Clockcycles deiner CPU abhängig ist, sondern auch von deinem RAM. Heutzutage sind die üblichen RAS times ca. 30ns, und da ist die row precharge time nichtmal drin eingerechnet. DANN kommen noch deine CPU cycles hinzu. Gut, nehmen wir mal worst case Szenario. Erst ein L1 und dann ein L2 Cache Miss. Das sind dann nochmal 40 cycles für L1 und ca. 600 für L2. Dann kommt eigentlich noch der Page Miss, aber die ganzen Syscalls würden so endlos viele cycles verbrennen, das wäre nicht mehr feierlich. Wären wir also nur mit Cache Miss bei 8 + 40 + 600 = 648 cycles = 192ns. Plus die RAS time, sind wir bei 222ns. Gratuliere...stark anders als 2ns, hm?

    Und das mit dem Register Allocator scheint nicht anzukommen. Du optimierst dich hier zu Tode an 3 Registern...pfeifst dann aber auf das pushen der Register auf den Stack das nötig ist weil du manuelle Register vorgibst.

    Weiterhin noch folgendes: du wolltest ja nichtmal log10 benutzen weil du von nichts abhängig sein wolltest, machst dich dann aber von speziellen Registern abhängig, ohne zu wissen ob diese vom Compiler oder System gebraucht werden (je nach calling convention darfst du z.B: das ECX Register bloß nicht anpacken oder du landest im Nirvana). Wenn du dann noch EBX benutzt, forcierst du den Compiler im prolog UND epilog deiner Funktion, noch spezielles Stack-foo anzurichten. Aber eeeey...wir haben den Code mit 2 Zeilen inline assembly "optimiert" m(

    Chris987 schrieb:

    erstelle ich mir ein Flussdiagramm um den Überblick nicht zu verlieren. ;)
    Wenn das für dich kein Signal für Code Smell ist dann weiß ich auch nicht mehr.

    Chris987 schrieb:

    Auch brauchst du nicht immer so hysterisch zu werden.

    Doch, brauche ich. Wenn jemand Optimierungen macht die schmarn sind und sie dann auch noch ohne das detaillierte Hintergrundwissen mit Pseudoargumenten "begründet"....dann verweise ich auf meinen Avatar.

  • Hmm... ich möchte dazu kein code posten, da ich lange dafür gebraucjt habe. Vielleicht kann mich jemand auf pn anschreiben, der sich von euch gut auskennt?
    Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
    Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

    Willst du mit mir auf Discord Chatten/Quatschen?
    Meine Husi's Tutorial Reihe