2017-11-08 5 views
14

Kann mir jemand sagen, warum diese beiden Modul-Berechnungen zwei unterschiedliche Ergebnisse ergeben? Ich muss nur jemanden oder etwas beschuldigen, aber ich für all die Stunden, in denen ich diesen Fehler nicht gefunden habe.Modul gibt falsches Ergebnis?

public void test1() 
{ 
    int stepAmount = 100; 
    float t = 0.02f; 
    float remainder = t % (1f/stepAmount); 
    Debug.Log("Remainder: " + remainder); 
    // Remainder: 0.01 

    float fractions = 1f/stepAmount; 
    remainder = t % fractions; 
    Debug.Log("Remainder: " + remainder); 
    // Remainder: 0 
} 

Mit VS-2017 V15.3.5

+1

Für was es wert ist, kann ich dies nicht auf VS für Mac v7.2 (636) reproduzieren. Beide Reste sind '0.0' – InBetween

+0

Dotnetfiddle zeigt 0 für beide Ergebnisse: https://dotnetfiddle.net/XTHswt Ich habe genau den gleichen Code wie in der Dotnetfiddle-Link mit https://www.jdoodle.com/compile-c versucht -sharp-online und es zeigt das Problem, das Sie beschreiben. – TyCobb

+0

Reproduzierbar hier: https://ideone.com/JHomEl – Ryan

Antwort

8

Meine beste Wette ist, dass dies auf die Freiheit zurückzuführen ist, die Laufzeit mit einer höheren Genauigkeit Gleitkomma-Operationen auszuführen hat, als die Typen beteiligt und dann das Ergebnis Kürzen zu die Genauigkeit des Typs bei der Zuweisung:

Die CLI-Spezifikation in Abschnitt 12.1.3 schreibt eine genaue Genauigkeit für Gleitkommazahlen, float und double vor, wenn sie in Speicherpositionen verwendet werden. Es erlaubt jedoch, dass die Genauigkeit überschritten wird, wenn Fließkommazahlen an anderen Stellen wie der Ausführungsstapel, Argumente, Rückgabewerte usw. verwendet werden. Welche Genauigkeit verwendet wird, bleibt der Laufzeit und der zugrunde liegenden Hardware überlassen. Diese zusätzliche Genauigkeit kann zu feinen Unterschieden bei Gleitkommaauswertungen zwischen verschiedenen Maschinen oder Laufzeiten führen.

Quelle here.

In Sie erstes Beispiel t % (1f/stepAmount) können mit einer höheren Genauigkeit als float und dann abgestumpften vollständig durchgeführt werden, wenn das Ergebnis zu remainder, während im zweiten Beispiel zugeordnet ist, zu 1f/stepAmountfractions zur Modulo-Operation vor und abgestumpften zugeordnet ist.

Wie, warum stepamount macht ein const macht beide Modul Operationen konsistent ist der Grund dafür, dass 1f/stepamount sofort einen konstanten Ausdruck wird, die ausgewertet und abgeschnitten Präzision zu schweben bei Kompilierung und unterscheidet sich nicht von 0.01f Schreiben, die im Wesentlichen macht beide Beispiele sind gleichwertig.

+0

Ich weiß einfach nicht genug, um einen guten Kommentar dazu zu machen, aber macht das "f" in der '(1f/stepAmount)' -Operation nicht eine ganze 'float'-Operation? Auch (noch seltsamer?), Machen 'stepamount' ein' const' behebt das Problem. – Madmenyo

+0

Screenshot der erzeugten IL aus dem Code https: // imgur.com/0fjIgIl –

+0

Ich denke, das ist richtig. Wenn ich die Typen von t, Rest und Brüche in LinqPad verdopple, bekomme ich 'Rest: 0.00999999955296516' für beide Operationen. –