Entwickler-Ecke

Basistechnologien - Weis jemand wie das System rundet?


C# - Mo 28.05.12 20:57
Titel: Weis jemand wie das System rundet?
Hey @ll,

ich habe mich gerade gefragt wie im System die Zahlen gerundet werden. Das Ergebnis findet ihr im Anhang als Bild, der Code dazu:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "Rundungstest";
            Console.ForegroundColor = ConsoleColor.White;

            ulong x = 9999999999999999999, y = 5000000000000000000;
            Console.WriteLine("{0} / {1} = {2}\tMit ulong / ulong", x, y, x / y);
            Console.WriteLine("{0} / {1} = {2}\tMit Math.Round(ulong, double)", x, y, Math.Round(x / (double)y));
            Console.WriteLine("{0} / {1} = {2}\tMit Math.Floor(ulong, double)", x, y, Math.Floor(x / (double)y));
            Console.WriteLine("{0} / {1} = {2}\tMit Math.Truncate(ulong, doub)", x, y, Math.Truncate(x / (double)y));
            Console.WriteLine("{0} / {1} = {2}\tMit ulong / double\n\n", x, y, (x / (double)y));

            x = 999999999999999;
            y = 500000000000000;
            Console.WriteLine("{0} / {1} = {2}\tMit ulong / ulong", x, y, x / y);
            Console.WriteLine("{0} / {1} = {2}\tMit Math.Round(ulong, double)", x, y, Math.Round(x / (double)y));
            Console.WriteLine("{0} / {1} = {2}\tMit Math.Floor(ulong, double)", x, y, Math.Floor(x / (double)y));
            Console.WriteLine("{0} / {1} = {2}\tMit Math.Truncate(ulong, double)", x, y, Math.Truncate(x / (double)y));
            Console.WriteLine("{0} / {1} = {2}\tMit ulong / double\n\n", x, y, (x / (double)y));


            x = 99999999999999;
            y = 50000000000000;
            Console.WriteLine("{0} / {1} = {2}\tMit ulong / ulong", x, y, x / y);
            Console.WriteLine("{0} / {1} = {2}\tMit Math.Round(ulong, double)", x, y, Math.Round(x / (double)y));
            Console.WriteLine("{0} / {1} = {2}\tMit Math.Floor(ulong, double)", x, y, Math.Floor(x / (double)y));
            Console.WriteLine("{0} / {1} = {2}\tMit Math.Truncate(ulong, double)", x, y, Math.Truncate(x / (double)y));
            Console.WriteLine("{0} / {1} = {2}\tMit ulong / double", x, y, (x / (double)y));
            Console.Read();
        }
    }
}


Kann mir das jemand erklären?


jaenicke - Mo 28.05.12 21:42

Wenn du nicht explizit rundest, wird offensichtlich der ganzzahlige Anteil als Ergebnis benutzt. Also das gleiche wie Truncate. Sprich die Nachkommastellen werden ignoriert.


interessierter - Mo 28.05.12 21:42

Hallo

Bin zwar Anfänger, aber vielleicht kann ich dir hier weiterhelfen :)

Dazu brauchst du Math.Round

Ich habe hier ein kleines Beispiel:

C#-Quelltext
1:
2:
3:
double x = 2.34567//Zu rundender Wert x
x = Math.Round(x, 2); //2 steht für ''wieviele Stellen nach dem Komma runden''
Console.WriteLine(x);


Hoffe es ist das was du suschst. Sonst gibts hier sicher jemand der dir weiterhelfen kann.

Grüsse
interessierter

Moderiert von user profile iconTh69: C#-Tags hinzugefügt


Ralf Jansen - Mo 28.05.12 22:25

Zitat:
Kann mir das jemand erklären?


Du kannst es einfach nachlesen. An jeder Stelle der Math Klasse deren Methode du ja schon benutzt steht es dran. Für Gleitkommatypen wird 'IEEE 754' benutzt.

Wenn dir ein bestimmtes Ergebnis deines Tests spanisch vorkommt solltest du gezielt nach diesem fragen. Ich und bestimmt sonst auch keiner hat Lust jeden Einzeltest durchzukauen.


C# - Fr 01.06.12 13:11

Ok Sorry für die ungenaue Beschreibung und Danke für die Antworten.
Worauf ich hinaus möchte ist dass Math.Floor(double) - welches ja die nächst kleinere Ganzzahl ausgibt - und Math.Truncate(double) anscheinend nicht so genau arbeitet wie die normale Division von ulong / double. Wenn ich diese 2 Typen fülle, bis die fast Höchstmögliche Ziffernzahl erreicht ist (siehe 1. Post Code-Zeile 15), erreiche ich bei ulong / ulong immer noch korrekter weise 1. Bei Truncate und bei Floor erhalte ich jetzt jedoch 2.

C#-Quelltext
1:
2:
3:
4:
ulong x = 9999999999999999999, y = 5000000000000000000;
Math.Floor(x / (double)y) = 2
Math.Truncate(x / (double)y) = 2
x / y = 1

Wieso?


Ralf Jansen - Fr 01.06.12 13:41

Für Floor und Truncate nimmst du vorher ein Division mit doubles vor. Bei der anderen Division eine mit ulongs. x hat aber mehr signifikante Stellen als man in einem double darstellen kann und verliert deshalb bei dem cast an Genauigkeit (Faustwert ist das double ungefähr 15 signifikante Stellen hat). Caste mal x direkt nach double und sieh dir den Wert an bzw. lass Truncate und Floor weg und betrachte nur die reine Division mit doubles. Da wird ebenfalls 2 rauskommen.


C#-Quelltext
1:
(double)x / (double)y                    


C# - Fr 01.06.12 14:11

Achso Danke. Verliert double nur wegen der mögichen größe der Kommastellen seine Genauigkeit? ulong hat keine Kommastellen und ist deshalb exakt?


Ralf Jansen - Fr 01.06.12 14:20

Zitat:
Achso Danke. Verliert double nur wegen der mögichen größe der Kommastellen seine Genauigkeit?


Nein. Es geht um signifikante Stellen wo das Komma steht ist egal. 0,0 ..... hundert 0en ... 01 ist darstellbar genauso wie 1 ... hundert nullen ... 0,0 . Würden da jetzt aber nicht eine 1 stehen sondern eine Zahlenfolge unterscheidbar von 0 länger als 15 Ziffern wirst du, Prinzip bedingt, ungenau. Wenn du höhere Genauigkeit willst bei kleinerem Zahlenraum kannst du auf decimal anstatt double ausweichen.

Ansonsten am besten noch mal das Thema Gleitkommazahl [http://de.wikipedia.org/wiki/Gleitkommazahl] zum Beispiel in Wikipedia nachlesen wo die prinzipiellen Problem liegen.