(int)((float)10.9 * 10)
wird zu 108
ausgewertet. Warum?Die angegebene Berechnung verstehen (Besetzung + Multiplikation)
IMO die (int)
-cast sollte nach die Multiplikation ausgewertet werden.
(int)((float)10.9 * 10)
wird zu 108
ausgewertet. Warum?Die angegebene Berechnung verstehen (Besetzung + Multiplikation)
IMO die (int)
-cast sollte nach die Multiplikation ausgewertet werden.
Das ist genau der Fall. Es ist nur, dass 10.9 ist leicht weniger als 10.9 aufgrund der Art, wie Fließkommazahlen dargestellt werden (10.9 kann nicht genau dargestellt werden, so erhalten Sie eine Annäherung, die in diesem Fall etwa 10.89999999 ist ...). Die Besetzung schneidet dann alle Ziffern ab, die dem Dezimalpunkt folgen. So erhalten Sie 108
Genaue Werte sind wie folgt hier (erhalten mit Jon Skeet DoubleConverter Klasse):
10.9 -> 10.9000000000000003552713678800500929355621337890625
(float) 10.9 -> 10.8999996185302734375
von 10, dass die Schwimmer Multipliziert und dann alle Dezimalstellen Abschneiden führt offensichtlich in 108
Umm ich verstehe nicht, warum es in zwei Anweisungen funktioniert zu arbeiten erwartet. 'var f = ((float) 10.9 * 10); int i = (int) f;' gibt 109 und 109 –
Aber warum bekomme ich '109' anstelle von' 108.9999 ... ', wenn ich folgendes mache: '((float) 10.9 * 10) .ToString()' – thomai
Weil 'ToString' rundet, während casting nach int abgeschnitten wird. –
Lustig genug, das Problem hier ist, dass der Ausdruck zur Kompilierzeit berechnet wird, scheinbar mit einfacher Genauigkeit Mathematik wie erwartet. Dies geschieht in beiden Debug- und Release-Builds:
// this replaces the whole operation
IL_0001: ldc.i4.s 108
IL_0003: stloc.0
IL_0004: ldloc.0
IL_0005: call void [mscorlib]System.Console::WriteLine(int32)
Während der Fall var f =((float)10.9 * 10);int i = (int)f;
noch für die Multiplikation optimiert ist, aber mit doppelter Genauigkeit. Da die Besetzung in einem separaten Schritt getan wird Ich denke, es ist den Compiler (??) verwechselt:
IL_000b: ldc.r4 109 // 109 result for the first part
IL_0010: stloc.1
IL_0011: ldloc.1
IL_0012: conv.i4 // separate conversion to int
IL_0013: stloc.2
// rest is printing it
IL_0014: ldloc.1
IL_0015: box [mscorlib]System.Single
IL_001a: ldstr " "
IL_001f: ldloc.2
IL_0020: box [mscorlib]System.Int32
IL_0025: call string [mscorlib]System.String::Concat(object, object, object)
IL_002a: call void [mscorlib]System.Console::WriteLine(string)
Ehrlich gesagt würde ich sagen, dass die Compiler falschen Code im zweiten Fall erzeugt, was wahrscheinlich ist, warum vermeidet C++ Optimierung Fließkomma-Code wie die Pest. Glücklicherweise ist dies nur ein Problem für diese Art von Testcode, der vollständig zur Kompilierungszeit durchgeführt werden kann, die tatsächliche Multiplikation der Variablen wäre in Ordnung.
ich tatsächlich versucht dies zu:
Console.WriteLine((int)(float.Parse(Console.ReadLine()) * int.Parse(Console.ReadLine())));
und gab es 10,9 und 10, und das Ergebnis war 108 wie erwartet.
* ... und das Ergebnis war 108 wie erwartet *. Du musst Fließkomma lieben. – Groo
Ich glaube nicht, dass das jemals in Frage stand, es ist die Tatsache, dass, wenn es in Schritten zerbrochen wird, das komische Ding ist. Der Compiler berechnet intern den falschen (besseren, aber immer noch falschen) Typ. – Blindy
Jedoch ist 'var z = 10; var f = (10,9 f * z); int i = (int) f; 'macht die Multiplikation (in IL), berechnet aber immer noch 109. Ich habe das Gefühl, dass der Jitter etwas Spaß machen muss. – zinglon
Ihr float
Ergebnis, vor dem Gießen zu int, ist 108.9999, da 109.0000 can't be represented in floating point. (Wie in den Kommentaren erwähnt, das ist falsch; 109 ganz gut dargestellt werden kann, aber irgendwie die Expression zu 108,9999 - das gilt nach wie vor)
Der int
Wert 108 sein Warum? Das Umwandeln von Gleitkomma (double
oder float
) zu int
schneidet den Dezimalteil ab. Es wird nicht abgerundet. So schneidet es die .9999 und Sie erhalten 108.
Zum runden, ersetzen Sie den Guss durch Math.Round()
oder Convert.ToInt32()
.
Convert.ToInt32((float) 10.9 * 10);
http://blog.reverberate.org/2014/09/what-every-computer-programmer-should.html sais, dass "Mathematische Operationen wie diese geben Ihnen genaue Ergebnisse, solange alle Werte ganze Zahlen kleiner als sind 2^24 ". 109 ist viel kleiner als 2^24 ... – thomai
Ja, Kay ist falsch, 109 kann gut dargestellt werden. Es ist die Multiplikation selbst, die nicht präzise genug ist. – Blindy
Obwohl @Blindy korrekt ist, +1 für die Erwähnung von 'Convert.ToInt32'. Ich wusste es nicht Runden, das ist eine gute Sache. – Groo
Sie treten in Fließkommaberechnungspräzisionsproblem auf. – MarcinJuraszek
Könnten Sie bitte erklären, was Sie bisher über Fließkomma gelernt haben, damit wir wissen, wo wir anfangen sollen zu erklären (Sie haben offensichtlich nach etwas gesucht, wie "C# welcher Programmierer über den Punkt lernen sollte" - zB http: //blog.reverberate) .org/2014/09/was-jeder-Computer-Programmierer-sollte.html - so zögern Sie nicht, Ergebnisse Ihrer Forschung zu der Post hinzuzufügen). –
@Joey sollten Sie Ihre Antwort rückgängig machen, die Antwort auf Sirams Kommentar zu Ihrer Antwort lautet: "Es ist, weil der Compiler, wenn Sie eine einzelne Anweisung verwenden, es tatsächlich als" double f = ((float) 10.9 * 10); int i = (int) f; 'es wird ein Doppel für den Zwischenwert verwendet." –