pother_dane: false >= null

hallo,

als ich heute auf der konsole (firebug) rumgespielt habe, ist mir folgendes, für mich nicht durchdringbares, phänomen untergekommen:

ich vergleiche null, false und "" und komme zu folgenden, wie ich finde seltsamen ergebnissen:

  
null < false //--> false  
null > false //--> false  
null == false //--> false  
null != false //--> true  
//bis hierhin hätte ich die ausgabe noch richtig vorher gesagt. aber jetzt:  
null <= false //--> true  
null >= false //--> true  
  
//das selbe mit ""  
null < "" //--> false  
null > "" //--> false  
null == "" //--> false  
null != "" //--> true  
//und auch hier:  
null <= "" //--> true  
null >= "" //--> true  

vergleiche mit undefined bringen für den durchschnittsverstand (halbwegs) erwartbare ergebnisse.
ich habe dann mal ein wenig in der dokumentation gelesen und versucht zu verstehen warum das so ist. die scheint aber für nichtinformatiker im anfängerstatus bei solchen fragen ein pdf mit einigen siegeln zu sein.
meine vermutung nach der doc-lektüre: es hat etwas damit zu tun, dass null ein objekt, false ein boolean und "" ein string ist. im vorgang des vergleichs werden die typen unterschiedlich "aufgelöst" (nennt man das so?) und eigentlich hat alles sein richtigkeit.
könnten mir das versiertere hier vielleicht erklären/einen hinweis geben?

danke und gruß,

pD

  1. Hi,

    könnten mir das versiertere hier vielleicht erklären/einen hinweis geben?

    (Auch) JS konvertiert automatisch Datentypen. false ist genauso !true wie null. false==null oder false=="" etc. ist also immer so wahr, wie false<=null.

    Wenn Du den Datentyp bei der Bedinung mittesten möchtest, geht das (auch) in JS mit false===null. Das ist dann immer unwahr ...

    Gruß, Cybaer

    --
    Man muß viel gelernt haben, um über das, was man nicht weiß, fragen zu können.
    (Jean-Jacques Rousseau, Philosoph u. Schriftsteller)
    1. Hi Cybaer,

      (Auch) JS konvertiert automatisch Datentypen. false ist genauso !true wie null. false==null oder false=="" etc. ist also immer so wahr, wie false<=null.

      Nur interessehalber: der UP hat ja herausgefunden, dass null == false --> false ist und null > false --> false - Aber: null >= false soll true sein, warum der Unterschied, ist glaube ich seine Frage. Wenn alles true wäre, wäre es ja vielleicht wieder logisch.

      Wenn Du den Datentyp bei der Bedinung mittesten möchtest, geht das (auch) in JS mit false===null. Das ist dann immer unwahr ...

      klar.

      ciao
      romy

    2. hallo,

      (Auch) JS konvertiert automatisch Datentypen. false ist genauso !true wie null. false==null oder false=="" etc. ist also immer so wahr, wie false<=null.

      dass js automatisch daten umwandelt ist mir schon klar gewesen. meine verwunderung entsprang dem, wie ich finde, gar nicht so selbstverständlichen umstand, dass null weder kleiner noch größer und auch nicht gleich false ist, aber gleichzeitig kleinergleich/größergleich.

      Wenn Du den Datentyp bei der Bedinung mittesten möchtest, geht das (auch) in JS mit false===null. Das ist dann immer unwahr ..

      die frage war mehr eine klassische interessefrage als einem programmierproblem gedankt. mit solchen sachen beschäftigt man sich halt wenn man noch lernen muss :)

      gruß,

      pD

  2. Hallo!

    ich habe dann mal ein wenig in der dokumentation gelesen und versucht zu verstehen warum das so ist.

    Der Hintergrund ist eigentlich ziemlich einfach:

    null ist vom Typ null [1] und evaluiert nach:

    false im Boolean-Kontext
     0 im Zahlen-Kontext
     "null" im String-Kontext

    undefined ist vom Typ undefined und evaluiert nach:

    false im Boolean-Kontext
     NaN im Zahlen-Kontext
     "undefined" im String-Kontext

    Die Frage bleibt jetzt, wann implizite Typumwandlungen bei Vergleichen stattfinden. Und die Regeln sind wie folgt für x == y bzw. x != y, falls die Typen nicht gleich sind:

    [Nummerierung an Hand ovn ECMA-262 11.9.3]
    14. x ist undefined, y ist null: true
    15. x ist null, y ist undefined: true
    16. x ist Zahl, y ist String: Wandle y in eine Zahl um und vergleiche dann
    17. x ist String, y ist Zahl: Wandle x in eine Zahl um und vergleiche dann
    18. x ist Boolean, y ist etwas anderes: Wandle x in eine Zahl um und
                                            vergleiche dann
    19. y ist Boolean, x ist etwas anderes: Wandle y in eine Zahl um und
                                            vergleiche dann
    20. x ist String oder Zahl und y ist Objekt: Wandle y in einen primitiven
                                                 Datentypen um und vergleiche
                                                 dann.
    21. y ist String oder Zahl und x ist Objekt: Wandle x in einen primitiven
                                                 Datentypen um und vergleiche
                                                 dann.
    22. Wenn keines der obigen zutrifft: false

    Das heißt, für null == false:

    Fällt in Fall 19, also wird false in eine Zahl umgewandelt (gibt 0) und dann verglichen: null == 0. Typ null und Typ Zahl tauchen aber nicht in der obigen Liste auf, also trifft 22 zu und das Ergebnis ist false.

    Für den Fall undefined == false:

    Fällt in den Fall 19, also wird false in eine Zahl umgewandelt (gibt 0) und dann verglichen: undefined == 0. Typ undefined und Typ Zahl tauchen aber nicht in der obigen Liste auf, also trifft 22 zu und das Ergebnis ist false.

    Betrachten wir nun die Regeln für die Vergleiche x < y, x <= y, x > y und x >= y:

    Wenn x und y in primitive Datentypen gewandelt keine Strings sind, dann gelten folgende Vergleichsregeln (nach ECMA-262 11.8.5):

    4. Wandle x in Zahl um
    5. Wandle y in Zahl um
    6. Wenn x NaN ist: gib undefined zurück
    7. Wenn y NaN ist: gib undefined zurück
    8. Wenn x und y die gleiche Zahl sind, gib false zurück
    9. Wenn x = +0 und y = -0 ist, gib false zurück
    10. Wenn x = -0 und y = +0 ist, gib false zurück
    11. Wenn x = +unendlich ist, gib false zurück
    12. Wenn y = +unendlich ist, gib true zurück
    13. Wenn y = -unendlich ist, gib false zurück
    14. Wenn x = -unendlich ist, gib true zurück
    15. Führe den mathematischen Vergleich x < y durch und gib das Ergebnis
        zurück.

    Das wird dann in die Operatoren "<" und ">=" so umgesetzt:

    | verwend. Vergleichsoperator
    Ergebnis des Vergleichs |   <   |   >=
    ------------------------+-------+-------
     true                   | true  | false
     false                  | false | true
     undefined              | false | false

    (Bei ">" und "<=" werden nur die beiden Operatoren vertauscht.)

    Betrachten wir nun den Fall null < false:

    Schritt 4 wandelt null in eine Zahl um, ergibt +0. Schritt 5 wandelt false in eine Zahl um, ergibt +0. Beide sind mathematisch gleich, Fall 8, also ergibt das ganze false, false ergibt in der Lookup-Tabelle für < ein false.

    Betrachten wir nun den Fall undefined < false:

    Schritt 4 wandelt undefined in eine Zahl um, ergibt NaN. Schritt 5 wandelt false in eine Zahl um, ergibt +0. Fall 6 tritt ein, ergebnis ist undefined. In der Lookuptabelle ergibt sich nun für "<" das Resultat false.

    Also ist null < false == false und undefined < false == false.

    Betrachten wir nun den Fall null <= false - der ist identisch mit dem Fall false >= null:

    Schritt 4 wandelt null in eine Zahl um, ergibt +0. Schritt 5 wandelt false in eine Zahl um, ergibt +0. Beide sind mathematisch gleich, Fall 8, also ergibt das ganze false, false ergibt in der Lookup-Tabelle für >= ein true.

    Betrachten wir nun den Fall undefined <= false - der ist identisch mit dem Fall false >= undefined:

    Schritt 4 wandelt undefined in eine Zahl um, ergibt NaN. Schritt 5 wandelt false in eine Zahl um, ergibt +0. Fall 6 tritt ein, ergebnis ist undefined. In der Lookuptabelle ergibt sich nun für ">=" das Resultat false.

    Also ist false >= null == true und undefined >= null == false.

    Das gleiche Spiel ist auch bei "" der Fall, da "" in eine Zahl gewandelt eben auch 0 ergibt (damit < und > andere Semantiken bei Stringvergleichen haben, müssen beides Strings sein).

    Ich hoffe, ich konnte damit das ganze etwas verdeutlichen.

    [1] typeof liefert nicht immer den internen Typ zurück!

    Viele Grüße,
    Christian

    1. hallo,

      wow, vielen dank für die ausführliche antwort. im prinzip (wo auch sonst) alles klar. man kann vielleicht sagen: ist mehr eine frage der konvention als eine die sich per menschenverstand so wirklich durchdringen lässt.
      eines noch:

      Wenn x und y in primitive Datentypen gewandelt keine Strings sind, dann gelten folgende Vergleichsregeln (nach ECMA-262 11.8.5):

      1. Wandle x in Zahl um
      2. Wandle y in Zahl um
      3. Wenn x NaN ist: gib undefined zurück
      4. Wenn y NaN ist: gib undefined zurück
      5. Wenn x und y die gleiche Zahl sind, gib false zurück
      6. Wenn x = +0 und y = -0 ist, gib false zurück
      7. Wenn x = -0 und y = +0 ist, gib false zurück
      8. Wenn x = +unendlich ist, gib false zurück
      9. Wenn y = +unendlich ist, gib true zurück
      10. Wenn y = -unendlich ist, gib false zurück
      11. Wenn x = -unendlich ist, gib true zurück
      12. Führe den mathematischen Vergleich x < y durch und gib das Ergebnis
            zurück.

      diese liste habe ich mir auch durchgelesen, aber bei so dingen wie -0, +0, -unendlich und +unendlich gingen mir die verständnismöglichkeiten aus. ich nehme mal an, (man verzeih mir meine unfachmännische/falsche ausdrucksweise) das hat was mit den bits ganz am boden der werte zu tun, so in der art? und: was unterscheidet +0/unendlich von -0/unendlich? auf solche fragen selbstständig laiengerechte antworten zu finden ist wirklich sehr schwer... sry!

      [1] typeof liefert nicht immer den internen Typ zurück!

      gibt es eine andere möglichkeit an die internen typen zu gelangen von der ich noch nichts weiß.

      vielen dank nochmal,
      gruß

      pD

      1. Hallo,

        diese liste habe ich mir auch durchgelesen, aber bei so dingen wie -0, +0, -unendlich und +unendlich gingen mir die verständnismöglichkeiten aus. ich nehme mal an, (man verzeih mir meine unfachmännische/falsche ausdrucksweise) das hat was mit den bits ganz am boden der werte zu tun, so in der art? und: was unterscheidet +0/unendlich von -0/unendlich? auf solche fragen selbstständig laiengerechte antworten zu finden ist wirklich sehr schwer... sry!

        Das hängt mit Floating-Point-Arithmetik zusammen. Eine Floating-Point-Zahl im Computer setzt sich aus 3 Dingen zusammen:

        1. Einem Bit für's Vorzeichen
        2. Der Mantisse
        3. Dem Exponenten

        Mathematisch ist eine Floating-Point-Zahl so zu lesen:

        (-1)^Vorzeichen * Mantisse * 2^Exponent

        Wenn man von Details wie der genauen Kodierung mal absieht ergeben sich +/-0, +/-unendlich und NaN aus folgender Überlegung:

        1. +/-0 ist einfach eine Notwendigkeit auf Grund der Tatsache, dass es ein Vorzeichenbit gibt. Im Gegensatz zu Ganzzahlen, die fast immer im Zweierkomplement dargestellt werden, kann man hier kein Zweierkomplement nutzen und muss daher ein Extra-Vorzeichenbit haben. Da Zahl ohne Bit gesetzt = - Zahl mit Bit gesetzt sein sollte (wenn man nicht komplett am Rad drehen will ;-)), gibt es eben zu +0 ein -0 als Äquivalent. Die Vergleichsregeln von eigentlich allen Programmiersprachen sagen jedoch, dass +0 == -0 ist, siehe auch die Regeln für JS.

        2. NaN ergibt soch aus unbestimmten Ausdrücken: 0/0 z.B. ist NaN, genauso wie die Versuchte Umwandlung vom String "abc" in ein Float. NaN steht für Not a Number und wird durch ein bestimmtes festgelegtes Bitmuster kodiert.

        3. +/-unendlich zeigen Überläufe an. Es gibt auch bei Floats eine größte darstellbare Zahl und wenn Du eine Operation durchführst, die über diese Zahl hinausgeht, dann wird durch +unendlich der Überlauf gekennzeichnet, den kann man damit auch abfangen.

        NaN, +/-unendlich und +/-0 spielen auch noch auf verschiedene Arten zusammen, was die Nützlichkeit nochmal erhöht, worauf ich hier aber nicht genauer eingehen will.

        Wenn Dich näheres zu FP-Arithemtik interessiert: http://docs.sun.com/source/806-3568/ncg_goldberg.html (Achtung: Langes, teilweise etwas schwer zu verdauendes Dokument, aber sehr informativ)

        [1] typeof liefert nicht immer den internen Typ zurück!
        gibt es eine andere möglichkeit an die internen typen zu gelangen von der ich noch nichts weiß.

        Naja, typeof ist eigentlich schonmal ein sehr guter Start, Du musst lediglich noch einige Spezialfälle abarbeiten. Wenn type == "object" ist, dann kann das vom Typ her auch null sein, d.h. Du musst extra noch auf "null" prüfen. Und es gibt noch ein paar andere Fälle diesbezüglich, es gab vor einiger Zeit mal im Archiv eine Diskussion zum Thema, Thema damals war, warum typeof für "function"-Objekte eine Ausnahme macht, für "array"-Objekte aber nicht.

        Viele Grüße,
        Christian