Hallo,
ich habe diesen C-Code, und ich wollte mal fragen ob man diesen
vielleicht in einen einzeiligen oder einfacheren Code vereinfachen kann.
Natürlich in Anbetracht der Tatsache, dass es sinnvoll ist und nicht im
Assembler die vielfache Größe wird.
Wenn man die Zahlen 1...4 in die Zahlen 1,2,4,8 wandeln möchte, geht das
ja mit dem Schiebebefehl gut. Aber hier ist es die andere Richtung. Ich
habe keine bessere Lösung gefunden.
Armin K. schrieb:> vielleicht in einen einzeiligen oder einfacheren Code vereinfachen kann.
Warum?
Ist er schlecht verständlich? Nein.
Ist er zu langsam? Nein.
Belegt er Zuviel Speicher? Nein.
Wenn es nur die vier sind: Ist doch okay. Wenn es mehr sind: Du suchst
den Zweierlogarithmus, was wahrscheinlich letztendlich auf clz()
hinauslaufen wird.
Armin K. schrieb:> Wenn man die Zahlen 1...4 in die Zahlen 1,2,4,8 wandeln möchte, geht das> ja mit dem Schiebebefehl gut.
Mit zwei multiplizieren ist lesbarer und damit besser. Daraus folgt,
dass durch 2 teilen einge gute Option ist.
Ich würde hier auch nichts vereinfachen, falls nicht noch mehr Werte
benötigt werden. Falls doch, würde ich mit einer i=0..n Schleife auf
alle Bits testen und mir nur was anderes überlegen, wenn das zu langsam
ist.
"Leicht verständlich" ist immer wichtiger als "kurz" und fast immer
wichtiger als "schnell", außer es ist klar, dass genau an dieser Stelle
"schnell" relevant ist.
Armin K. schrieb:> Danke für die Hinweise.> Die Loockuptable gefällt mir gut, aber das macht es nicht wirklich> einfacher zu verstehen.
Du musst dir schon überlegen auf was du Optimieren willst: Auf gute
Lesbarkeit, auf Geschwindigkeit oder auf Codegröße.
Alles zusammen bekommst du leider nicht.
Armin K. schrieb:> Ich> habe keine bessere Lösung gefunden.
Hallo,
du kannst mit switch-case und mit if-else probieren und in *.lss
Assembler-Code ankucken. Du wirst wohl überrascht.
Armin K. schrieb:> Ich habe keine bessere Lösung gefunden.
Deutlich robuster könntest du den Algorithmus gestalten, indem auch bei
Zahlen außerhalb der Menge {1.2.4.8} einen definierten Wert als Output
lieferst.
Armin K. schrieb:> Ich habe keine bessere Lösung gefunden.
Diese Lösung ist für den Leser des Programms die beste Variante.
Sie ist klar verständlich und die Funktion ist auf den ersten Blick
klar.
Bei einer LUT muss man schon etwas länger nachdenken. Die wäre aber auf
jeden Fall die bessere Wahl, wenn es sich viele (ich sage mal mehr als
8) Werte handelt.
So würde man das mit >> machen
int convert(int val)
{
int i=1;
while (val >>= 1)
i++;
return i;
}
Aber wie von vielen hier schon gesagt, ist Deine Lösung mit dem
switch-Statement viel verständlicher. Oder, um es mit einem der Erfinder
von C zu sagen: Wenn Du beim Schreiben Deines Programms schon 100%
Deines Könnens verwendest, wie willst Du das Teil dann jemals debuggen?
Bitte beachte, dass die Lösung mit Lookuptable nicht äquivalent zu
Deiner Switch-Case-Lösung ist, da diese auch für die
Zwischen-Eingangswerte gültige Ausgangswerte zurückliefert, aber keine
Bereichsprüfung des Eingangswerts umfasst und somit z. B. für den
Eingangswert 9 keinen gültigen Ausgangswert liefert, für den Wert 3 aber
schon.
Daher müsstest Du zuerst klären, was Du überhaupt erreichen willst, denn
daraus ergeben sich die möglichen Lösungen.
Moderne Compiler sind nicht doof, so dass dieser ein vollständig
definiertes Switch-Case-Konstrukt auch selbständig durch eine
Lookuptable ersetzen kann, wenn alle weiteren Parameter passen, d. h.
Optimierungsstufe (Du musst dem Compiler sagen, ob er auf
Geschwindigkeit oder Platzverbrauch optimieren soll; davon hängt die
beste Lösung ab), Rechnerarchitektur usw.
Am Ende des Tages hilft wohl nur Ausprobieren unter Deinen spezifischen
Rahmenbedingungen; letztlich sollte die Lösung jedoch primär für
C-Verständige gut verständlich und nachvollziehbar sein und keine
"Tricksereien" beinhalten, von denen in zwei Tagen auch Du nicht mehr
weißt, was Du da genau gemacht hast - wie oben schon steht, wie willst
Du Deinen Code ordentlich debuggen, wenn Du schon selbst beim Lesen
Deines eigenen Codes Schwierigkeiten hast und permanent überlegen musst,
warum Du etwas so gemacht hast und was Du damit eigentlich bezwecken
wolltest.
foobar schrieb:> Lass es so wie es ist.
Besser wäre es.
>> Der Vollständigkeit halber: man kann das, insb für größere Zahlen, durch> binäre Suche machen, z.B. für 32 Bit:>
1
>Ouput=((Input&0xffff0000)?16:0)
2
>+((Input&0xff00ff00)?8:0)
3
>+((Input&0xf0f0f0f0)?4:0)
4
>+((Input&0xcccccccc)?2:0)
5
>+((Input&0xaaaaaaaa)?1:0)
6
>+(Input!=0);
7
>
> Bei deinem Zahlenbereich (1,2,4,8) wäre es:>
1
>Output=((Input&0xc)?2:0)
2
>+((Input&0xa)?1:0)
3
>+1;
4
>
Super lesbar. Auf wie viele WTFs/Sekunde kommst du so in deinen Code
Reviews?
Danke nochmals für alle Beiträge.
Ich wollte nur sichergehen, dass es nicht etwas sinnvolleres gibt, hätte
ja sein können dass es etwas besseres gegeben hätte. Ich bin in C nur
Anfänger.
Kleiner Schwank am Rande:
Falk B. schrieb:> 90% der Rechenleistung werden in 10% des Codes verbraucht.
Genau deswegen haben Scriptsprachen (auf Servern) zur Implementierung
der Geschäftslogik durchaus eine Existenzberechtigung. Die harte Arbeit
(z.B. XML Parsing) machen fertige Bibliotheken, die in einer effizienten
Sprache implementiert ist.
Armin K. schrieb:> Ich wollte nur sichergehen, dass es nicht etwas sinnvolleres gibt
Und nur als Zusammenfassung: Nein, es gibt hier nicht einen Vorschlag,
der das gleiche macht, wie Dein Code.
Wenn man es wirklich ganz eilig hat und GCC verwendet, dann gibts noch
die passende Built-in Function:
int __builtin_ffs (int x)
Returns one plus the index of the least significant 1-bit of x, or if x
is zero, returns zero.