Unäres "?"



  • Also Folgendes kann man doch sicher smarter machen, oder?

    if (a < b) {
        c = b - a;
    } else {
        c = a - b;
    };
    

    Liege ich mit ...

    (a < b) ? c=b-a : c=a-b;
    

    ... halbwegs richtig?

    Habe gerade keinen Compiler zur Hand, sonst hätte ichs auf meinem Wege zum C-Nerd ausprobiert! 😉

    Sänkju!



  • denk schon dass es stimmt, aber man kann es sogar auch noch so schreiben:

    c=(a < b) ? b-a : a-b;
    


  • ... das spezielle Beispiel sieht mir verdammt aus wie:

    #define ABS(x) ((x) < 0 ? -(x) : (x))
    
    c = ABS(a-b);
    

    ... was dann aufgelöst wird zu:

    c = ( (a-b) < 0 ? -(a-b) : (a-b) );

    ... und nach mathematischer Umformulierung/Aufdröselung:

    c = ( a < b ? b - a : a - b );

    ... und das bedeutet: JA 😉



  • Noch l33ter:

    int uplus(int x) { return x; }
    int uminus(int x) { return -x; }
    ...
    c = (a < b ? uminus : uplus)(a - b);
    

    OK in Lisp sieht das schöner aus.



  • Schonmal gut dass ich nerdmäßig nicht daneben lag, aber die Empfehlungen von "0bi^" finde ich geradezu sexy weil man noch sehen kann was genau gemacht wird (a-b) sonst (b-a), der Beitrag von "jox" ist sicherlich auch sehr smart, allerdings musste ich über -(a-b) dann doch erst mal nachdenken. 🙂

    Das von "bashar" habe ich nicht verstanden. 😞

    Allerbeste Grüße
    Timmix



  • timmix schrieb:

    Also Folgendes kann man doch sicher smarter machen, oder?

    kann man 😉

    /* für 32 bit integers */
    #define SMART(a,b) ((((a)-(b))>>30)|1)*((a)-(b))
    


  • net schrieb:

    /* für 32 bit integers */
    #define SMART(a,b) ((((a)-(b))>>30)|1)*((a)-(b))
    

    Herr im Himmel! Kann mir DAS mal bitte jemand haarspaltermäßig erklären?

    Also #define SMART(a,b) verstehe ich noch, aber die Sachen mit dem Shift und der ODER Verknüpfung macht mich ganz wuschisch ... 😕



  • timmix schrieb:

    net schrieb:

    /* für 32 bit integers */
    #define SMART(a,b) ((((a)-(b))>>30)|1)*((a)-(b))
    

    Herr im Himmel! Kann mir DAS mal bitte jemand haarspaltermäßig erklären?

    Haarspaltermäßig soll es dir net erklären, der hat das auch verbrochen 😉

    Die Kurzfassung: Der erste Teil ((((a)-(b))>>30)|1) gibt je nachdem ob (a-b) negativ oder positiv ist, eine -1 oder eine +1. Mit dieser wird dann der zweite Teil, also (a-b) selbst multipliziert.

    Empfehlen kann man sowas aber nicht, weil es nicht portabel ist und weil...

    timmix schrieb:

    Also #define SMART(a,b) verstehe ich noch, aber die Sachen mit dem Shift und der ODER Verknüpfung macht mich ganz wuschisch ... 😕

    ... es die Sache unnötig verkompliziert.

    Die smarteste Variante ist imho eh:

    int foo = abs(a-b);
    


  • jox schrieb:

    ... das spezielle Beispiel sieht mir verdammt aus wie:

    #define ABS(x) ((x) < 0 ? -(x) : (x))
    
    c = ABS(a-b);
    

    ... was dann aufgelöst wird zu:

    c = ( (a-b) < 0 ? -(a-b) : (a-b) );

    ... und nach mathematischer Umformulierung/Aufdröselung:

    c = ( a < b ? b - a : a - b );

    c=(a < b) ? b-a : a-b;
    

    Funktioniert prima bei unsigned wogegen a-b<0 gleich durch false ersetzt werden kann.



  • TactX schrieb:

    Haarspaltermäßig soll es dir net erklären, der hat das auch verbrochen 😉

    ok, versuch ich's mal. die 'formel' geht davon aus dass:
    1. negative 'ints' als zweierkomplement gespeichert werden. guckst du: http://nirvana.informatik.uni-halle.de/~molitor/CDROM1999/java/Multiplikation/two.html
    2. der 'right shift' operator (>>) immer das reinschiebt, was im höchsten bit steht (ist aber meistens so).
    also: eine -1 als 32-bittiger integer wird in der oben genannten darstellungsform binär als 32 einsen gespeichert und jede negative zahl hat das höchste bit gesetzt. wenn man nun eine beliebige negative zahl 31 mal rechts shiftet kommt immer -1 dabei heraus. bei positiven zahlen würde aber immer 0 herauskommen. mit der 0 kann man als multiplikator aber nix anfangen. mit einem kleinen trick (|1) wird diese null zur 1 gemacht. bei einer -1 hat das '|1' keine wirkung, weil sowieso alle bits sowieso schon 1 sind. eine kleine unbedeutsamkeit: dadurch, dass das niedrigste bit durch das '|1' immer auf 1 gesetzt wird, braucht man nicht 31 mal sondern nur 30 mal schiften.
    ich hoffe das ist einigermassen verständlich so. 😉

    btw: wie TactX schon schrieb, ist das ganze nicht portabel, obwohl's wohl auf 99% aller prozessoren funzen wird... vorteil: so ein makro wird schon beim compilieren ausgerechnet und kann u.u. ganz schön speed bringen im vergleich zu 'normalem' code.



  • Herrlich - ich habs begriffen! Vielen Dank.

    edit:
    Ein Stutzer noch!

    so ein makro wird schon beim compilieren ausgerechnet und kann u.u. ganz schön speed bringen im vergleich zu 'normalem' code.

    Wie kann das sein, wenn ich SMART(a,b) in einer Schleife (sagen wir 120000 mal) bearbeite und berchne? A und B also zur Laufzeit andere Werte haben können als beim kompilieren?



  • timmix schrieb:

    so ein makro wird schon beim compilieren ausgerechnet und kann u.u. ganz schön speed bringen im vergleich zu 'normalem' code.

    Wie kann das sein, wenn ich SMART(a,b) in einer Schleife (sagen wir 120000 mal) bearbeite und berchne? A und B also zur Laufzeit andere Werte haben können als beim kompilieren?

    äääh? ach so - da hab' ich mist geschrieben. das gilt natürlich nur für konstanten...


Anmelden zum Antworten