mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ItoA mit Uint64_t


Autor: Benjamin S. (benjamin_s316)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin Moin

Ich versuche die Wandlung einer 64Bit unsigned int in ASCII.

Folgende Funktion liefert leider falsche Werte

snr=0;
ItoA(snr,teststring);
draw_string_8x16_normal(10,210,teststring);

-> Ausgabe zeigt 125729


void ItoA( uint64_t z, char* Buffer )
{
    int i = 0;
    int j;
    char tmp;
    uint64_t u;    // In u bearbeiten wir den Absolutbetrag von z.

    // ist die Zahl negativ?
    // gleich mal ein - hinterlassen und die Zahl positiv machen
    // die einzelnen Stellen der Zahl berechnen
    do
        {
            Buffer[i++] = '0' + u % 10;
            u /= 10;
        }
    while( u > 0 );

    // den String in sich spiegeln
    for( j = 0; j < i / 2; ++j )
        {
            tmp = Buffer[j];
            Buffer[j] = Buffer[i-j-1];
            Buffer[i-j-1] = tmp;
        }
    Buffer[i] = '\0';
}

Autor: Kaj (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Benjamin S. schrieb:
> uint64_t u;

Benjamin S. schrieb:
> do
>         {
>             Buffer[i++] = '0' + u % 10;
>             u /= 10;
>         }
>     while( u > 0 );

u ist nicht initialisiert, damit erhälst du logischer weise schrott.

Autor: Hannes J. (pnuebergang)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Von der großartig im Kommentar angekündigten Behandlung negativer Zahlen 
ist auch nichts zu sehen. Auf 
http://hauptschule-bochum.de/wordpress/?incsub_wiki=testwiki findet man 
vermutlich das Original der Funktion.

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hannes J. schrieb:
> Von der großartig im Kommentar angekündigten Behandlung negativer Zahlen
> ist auch nichts zu sehen.

Hätte mich auch gewundert wenn ein Unsinged Integer negativ Vorbehaftet 
ist. ;-)

Autor: Kaj (Gast)
Datum:

Bewertung
-3 lesenswert
nicht lesenswert
Wenn du den String so spiegelst
// den String in sich spiegeln
Buffer[i--] = '\0';
for( j = 0; j < i ; j++, i-- ) {
    Buffer[j] ^= Buffer[i];
    Buffer[i] ^= Buffer[j];
    Buffer[j] ^= Buffer[i];
}
sparst du dir die extra tmp variable. Das ist aber geschmackssache.

Autor: Ralph S. (jjflash)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
... schließe mich den Vorrednern komplett an (die schlicht eben 
schneller waren als ich während ich den Code angesehen und modifiziert 
hab).

Irgendwie ... bin ich wohl definitiv zu langsam !

Autor: Mikro 7. (mikro77)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ralph S. schrieb:
>...während ich den Code angesehen und modifiziert hab...

Fast korrekt. Hat noch mit (int64_t) 0x8000000000000000 Probleme.

Für den kleinsten (negativen) Integer gibt es kein positives Pendant.

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eigentlich war doch uint64_t gefragt und nicht int64_t.

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Eigentlich war doch uint64_t gefragt und nicht int64_t.

Eben. Daher sollte man die Funktion auch UtoA() nennen.

Autor: Dr. Sommer (Gast)
Datum:

Bewertung
-3 lesenswert
nicht lesenswert
Warum selber machen, wenn die Standard Library das schon kann... Ok, ist 
für kleine Mikrocontroller nicht geeignet:
#include <sstream>
#include <cstdint>
#include <string>
#include <iostream>

int main () {
  uint64_t i = 0x1122334455667788;
  std::stringstream ss;
  ss << i;
  std::string res = ss.str ();
  std::cout << res;
}

Autor: Jens G. (jensg)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Mikro 7. schrieb:
> Ralph S. schrieb:
>>...während ich den Code angesehen und modifiziert hab...
>
> Fast korrekt. Hat noch mit (int64_t) 0x8000000000000000 Probleme.
>
> Für den kleinsten (negativen) Integer gibt es kein positives Pendant.
Ich habe zum Thema vorhandene Software erweitert und angepasst -- 
funktioniert prima beim Arduino.

Quelle: https://github.com/amdn/itoa_ljust
von mir: 
https://github.com/JensGrabner/snc98_Slash-Number-...

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dr. Sommer schrieb:
> Warum selber machen, wenn die Standard Library das schon kann... Ok, ist
> für kleine Mikrocontroller nicht geeignet:
>
>
#include <sstream>
> #include <cstdint>
> #include <string>
> #include <iostream>
> 
> int main () {
>   uint64_t i = 0x1122334455667788;
>   std::stringstream ss;
>   ss << i;
>   std::string res = ss.str ();
>   std::cout << res;
> }

(Noch) einfacher geht es mit std::to_string(i) ...

Aber C++ war ja nicht gefragt ;-)

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Jens G. schrieb:
> Mikro 7. schrieb:
>> Ralph S. schrieb:
>>>...während ich den Code angesehen und modifiziert hab...
>>
>> Fast korrekt. Hat noch mit (int64_t) 0x8000000000000000 Probleme.
>>
>> Für den kleinsten (negativen) Integer gibt es kein positives Pendant.
> Ich habe zum Thema vorhandene Software erweitert und angepasst --
> funktioniert prima beim Arduino.
>
> Quelle: https://github.com/amdn/itoa_ljust
> von mir:
> 
https://github.com/JensGrabner/snc98_Slash-Number-...

Sorry, ich kann einfach nicht nachvollziehen, dass man das in C++ mit 
C-Arrays macht, deren (hoffentlich ausreichende) Größe einer Annahme 
unterliegt, die der Compiler ja nicht prüfen kann!

Autor: Jens G. (jensg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Jens G. schrieb:
> Sorry, ich kann einfach nicht nachvollziehen, dass man das in C++ mit
> C-Arrays macht, deren (hoffentlich ausreichende) Größe einer Annahme
> unterliegt, die der Compiler ja nicht prüfen kann!

Ich verstehe die Nachfrage nicht. Der Quelltext ist getestet und 
funktioniert. .. ist bei Arduino etwa doppelt so schnell wie itoa(); 
ltoa(); .. und geht mit allen Datentypen von 8_bit bis 64_bit, mit und 
ohne Vorzeichen.

Bei VisualStudio gibt es Warnungen, da mehrmals Typumwandlungen 
angenommen werden. Es ist alles mit Bedacht verwendet worden. Dieser 
Test: https://github.com/miloyip/itoa-benchmark lief fehlerfrei bei mir 
durch.

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Jens G. schrieb:
> Wilhelm M. schrieb:
>> Jens G. schrieb:
>> Sorry, ich kann einfach nicht nachvollziehen, dass man das in C++ mit
>> C-Arrays macht, deren (hoffentlich ausreichende) Größe einer Annahme
>> unterliegt, die der Compiler ja nicht prüfen kann!
>
> Ich verstehe die Nachfrage nicht. Der Quelltext ist getestet und
> funktioniert. .. ist bei Arduino etwa doppelt so schnell wie itoa();
> ltoa(); .. und geht mit allen Datentypen von 8_bit bis 64_bit, mit und
> ohne Vorzeichen.

Der Compiler wirds compilieren:
uint64_t x = 42;
char buffer[2];
itoa(x, 42);

Aber was passiert?

Autor: Jens G. (jensg)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Der Compiler wirds compilieren:
>
>
> uint64_t x = 42;
> char buffer[2];
> itoa(x, 42);
> 
>
> Aber was passiert?
Das Programm wird fehlerhaft ausgeführt werden, da zur Laufzeit nicht 
überprüft wird, wo in den Buffer geschrieben wird. Der Programmierer 
steht in der Verantwortung den Buffer entsprechend der zu erwartenden 
Zahlen zu wählen.  .. bei Pascal war alles noch anders - da gab es eine 
Typprüfung. Heute darf der Programmierer selbst darauf achten was ER 
tut.

: Bearbeitet durch User
Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Jens G. schrieb:
> Wilhelm M. schrieb:
>> Der Compiler wirds compilieren:
>>
>>
>> uint64_t x = 42;
>> char buffer[2];
>> itoa(x, 42);
>> 
>>
>> Aber was passiert?
> Das Programm wird fehlerhaft ausgeführt werden, da zur Laufzeit nicht
> überprüft wird, wo in den Buffer geschrieben wird.

Genau. Und das kann man bei C++ ja ganz elegant verhindern! Sowas macht 
man meinetwegen in C, aber nicht in C++!

Autor: Jens G. (jensg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Genau. Und das kann man bei C++ ja ganz elegant verhindern! Sowas macht
> man meinetwegen in C, aber nicht in C++!
Na dann freue ich mich auf die Verbesserungen meines Quelltextes. In C++ 
bin ich noch Anfänger, lerne gerne auch von anderen Profis. Ich habe den 
vorliegenden Quelltext einfach etwas erweitert und von Fehlern 
(Portierbarkeit) beseitigt. Hoffenlich funktioniert .. nach der 
Veränderung .. der Quelltext noch beim Arduino.

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jens G. schrieb:
> Wilhelm M. schrieb:
>> Genau. Und das kann man bei C++ ja ganz elegant verhindern! Sowas macht
>> man meinetwegen in C, aber nicht in C++!
> Na dann freue ich mich auf die Verbesserungen meines Quelltextes. In C++
> bin ich noch Anfänger, lerne gerne auch von anderen Profis.

Ok, habe ich mir gedacht.
Nun, dann schnapp Dir ein paar gute Bücher (Breymann, alle von Scott 
Meyers sowie von Herb Sutter und Josuttis, oder schau auf Youtube die 
Serie von Jason Turner) und los geht's. Aber auf dieser Stufe solltest 
Du nicht stehen bleiben, wenn Du wirklich C++ machen möchtest und nicht 
nur C-Code mit einem C++-Compiler übersetzen.

: Bearbeitet durch User
Autor: Jens G. (jensg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Aber auf dieser Stufe solltest Du nicht stehen bleiben,
> wenn Du wirklich C++ machen möchtest und nicht
> nur C-Code mit einem C++-Compiler übersetzen.

Ich denke Du meinst man sollte anstelle von "array of char" lieber den 
Typ String verwenden und bei 8-bit µC kann dann nur dies zur Anwendung 
kommen: http://www.etlcpp.com/string.html

Ist das gemeint -- lieber "String" anstelle von "array of char" ?

Autor: Wolfgang (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jens G. schrieb:
> Der Programmierer steht in der Verantwortung den Buffer entsprechend
> der zu erwartenden Zahlen zu wählen.
Bei integer Datentypen bekannter Größe ist die maximale Größe der 
möglichen Zahlen und damit auch die maximale Größe des erforderlichen 
Zeichen-Arrays doch wohl nicht ganz unberechenbar. Was erwartest du da 
für Unwägbarkeiten, die der Programmierer entscheiden muss?

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jens G. schrieb:
> Wilhelm M. schrieb:
>> Aber auf dieser Stufe solltest Du nicht stehen bleiben,
>> wenn Du wirklich C++ machen möchtest und nicht
>> nur C-Code mit einem C++-Compiler übersetzen.
>
> Ich denke Du meinst man sollte anstelle von "array of char" lieber den
> Typ String verwenden und bei 8-bit µC kann dann nur dies zur Anwendung
> kommen: http://www.etlcpp.com/string.html

Nicht notwendigerweise. Der wichtige Punkt ist: wird die Schnittstelle 
von
itoa() falsch benutzt, d.h. hier: verwendet der Anwender einen zu 
kleinen
Buffer / Container als Output-Parameter für den zu wandelnden 
Ganzzahltyp, dann darf das nicht kompilieren(!).

Da kann man sicher etl::string<> nehmen, aber auch std::array<> (oder 
auch char[N]) oder stringview<> oder eigene Container Realisierungen. 
Daran erkennt man, dass der Typ des Containers eigentlich egal ist unter 
der Voraussetzung, das der Elementtyp und die Größe passt. Also ein 
generischer Algorithmus.

Das führt dazu, dass man itoa() als template schreiben kann. Das 
template
leitet die Größe des Containers ab und compiliert nicht, wenn die zu 
klein / nicht passend ist im Vergleich zur Ganzzahl.

> Ist das gemeint -- lieber "String" anstelle von "array of char" ?

s.o. ... nein.

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Nicht notwendigerweise. Der wichtige Punkt ist: wird die Schnittstelle
> von itoa() falsch benutzt, d.h. hier: verwendet der Anwender einen zu
> kleinen Buffer / Container als Output-Parameter für den zu wandelnden
> Ganzzahltyp, dann darf das nicht kompilieren(!).

Nicht "zu klein für den Typ", sondern "zu klein für den Wertebereich". 
Wenn  ich einen Wert im Bereich 0 bis 80000 in einen String wandeln 
will, brauche ich nicht einen 12 Bytes großen Puffer dafür, nur weil der 
Wert in einer 32-Bit-Variable gespeichert sein muss. Es reicht auch ein 
halb so großer Puffer. Dass man diesen Wertebereich nicht verlässt, muss 
man dann natürlich sicherstellen.

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Wilhelm M. schrieb:
>> Nicht notwendigerweise. Der wichtige Punkt ist: wird die Schnittstelle
>> von itoa() falsch benutzt, d.h. hier: verwendet der Anwender einen zu
>> kleinen Buffer / Container als Output-Parameter für den zu wandelnden
>> Ganzzahltyp, dann darf das nicht kompilieren(!).
>
> Nicht "zu klein für den Typ", sondern "zu klein für den Wertebereich".
> Wenn  ich einen Wert im Bereich 0 bis 80000 in einen String wandeln
> will, brauche ich nicht einen 12 Bytes großen Puffer dafür, nur weil der
> Wert in einer 32-Bit-Variable gespeichert sein muss. Es reicht auch ein
> halb so großer Puffer. Dass man diesen Wertebereich nicht verlässt, muss
> man dann natürlich sicherstellen.

Ein klares Nein. Eine Funktion, die einen domänen-unspezifischen Typ wie 
etwa uint32_t in irgendwas wandeln soll, MUSS davon ausgehen, das der 
Wertebereich ausgenutzt wird. Bei solchen Datentypen gibt es keine 
"ungültigen" Werte aus Sicht der verarbeitenden Funktion.

Man kann das aber natürlich mit spezielleren Typ als die primitiven 
machen: etwa in der Art uint_bounded<uint32_t, 999>. Dafür reichen dann 
bei itoa() char-Container der Länge 3. Das kostet auch gar keine 
Laufzeit - das ist ja gerade die Stärke von C++, dass man 
domänen-spezifische DT "kostenneutral" bilden kann. Damit bildet man 
möglichst viel Semantik in den Typen ab, was der Compiler zur 
Compile-Zeit prüfen kann. Zusicherungen zur Laufzeit sind immer die 
zweite Wahl.

Natürlich ist uint_bounded<> auch noch ein unspezifischer DT. Bspw. für 
Kalendermonate sollte man dann etwas wie Date::Month haben, statt int.

Man kann natürlich eine entsprechende Funktion wie itoa() schreiben, der 
man beliebige, auch zur kurze Container übergibt. Dann muss man zur 
Laufzeit prüfen und ggf. abschneiden. Die würde ich dann aber anders 
nennen. Aber wichtig ist eben, das itoa_xxx() das prüfen kann. Und das 
kann sie als
void itoa_xxx(uint32_t, char*)
nicht, aber als
template<uint8_t L>
void itoa_xxx<uint32_t, array<char, L>&);
schon.

Autor: Jens G. (jensg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ungeachtet aller "Formfehler" bezüglich der Nutzung von C++, so sollte 
das Stück Software auch zuverlässig funktionieren. Das hat es leider 
nicht. Ich habe Fehler bereinigt und noch etwas Zeitoptimierung gemacht.
 Test: 900x itoa_() at 12_MHz on ATMEGA_1284p
 =========================
 0 -                    1 -
 1 -                   10 -
 2 -                  100 -
 3 -                 1000 -  48 ms (  53 µs )
 4 -                10000 -  51 ms (  57 µs )
 5 -               100000 -  81 ms (  90 µs )
 6 -              1000000 - 102 ms ( 113 µs )
 7 -             10000000 - 152 ms ( 169 µs )
 8 -            100000000 - 152 ms ( 169 µs )
 9 -           1000000000 - 201 ms ( 223 µs )
10 -          10000000000 - 249 ms ( 277 µs )
11 -         100000000000 - 275 ms ( 306 µs )
12 -        1000000000000 - 294 ms ( 327 µs )
13 -       10000000000000 - 300 ms ( 333 µs )
14 -      100000000000000 - 337 ms ( 374 µs )
15 -     1000000000000000 - 368 ms ( 409 µs )
16 -    10000000000000000 - 419 ms ( 466 µs )
17 -   100000000000000000 - 435 ms ( 483 µs )
18 -  1000000000000000000 - 485 ms ( 539 µs )
19 - 10000000000000000000 - 544 ms ( 604 µs )

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habs auch mal auf einem ATMega1284p-Testboard (20Mhz) laufen lassen:
0 : V : 0,0ms
1 : V : 1,2ms
2 : V : 10,2ms
3 : V : 100,6ms
4 : V : 1000,19ms
5 : V : 10000,29ms
6 : V : 100000,50ms
7 : V : 1000000,79ms
8 : V : 10000000,81ms
9 : V : 100000000,109ms
10 : V : 1000000000,109ms
11 : V : 10000000000,154ms
12 : V : 100000000000,159ms
13 : V : 1000000000000,190ms
14 : V : 10000000000000,198ms
15 : V : 100000000000000,237ms
16 : V : 1000000000000000,266ms
17 : V : 10000000000000000,268ms
18 : V : 100000000000000000,318ms
19 : V : 1000000000000000000,319ms

Allerdings sind die Routinen nicht für jedermann geeignet, das sie wegen 
der LookUp-Tabelle 200 Byte RAM zusätzlich verbrauchen.

Eine primitiv-Variante erreicht:
0 : V : 0,0ms
1 : V : 1,10ms
2 : V : 10,17ms
3 : V : 100,24ms
4 : V : 1000,51ms
5 : V : 10000,63ms
6 : V : 100000,189ms
7 : V : 1000000,219ms
8 : V : 10000000,251ms
9 : V : 100000000,281ms
10 : V : 1000000000,313ms
11 : V : 10000000000,822ms
12 : V : 100000000000,951ms
13 : V : 1000000000000,1083ms
14 : V : 10000000000000,1214ms
15 : V : 100000000000000,1363ms
16 : V : 1000000000000000,1515ms
17 : V : 10000000000000000,1688ms
18 : V : 100000000000000000,1859ms
19 : V : 1000000000000000000,2050ms

ohne zusätzlichen RAM Verbrauch durch Lookup-Tabelle.

Space <-> Speed-Tradeoff

: Bearbeitet durch User
Autor: Jens G. (jensg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Allerdings sind die Routinen nicht für jedermann geeignet, das sie wegen
> der LookUp-Tabelle 200 Byte RAM zusätzlich verbrauchen.
>
Macht es Sinn die LookUp-Tabelle im Pgm-Space zu halten?

Autor: Jens G. (jensg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Meine Testroutine habe ich mal hier veröffentlicht: 
https://github.com/JensGrabner/snc98_Slash-Number-...

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe meine Lösung nochmal umgebaut. Es ist nun einen generische 
Variante, die für alle Basen (2 ... 16) wandeln kann und eine 
Lookup-Tabelle verwendet (Space-Speed-Tradeoff).

Das sind die Zahlen (at328p@12MHz):
O:0 : V : ,0,0,0ms
O:1 : V : ,1,1,2ms
O:2 : V : ,1,10,4ms
O:3 : V : ,1,100,11ms
O:4 : V : ,2,1000,21ms
O:5 : V : ,2,10000,37ms
O:6 : V : ,3,100000,102ms
O:7 : V : ,3,1000000,147ms
O:8 : V : ,3,10000000,150ms
O:9 : V : ,3,100000000,195ms
O:10 : V : ,3,1000000000,198ms
O:11 : V : ,4,10000000000,258ms
O:12 : V : ,4,100000000000,304ms
O:13 : V : ,4,1000000000000,325ms
O:14 : V : ,4,10000000000000,365ms
O:15 : V : ,4,100000000000000,382ms
O:16 : V : ,4,1000000000000000,431ms
O:17 : V : ,4,10000000000000000,434ms
O:18 : V : ,4,100000000000000000,498ms
O:19 : V : ,4,1000000000000000000,500ms

Es ist eine vollständig reguläre Lösung für alle Datentypen (uint8_t ... 
uint64_t sowie signed) mit Längenbestimmung über binäre Auswahl, die mit 
templates realisiert ist.

Autor: Jens G. (jensg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Habe meine Lösung nochmal umgebaut. Es ist nun einen generische
> Variante, die für alle Basen (2 ... 16) wandeln kann und eine
> Lookup-Tabelle verwendet (Space-Speed-Tradeoff).
>
> Es ist eine vollständig reguläre Lösung für alle Datentypen (uint8_t ...
> uint64_t sowie signed) mit Längenbestimmung über binäre Auswahl, die mit
> templates realisiert ist.
>
Der Quelltext zu bekommen, währe nicht schlecht ;-) .

: Bearbeitet durch User
Beitrag #5007148 wurde vom Autor gelöscht.
Autor: Wilhelm M. (wimalopaan)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Jens G. schrieb:
> Wilhelm M. schrieb:
>> Habe meine Lösung nochmal umgebaut. Es ist nun einen generische
>> Variante, die für alle Basen (2 ... 16) wandeln kann und eine
>> Lookup-Tabelle verwendet (Space-Speed-Tradeoff).
>>
>> Es ist eine vollständig reguläre Lösung für alle Datentypen (uint8_t ...
>> uint64_t sowie signed) mit Längenbestimmung über binäre Auswahl, die mit
>> templates realisiert ist.
>>
> Der Quelltext zu bekommen, währe nicht schlecht ;-) .

Hier der erste Wurf (s.a. Anhang):

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jens G. schrieb:
> Wilhelm M. schrieb:
>> Habe meine Lösung nochmal umgebaut. Es ist nun einen generische
>> Variante, die für alle Basen (2 ... 16) wandeln kann und eine
>> Lookup-Tabelle verwendet (Space-Speed-Tradeoff).
>>
>> Es ist eine vollständig reguläre Lösung für alle Datentypen (uint8_t ...
>> uint64_t sowie signed) mit Längenbestimmung über binäre Auswahl, die mit
>> templates realisiert ist.
>>
> Der Quelltext zu bekommen, währe nicht schlecht ;-) .

Bei Deinem Code solltest Du unbedingt noch für die switch-cases ein 
fallthrough attribute ergänzen. Ansonsten bekommt einen Haufen von 
Warnungen ...

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Beim der Menge von Warnungen ist mir das in Deinem Code auch nicht 
aufgefallen: es gibt Funktionen, die haben ein switch-case mit 
fallthrough und ohne default. In diesem Fall gibt es die Warnung, dass 
ein return für diese non-void Funktion fehlt. Zwar kann der Fall (im 
Moment) in Deinem Code nicht vorkommen, doch das weiß ja der Compiler so 
nicht. Deswegen ein default-case einbauen mit einem assert(false) und 
auch ein return p; (falls das assert()-Macro eine noreturn-Funktion 
aufruft)

Autor: Jens G. (jensg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Beim der Menge von Warnungen ist mir das in Deinem Code auch nicht
> aufgefallen: es gibt Funktionen, die haben ein switch-case mit
> fallthrough und ohne default. In diesem Fall gibt es die Warnung, dass
> ein return für diese non-void Funktion fehlt.
danke für den Tip - default switch-case verwenden. Das hat den 
Maschinencode verringert und die Laufzeit etwas verbessert.
https://github.com/JensGrabner/snc98_Slash-Number-Calculator

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Lookup-Tabelle verwendet (Space-Speed-Tradeoff).
> Das sind die Zahlen (at328p@12MHz):
> O:19 : V : ,4,1000000000000000000,500ms

Irgendwas kann da doch nicht stimmen.  Bei 12MHz und 500ms wären das 
6.000.000 Cycles.  Eine Umwandlung nach ASCII Dezimal in in 1/1000 der 
Zeit machbar, und zwar ohne Splatz durch Lookup-Tabelle zu 
verschwenden.

: Bearbeitet durch User
Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Zeit gilt für 900 Konvertierungen (bitte lies weiter oben) wegen 
Vergleich zum Ausgangscode ...

: Bearbeitet durch User
Autor: Jens G. (jensg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Die Zeit gilt für 900 Konvertierungen (bitte lies weiter oben) wegen
> Vergleich zum Ausgangscode ...
in jede Dekade werden bei meinem Test 900 unterschiedliche Zahlen 
erzeugt. Ab der Zahl 100 ist es +1, ab 1000 ist es +10  ... das macht 17 
Dekaden bei dem vollen Zahlenumfang den ich teste  --  bei meiner 
Testroutine werden 15300 Zahlen erzeugt - so konnte ich Fehler finden.

: Bearbeitet durch User
Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch eine interessante Beobachtung
(für uint32_t, uint64_t geht mit ltoa() ja nicht mehr):
   text    data     bss     dec     hex filename
    252       0      87     339     153 bm02a.elf
    374       0      87     461     1cd bm03a.elf
    828     202      87    1117     45d bm04a.elf

bm02a: meine template Variante (auch die schnellste)
bm03a: aus avr-libc
bm04a: von jensg

(Bei den Beispielen oben ist jeweils noch eine Text-Ausgabe dabei):

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Noch eine interessante Beobachtung
> (für uint32_t, uint64_t geht mit ltoa() ja nicht mehr):
>
>
>    text    data     bss     dec     hex filename
>     252       0      87     339     153 bm02a.elf
>     374       0      87     461     1cd bm03a.elf
> 
>
> bm02a: meine template Variante (auch die schnellste)
> bm03a: aus avr-libc

Lass einfach mal "constexpr uint8_t Base = 10;" weg und übergib Base als 
Parameter, das mach den Vergleich mit der avr-libc etwas realistischer.

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann L. schrieb:
> Wilhelm M. schrieb:
>> Noch eine interessante Beobachtung
>> (für uint32_t, uint64_t geht mit ltoa() ja nicht mehr):
>>
>>
>>    text    data     bss     dec     hex filename
>>     252       0      87     339     153 bm02a.elf
>>     374       0      87     461     1cd bm03a.elf
>> 
>>
>> bm02a: meine template Variante (auch die schnellste)
>> bm03a: aus avr-libc
>
> Lass einfach mal "constexpr uint8_t Base = 10;" weg und übergib Base als
> Parameter, das mach den Vergleich mit der avr-libc etwas realistischer.

Schau Dir den Code noch mal genauer an!

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Schau Dir den Code noch mal genauer an!

Unw was soll mir da auffallen?

Autor: Jens G. (jensg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Wilhelm M. .. Arduino kennt nur eine Teilmenge von C++. Womit 
programmierst Du? Damit ich einen Weg zu Arduino finde, deinen Quelltext 
zu testen.

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jens G. schrieb:
> Hallo Wilhelm M. .. Arduino kennt nur eine Teilmenge von C++. Womit
> programmierst Du? Damit ich einen Weg zu Arduino finde, deinen Quelltext
> zu testen.

Mit Arduino hat das ganze nichts zu tun ...

Du brauchst einen g++ mit variadic-templates und fold-expressions (ab 
Version 6) und concepts-lite (glaube ab Version 6.3.1 vorhanden, 
Schalter -fconcepts nicht vergessen) und einiges von C++17, was erst mit 
g++ >= 7.0 dabei ist, v.a. constexpr-lambda-expressions sowie 
Selektionen mit initializern, inline-static Variablen, constexpr-if und 
wahrscheinlich noch ein paar mehr Sachen aus c++17, die ich mir so 
angewöhnt habe (ich denke, structured bindings könnten auch dabei sein 
sowie variablen-templates).

Autor: Jens G. (jensg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wird dein Stück Software auf Atmel AVR 8-bit lauffähig sein? C++17 ist 
um einiges entfernt von C++11 der auf Atmel portiert wurde.

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jens G. schrieb:
> Wird dein Stück Software auf Atmel AVR 8-bit lauffähig sein? C++17 ist
> um einiges entfernt von C++11 der auf Atmel portiert wurde.

Es IST auf AVR-8Bit lauffähig - und läuft. Sonst hätte ich Dir kaum die 
Zeiten und Code-Größen sagen können ... ;-)

Wie das mit ATmel-Studio oder Arduino-IDE geht, kann ich Dir allerdings 
nicht sagen. Als IDE bzw. Editor nehme ich QtCreator und den Rest 
erledigen ein paar Makefiles.

Autor: Jens G. (jensg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Jens G. schrieb:
>> Wird dein Stück Software auf Atmel AVR 8-bit lauffähig sein? C++17 ist
>> um einiges entfernt von C++11 der auf Atmel portiert wurde.
>
> Es IST auf AVR-8Bit lauffähig - und läuft. Sonst hätte ich Dir kaum die
> Zeiten und Code-Größen sagen können ... ;-)
>
Sorry, wollte Deine qualitativ hochwertige Arbeit nich schmälern. Ich 
selbst kann Deine Arbeit nicht bewerten, da ich in meinem 
Open-Source-Projekt Lösungen brauche die einfach auf der 
Arduino-Plattform zum laufen zu bringen sind. Wie das technisch auf 
Arduino geht -- da bin ich fachlich überfordert und werde deinen Ansatz 
nicht weiter verfolgen (können). Schade....

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jens G. schrieb:
> Wilhelm M. schrieb:
>> Jens G. schrieb:
>>> Wird dein Stück Software auf Atmel AVR 8-bit lauffähig sein? C++17 ist
>>> um einiges entfernt von C++11 der auf Atmel portiert wurde.
>>
>> Es IST auf AVR-8Bit lauffähig - und läuft. Sonst hätte ich Dir kaum die
>> Zeiten und Code-Größen sagen können ... ;-)
>>
> Sorry, wollte Deine qualitativ hochwertige Arbeit nich schmälern. Ich
> selbst kann Deine Arbeit nicht bewerten, da ich in meinem
> Open-Source-Projekt Lösungen brauche die einfach auf der
> Arduino-Plattform zum laufen zu bringen sind. Wie das technisch auf
> Arduino geht -- da bin ich fachlich überfordert und werde deinen Ansatz
> nicht weiter verfolgen (können).

Du brauchst doch einfach nur eine neuere Version des avr-g++ zu 
installieren. Das ist alles. Es ist ja alles abwärtskompatibel bis zu 
C++98. Das Compilieren eines avr-gcc besteht doch nur aus

configure ...
make
make install

Und dann musst Du Deiner IDE nur sagen, dass sie einen anderen Compiler 
benutzen soll ...

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Und dann musst Du Deiner IDE nur sagen, dass sie einen anderen Compiler
> benutzen soll ...

Tja, und genau das ist die Frage, ob das bei Arduino so einfach geht. 
Konfigurierbar ist da herzlich wenig. Ich hatte auch schon mehrfach 
vergeblich versucht, lediglich ein paar Warning-Levels hochzuschrauben, 
weil sonst noch nichtmals unbenutzte Variablen angemeckert werden.

Bei manchen Dingen kann so ein Wohlfühlkissen furchtbar starr werden.

: Bearbeitet durch Moderator
Autor: Jens G. (jensg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frank M. schrieb:
> Wilhelm M. schrieb:
>> Und dann musst Du Deiner IDE nur sagen, dass sie einen anderen Compiler
>> benutzen soll ...
>
> Tja, und genau das ist die Frage, ob das bei Arduino so einfach geht.
> Konfigurierbar ist da herzlich wenig.
Da ich ein Open-Source-Projekt für Arduino betreibe, bin ich darauf 
angewiesen, alles so zu machen, das es bei Arduino geht. Was ein Vorteil 
für den einen (Anfänger) ist, ist ein Nachteil für den anderen (Profi). 
Arduino verwendet aktuell: avr-gcc=4.9.2-atmel3.5.4-arduino2.

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jens G. schrieb:
> Frank M. schrieb:
>> Wilhelm M. schrieb:
>>> Und dann musst Du Deiner IDE nur sagen, dass sie einen anderen Compiler
>>> benutzen soll ...
>>
>> Tja, und genau das ist die Frage, ob das bei Arduino so einfach geht.
>> Konfigurierbar ist da herzlich wenig.
> Da ich ein Open-Source-Projekt für Arduino betreibe, bin ich darauf
> angewiesen, alles so zu machen, das es bei Arduino geht. Was ein Vorteil
> für den einen (Anfänger) ist, ist ein Nachteil für den anderen (Profi).
> Arduino verwendet aktuell: avr-gcc=4.9.2-atmel3.5.4-arduino2.

Oh je: Version 4.9.2 ist aber wirklich alt (vor Juni 2015).

Gerade bei C++ hat sich ja in dieser Zeit SEHR viel geändert, vor allem 
in Bezug auf templates und constexpr, was man für µC sehr gut gebrauchen 
kann. Und es wird sich in Zukunft ja weiterhin viel ändern!

Da kann ich nur dringend empfehlen, mal zu schauen, ob man dass nicht 
ändern kann.

Autor: Jens G. (jensg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ist schon etwas länger her  --  jetzt gibt es auch ein Format int96_a 
der auf 8bit Atmel rechnen kann  ...  und das "itoA" von mir kann es 
auch nach ASCII umwandeln.

Infos zum int96_a gibt es hier:
#include <int96.h>
// Original:  http://www.naughter.com/int96.html
// 
https://github.com/JensGrabner/snc98_Slash-Number-...

#include <itoa_ljust.h>
// 
https://github.com/JensGrabner/snc98_Slash-Number-...

Ein Testprogramm findet man hier:
https://github.com/JensGrabner/snc98_Slash-Number-...

Es sind damit Rechungen bis zu 28 Dezimalstellen möglich.

: Bearbeitet durch User
Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe gerade einen ganz kurzen Blick da hinein geworfen. Sehe ich das 
richtig, dass Du den Code unverändert übernommen hast?

Autor: Jens G. (jensg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Habe gerade einen ganz kurzen Blick da hinein geworfen. Sehe ich das
> richtig, dass Du den Code unverändert übernommen hast?
Es kommt drauf an, auf was es sich bezieht - ja < Original: 
http://www.naughter.com/int96.html > habe ich weitgehend übernommen. Der 
Quallcode ist auf die .. #include <inttypes.h> Konvention angepasst.

Und .. #include <itoa_ljust.h> habe ich von 64bit auf 96bit erweitert. 
Es besteht noch Optimierungsbedarf - ab bit 65 wird es 10x langsamer.

: Bearbeitet durch User
Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jens G. schrieb:

> Und .. #include <itoa_ljust.h> habe ich von 64bit auf 96bit erweitert.
> Es besteht noch Optimierungsbedarf - ab bit 65 wird es 10x langsamer.

Ok, der Frage war einfach nur erst einmal reines Interesse.

Bezogen auf die Schnittstelle und auch Teile der Implementierung sehe 
ich auch noch Verbesserungsmöglichkeiten. Es ist teilweise nicht sehr 
idiomatisch und die Typumwandlungsoperation halte ich für problemtisch 
...

Autor: Jens G. (jensg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mein Quelltext ist verbessert worden. Die einzig große Division mit 
int96 habe ich durch eine Multiplikation ersetzt (* 1/x). Dazu habe ich 
eine neue Funktion erstellt (a * b) / 2^95.
void mul_div95(const int96_a& mul, int96_a& rVal) const;

https://github.com/JensGrabner/snc98_Slash-Number-...

Autor: Jens G. (jensg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe den Quelltext aktuallisiert. Es waren Fehler in der Umwandlung 
von int96_a drinn -- jetzt dauert es etwas länger in der Zeit (max. 1.3 
ms).

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.