1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies. Weitere Informationen
  2. Unsere jährliche Weihnachts-Banner-Aktion hat begonnen! Wir freuen uns auf viele, viele kreative Vorschläge.
    Mehr dazu könnt Ihr hier nachlesen: Weihnachtsbanner 2016

    Information ausblenden

ObjC: Konflikt zwischen int und float wo keiner sein sollte?

Dieses Thema im Forum "OS X-Developer" wurde erstellt von effzehn, 16.09.09.

  1. effzehn

    effzehn Adams Apfel

    Dabei seit:
    07.02.05
    Beiträge:
    511
    Liebe Apfeltalkler,

    folgende Methode ist gegeben:

    Code:
    - (float)angleInDegrees {
    	return ((numberOfSides - 2) / numberOfSides) * 180;
    }
    
    (numberOfSides ist ein integer der bspw. einen Wert von 4 hat.)

    Diese Funktion gibt mir immer 0 zurück. Wenn ich aber statt "2" "2.0" notiere, gibt mir die Methode den korrekten, errechneten Wert zurück. Ich verstehe das nicht: numberOfSides selbst ist ein int, warum kann ich dann nicht erstmal mit einem anderen int verrechnen, auch wenn das Ergebnis float wird? Auch kann ich 180 als int so stehen lassen, nur die Änderung des Subtrahenden ist nötig...

    Vielleicht habe ich da etwas übersehen oder mir sind einige Eigenheiten von ObjC nicht bekannt?

    Gruß,

    Andre
     
  2. Amin Negm-Awad

    Amin Negm-Awad Süsser Pfaffenapfel

    Dabei seit:
    01.03.07
    Beiträge:
    665
    Nein, das ist normales C-Verhalten.

    Wenn Du nur Ints in einer Rechnung hast, dann wird die Rchnung als Int ausgeführt. Bei deinem Ausdruck bedeutet dies:

    ((numberOfSides - 2) / numberOfSides)
    ((int - int) / int)

    Die Klammer besteht nur aus Ints. Daher wird dort eine Int-Subtraktion ausgeführt. Ergebnis:

    (int / int)

    Die Rechnung besteht nur aus Ints. Daher wird eine Int-Division durchgeführt. Da die Rechnung so aussieht, als das der Nenner größer ist, kommt da immer 0 heraus. TTrägst du 2.0 ein, gilt etwas anders:

    ((int - double) / int)

    Da der größere Typ gewählt wird, wird jetzt die Subtraktion als Double ausgeführt. Ergebnis:

    (double / int)

    Da der Zähler jetzt Double ist, wird eine Double-Division ausgeführt. Also gibt es gebrochene Ergebnisse.

    Kinder: Float-Konstanten *immer* als Double schreiben: 2.0 usw.
     
  3. creative7even

    creative7even Jerseymac

    Dabei seit:
    23.02.05
    Beiträge:
    454
    ich kenne Objective-C (noch) nicht - aber ich vermute dass sich die Operationen wie in Java verhalten. Demnach hängt der Typ des Ergebnisses zweier mathematischer Operationen von den Typen der Operanden ab (Operator ist nicht gewichtig - Operand mit höherem Datentyp).

    Angewandt auf den Ausdruck der Methode ergibt die Reduktion auf Datentypen folgendes Ergebnis:
    Code:
    ((numberOfSides - 2) / numberOfSides) * 180;
    
    ((int - int) / int) * int;
    
    und liefert demzufolge auch einen Integer.

    Verändert man einen Datentyp so ändert sich auch das Ergebnis.
    Code:
    ((numberOfSides - 2.0) / numberOfSides) * 180;
    ((int - float) / int) * int; // nun schrittweise aufgelöst
    (float) / int * int;
    (float) * int;
    float;
    
     
    #3 creative7even, 16.09.09
    Zuletzt bearbeitet: 17.09.09
  4. effzehn

    effzehn Adams Apfel

    Dabei seit:
    07.02.05
    Beiträge:
    511
    Ich kann mich dunkel an die Java Regel erinnern (bin da aber schon etwas länger raus). Auf jeden Fall vielen Dank Amin und creative7even, nun macht es wieder Sinn :)
     
  5. mille

    mille Granny Smith

    Dabei seit:
    12.09.09
    Beiträge:
    16
    eigentlich müsste der compiler ruhig sein, wenn du hinter der 180 nen punkt machst, also einen float wert aus der 180 machst.
     
  6. effzehn

    effzehn Adams Apfel

    Dabei seit:
    07.02.05
    Beiträge:
    511
    Nein, die 2 bzw. 2.0 scheint tatsächlich entscheidend zu ein. Trotz der Multiplikation von float mit einem int bleibt das Ergebnis allerdings float.

    Wie Amin schrieb:

     
  7. creative7even

    creative7even Jerseymac

    Dabei seit:
    23.02.05
    Beiträge:
    454
    ja - da am Ende int mit float multipliziert wird:
    Code:
    (Bruch) * 180.0
    int * float = float
    
     
  8. mille

    mille Granny Smith

    Dabei seit:
    12.09.09
    Beiträge:
    16
    ja, ich dachte aber darum geht es. deine methode soll ja float zurückgeben, also musst du da einen floatwert draus machen. und das geschieht mit dem erweitern der 180.
     
  9. effzehn

    effzehn Adams Apfel

    Dabei seit:
    07.02.05
    Beiträge:
    511
    Was ich meinte war, dass die letzte Zahl anscheinend unerheblich ist. Ich bekomme auch beim verwenden eines int (180) eine float zurück – es scheint egal zu sein, ob ich nun 180 oder 180.0 notiere.
     
  10. falseidols

    falseidols Jonagold

    Dabei seit:
    31.07.09
    Beiträge:
    18
    Der Rückgabewert der Methode ist vom Typ float, daher wird hier eine automatische Konvertierung vorgenommen (daher ist es egal ob da nun 180 oder 180.0 steht). Das Problem hier ist, dass der Ausdruck nicht die erwarteten Ergebnisse liefert.

    An dieser Stelle

    Code:
    ((numberOfSides - 2) / numberOfSides)
    
    wird eine Ganzzahldivision durchgeführt, weil alle Operanden vom Typ int sind. Daher geht an dieser Stelle der Nachkommaanteil der Division verloren. Auch das Ändern von 180 in 180.0 ändert daran nichts, da zunächst die innere Klammer ausgewertet wird und hier dann immer noch alle Operanden vom Typ int sind.

    Lösen kann man das Problem indem man einen der Operanden in den Typ float umwandelt:

    Code:
    return ((numberOfSides - 2.0) / numberOfSides) * 180;
    
    oder
    
    return (((float)numberOfSides - 2) / numberOfSides) * 180;
    
    oder
    
    return ((numberOfSides - 2) / (float)numberOfSides) * 180;
    
     
  11. effzehn

    effzehn Adams Apfel

    Dabei seit:
    07.02.05
    Beiträge:
    511
    Danke für die Aufklärung! Den Rückgabewert habe ich ganz außer acht gelassen.
     
  12. Amin Negm-Awad

    Amin Negm-Awad Süsser Pfaffenapfel

    Dabei seit:
    01.03.07
    Beiträge:
    665
    Das hat mit dem Rückgabewert gar nichts zu tun Noch einmal, mache wir es länger

    ((int - int) / int) * float

    Zuerst wird die (innere) Klammer ausgeführt. Dort befinden sich nur Integer. Ob in Cstrop-Rauxel gerade ein gebrochener Mann über die Straße geht, ist gleichgültig. Es werden zwei Integer subtrahiert. Also wird eine Int-Subtraktion mit einem Int-Ergebnis erstellt:

    (int / int) * float

    Zuerst wird die Klammer ausgeführt. Dort befinden sich nur Integer. Ob in Cstrop-Rauxel gerade ein gebrochener Mann über die Straße geht, ist gleichgültig. Es werden zwei Integer dvidiert. Also wird eine Int-Division mit einem Int-Ergebnis erstellt. Dies wird mutmaßlich bereits 0 sein, jedenfalls heftig "gerundet". Also:

    int * float

    Das wird jetzt ne Float-Multiplikation. Da wir jetzt bereits aber nur noch einen Int haben, ändert der Float gar nichts mehr. Das wird nicht mehr nachträglich genau.
     
  13. Jamsven

    Jamsven London Pepping

    Dabei seit:
    21.11.07
    Beiträge:
    2.046
    Ein Tipp:
    Wenn man mal nicht weiß wieso bestimmte Werd auftreten einfach die Schritte mit dem Debugger austesten. Da sieht man dann zeilenweise wie sich die Variablen verändern.
    In diesem Fall hättest du die Rechnung auf mehrere Ausdrücke aufteilen müssen.
     
  14. falseidols

    falseidols Jonagold

    Dabei seit:
    31.07.09
    Beiträge:
    18
    Genau das hatte ich auch geschrieben. Mein erster Satz(mit dem Rückgabetyp) bezog sich nur auf den Post, indem vorgeschlagen wurde einfach mit 180.0 statt 180 zu multiplizieren. Mein ganzer restlicher Eintrag bezog sich dann auf das Problem der Integerdivision. :)

    Da kann man nur hoffen, dass sich der arme Mann aus Castrop-Rauxel gerade auf dem Weg zum Optiker befindet. ;)
     
  15. Amin Negm-Awad

    Amin Negm-Awad Süsser Pfaffenapfel

    Dabei seit:
    01.03.07
    Beiträge:
    665
    Sorry, hatte ich nicht gesehen, mea culpa.
     

Diese Seite empfehlen