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

effzehn

Luxemburger Triumph
Registriert
07.02.05
Beiträge
510
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
 

Amin Negm-Awad

Süsser Pfaffenapfel
Registriert
01.03.07
Beiträge
665
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

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.
 

creative7even

Jerseymac
Registriert
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;
 
Zuletzt bearbeitet:

effzehn

Luxemburger Triumph
Registriert
07.02.05
Beiträge
510
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 :)
 

mille

Granny Smith
Registriert
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.
 

mille

Granny Smith
Registriert
12.09.09
Beiträge
16
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.

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.
 

effzehn

Luxemburger Triumph
Registriert
07.02.05
Beiträge
510
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.
 

falseidols

Jonagold
Registriert
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;
 

effzehn

Luxemburger Triumph
Registriert
07.02.05
Beiträge
510
Danke für die Aufklärung! Den Rückgabewert habe ich ganz außer acht gelassen.
 

Amin Negm-Awad

Süsser Pfaffenapfel
Registriert
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.
 

Jamsven

London Pepping
Registriert
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.
 

falseidols

Jonagold
Registriert
31.07.09
Beiträge
18
Das hat mit dem Rückgabewert gar nichts zu tun

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. ;)