Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

14.07.2013, 18:15

C# Float Werte ungenau

Hallo Leute,
ich habe gerade in C# ein Programm geschrieben, welches bei Knopfdruck den Wert von einer Variablen um 0,1 erhöht. Als das Programm fertig war habe ich dann auf den Button mehrmals gedrückt und bis 0,7 funktioniert alles noch wunderbar aber ab 0,8 zeigt er anstatt 0,8 - 0,80000001 an und später verrechnet er sich wieder. Warum ist das so?

Quelltext:

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
42
43
44
45
46
47
48
49
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GültigkeitsbereichÜbung
{
    public partial class GültigkeitsbereichÜbung : Form
    {
        // Variablen
        float fx = 0.0f;

        public GültigkeitsbereichÜbung()
        {
            InitializeComponent();
        }

        private void cmdAnzeigen1_Click(object sender, EventArgs e)
        {
            // Variablen
            float fy = 0.0f;

            // Werte um 0,1 erhöhen
            fx = fx + 0.1f;
            fy = fy + 0.1f;

            // Werte ausgeben
            lblAnzeige.Text = "X: " + fx + "\nY: " + fy;
        }

        private void cmdAnzeige2_Click(object sender, EventArgs e)
        {
            // Variablen
            float fz = 0.0f;

            // Werte um 0,1 erhöhen
            fz = fz + 0.1f;
            fx = fx + 0.1f;

            // Werte ausgeben
            lblAnzeige.Text = "X: " + fx + "\nZ: " + fz;
        }
    }
}

Sylence

Community-Fossil

Beiträge: 1 663

Beruf: Softwareentwickler

  • Private Nachricht senden

2

14.07.2013, 18:23

Guck dir einfach mal an wie eine Kommazahl im Computer dargestellt wird.

Und dann überleg mal, wie du 0,1 in Binär darstellen willst. Da hast du das gleiche Problem, wie 1/3 als Dezimalzahl darzustellen.

3

14.07.2013, 19:16

Stichwort IEEE 754 ;)

MitgliedXYZ

Alter Hase

Beiträge: 1 369

Wohnort: Bayern

  • Private Nachricht senden

4

14.07.2013, 19:33

Aber was mich wundert:

Zitat

Ungültigkeit der Assoziativ- und Distributivgesetze
Die Addition und die Multiplikation von Gleitkommazahlen ist nicht assoziativ, das heißt im Allgemeinen gilt:
<ul);" color: rgb(0, 0, 0); font-family: sans-serif; font-size: 12.499999046325684px; background-color: rgb(255, 255, 255);">[*]

(Link)
[*]

(Link)
Die Addition und Multiplikation von Gleitkommazahlen ist auch nicht distributiv, das heißt im Allgemeinen gilt:
<ul);" color: rgb(0, 0, 0); font-family: sans-serif; font-size: 12.499999046325684px; background-color: rgb(255, 255, 255);">[*]

(Link)
[*]

(Link)
(Wikipedia.de)


Das klingt irgendwie sehr unlogisch. Warum ist das so?

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

5

14.07.2013, 19:41

Eben wegen der endlichen Genauigkeit.

6

14.07.2013, 20:53

Alle Werte werden intern im Rechner im IEEE 754 Format umgewandelt. Dieses Format gibt es in 2 Varianten:
- einfache Genauigkeit
- doppelte Genauigkeit

Das Format besteht im wesentlichen aus 3 Komponenten:

- Vorzeichen
- Mantisse
- Exponent

Nun, der Fehler, den du beobachtest ereignet sich genau in diesem Format, oder genauer gesagt: In der Mantisse.
Wenn du jetzt Beispielsweise 0,1 aus unserem System in IEEE 754 zur Basis 2 umwandeln willst wirst du feststellen,
dass die 0,1 im Dualsystem eine Periode besitzt. Genau solch eine Periode erscheint auch in der Mantisse.
Da IEEE 754 aber in der Darstellung begrenzt ist, wird von dieser Periode hinten etwas "abgeschnitten" damit die
Zahlenfolge ins Raster passt (untere Schranke, obere Schranke).
Deswegen ist es auch nicht ratsam längere Nachkommastellen zu benutzen, da sonst die ganze Umwandlung verfälscht ist.
Hierfür muss man dann entweder spezielle Datentypen benutzen oder sich selber einen basteln bzw Funktionen dafür erfinden.

Ich hoffe dir jetzt etwas nachgeholfen zu haben. :)

Legend

Alter Hase

Beiträge: 731

Beruf: Softwareentwickler

  • Private Nachricht senden

7

14.07.2013, 20:57

Mein lineare Algebra-Prof hatte damals über seine ersten Programme mit C++ erzählt und meinte Sinngemäß und dann wollte ich mit reelen Zahlen rechnen, aber das kann das arme C++ ja gar nicht. Und wenn man es ganz genau nimmt hat er durchaus recht damit. Float als auch Double sind, wie nun schon oft erwähnt, nur Annäherungen mit endlicher Genauigkeit.
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

Netzwerkbibliothek von mir, C#, LGPL: https://sourceforge.net/projects/statetransmitt/

TGGC

1x Rätselkönig

Beiträge: 1 799

Beruf: Software Entwickler

  • Private Nachricht senden

8

14.07.2013, 22:56

Aber was mich wundert:

Zitat

Ungültigkeit der Assoziativ- und Distributivgesetze
Die Addition und die Multiplikation von Gleitkommazahlen ist nicht assoziativ, das heißt im Allgemeinen gilt:
<ul);" color: rgb(0, 0, 0); font-family: sans-serif; font-size: 12.499999046325684px; background-color: rgb(255, 255, 255);">[*]

(Link)
[*]

(Link)
Die Addition und Multiplikation von Gleitkommazahlen ist auch nicht distributiv, das heißt im Allgemeinen gilt:
<ul);" color: rgb(0, 0, 0); font-family: sans-serif; font-size: 12.499999046325684px; background-color: rgb(255, 255, 255);">[*]

(Link)
[*]

(Link)
(Wikipedia.de)


Das klingt irgendwie sehr unlogisch. Warum ist das so?
Weil es nur eine begrenzte Anzahl signifikanter Stellen gibt. Sagen wir der Einfachheit halber 3 Stellen. Wenn du also als Beispiel die Zahl 101011 abspeicherst, wird daraus auf die naechste Zahl mit 3 signifikanten Zahlen gerundet 101000. Addierst du nun z.b. 101000 + 11 ergibt dies also 101000. Daher ist also auch 101000 + 11 + 11 = 101000. Machst du aber 101000 + (11 + 11) = 101000 + 110 = 101110 nach dem Runden also 110000. Also doch sehr logisch, oder?

MitgliedXYZ

Alter Hase

Beiträge: 1 369

Wohnort: Bayern

  • Private Nachricht senden

9

15.07.2013, 16:24

Weil es nur eine begrenzte Anzahl signifikanter Stellen gibt. Sagen wir der Einfachheit halber 3 Stellen. Wenn du also als Beispiel die Zahl 101011 abspeicherst, wird daraus auf die naechste Zahl mit 3 signifikanten Zahlen gerundet 101000. Addierst du nun z.b. 101000 + 11 ergibt dies also 101000. Daher ist also auch 101000 + 11 + 11 = 101000. Machst du aber 101000 + (11 + 11) = 101000 + 110 = 101110 nach dem Runden also 110000. Also doch sehr logisch, oder?
Danke für die Erklärung, aber ist das von mir oben Fettgedruckte ein Tippfehler, oder wie meinst du das?
101000 + 11 muss doch eigentlich 101011 und nicht 101000 ergeben
und
101000 + 11 + 11 ist doch 101110 und nicht 101000?

Oder ist das so eine eigenheit wenn man Binärzahlen rundet?

Sylence

Community-Fossil

Beiträge: 1 663

Beruf: Softwareentwickler

  • Private Nachricht senden

10

15.07.2013, 16:41

Er sprach von 3 signifikanten Stellen.

1,105 + 0,0001 ist auch auch 1,105 wenn du nur 3 Nachkommastellen hast.

Werbeanzeige