Benutzer mit den meisten Antworten
Mit mehr als 28 Dezimalstellen rechnen

Frage
-
Ich möchte eine Anwendung erstellen, die Wurzeln einer eingegebenen Zahl mit Hilfe des Heron-Verfahrens möglichst genau berechnet. Leider unterstützt der von mir gewählte Datentyp Decimal nur 28 Nachkommastellen. Hat irgendjemand eine Idee, wie ich die Wurzeln genauer berechnen kann?
Hier mein Code:
Dim fehlertext As String = "Lange Wurzel Rechner - Fehler!" Dim tv As Single Dim l As Decimal Dim b As Decimal Dim sq As Decimal Private Sub ButtonLos_Click(sender As Object, e As EventArgs) Handles ButtonLos.Click Try tv = TextBox1.Text / 2 Catch ex As Exception MsgBox("Bitte geben Sie eine Zahl ein!", MsgBoxStyle.Critical, fehlertext) Exit Sub End Try Try sq = TextBox1.Text Catch ex As Exception If TextBox1.Text.StartsWith("-") Then MsgBox("Die eingegebene Zahl ist zu klein. Bitte geben Sie eine Zahl zwischen " & Decimal.MinValue.ToString & " und " & Decimal.MaxValue.ToString & " ein.", MsgBoxStyle.Critical, fehlertext) Else MsgBox("Die eingegebene Zahl ist zu groß. Bitte geben Sie eine Zahl zwischen " & Decimal.MinValue.ToString & " und " & Decimal.MaxValue.ToString & " ein.", MsgBoxStyle.Critical, fehlertext) End If RichTextBox1.Text = "" Exit Sub End Try l = 1 b = sq For i = 0 To 100000 l = (l + b) / 2 b = sq / l Next If NumericUpDown1.Value < 29 Then RichTextBox1.Text = Math.Round(l, CInt(NumericUpDown1.Value), MidpointRounding.AwayFromZero) Else RichTextBox1.Text = l.ToString End If End Sub
Antworten
-
Ähm ja...
die Wurzel aus 2 wirst du nie 100% exakt ermitteln können. Egal mit welchem Datentyp. Du könntest dir höchstens etwas ausdenken, was sich √2 statt 1,41... merkt um exakter rechnen zu können. Die Dezimalausgabe wird allerdings auch nicht anders. Die ganzen .NET Zahlentypen können alle höchstens Rationale Zahlen fassen.Wenn du auf Ganze Zahlen zum speichern setzt dann musst du dir merken an welcher Stelle du dir das Komma vorstellst. Wirklich anders macht .NET das auch nicht. Es wird eine ganze Zahl gespeichert und ein Exponent der angibt um wie viele Stellen das Komma verschoben werden soll (Binär).
Koopakiller [kuːpakɪllɐ] (Tom Lambert)
Webseite |
Code Beispiele |
Facebook |
Twitter |
Snippets
C# ↔ VB.NET Konverter
Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.- Bearbeitet Tom Lambert (Koopakiller)Moderator Montag, 30. Dezember 2013 12:32
- Als Antwort markiert QR-3 Montag, 30. Dezember 2013 15:27
- Tag als Antwort aufgehoben QR-3 Montag, 30. Dezember 2013 15:39
- Als Antwort markiert QR-3 Montag, 30. Dezember 2013 15:39
-
Hallo,
zu 1.
Das ist nicht immer ganz einfach. Angenommen du hast 2 Zahlen: 1.23 und 2.34. Diese möchtest du nun addieren. Als Ganze Zahl könnten diese so aussehen:
1230 und 2340, die letzten 3 Stellen sind die Dezimalstellen. Wenn du nun beide Zahlen addierst und das Komma zurück verschiebst erhälst du das Ergebnis: 3570 > 3.57.
Für die Subtraktion, Multiplikation und Division läuft es genauso ab. Für den Rest wird es schwieriger. Aber mehr brauchst du nicht wirklich. Wenn du doch mal mehr brauchen solltest, vieles lässt sich auf die Exponentialfunktion zurück führen. Diese lässt sich mittels einer Reihenentsicklung berechnen. Für einige andere Dinge gibt es noch andere Entwicklungsmöglichkeiten. Wikipedia ist für diese Formeln ein ziehmlich allumfassender Anlaufpunkt mit vielen Ansätzen.
zu 2.
Du musst noch einen Verweis auf System.Numerics setzen. Mache dazu im Projektmappen Explorer einen Rechtsklick auf Verweise und wähle Verweis hinzufügen... Dort wählst du anschließend System.Numerics aus.Koopakiller [kuːpakɪllɐ] (Tom Lambert)
Webseite |
Code Beispiele |
Facebook |
Twitter |
Snippets
C# ↔ VB.NET Konverter
Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.- Als Antwort markiert QR-3 Freitag, 10. Januar 2014 15:44
Alle Antworten
-
Hallo,
das Standard .NET-Framework unterstützt keine genaueren Typen für Dezimalzahlen. Es gibt aber 3 andere Möglichkeiten:- Unter den BCL-Klassen auf CodePlex befindet sich auch eine BigRational-Klasse:
https://bcl.codeplex.com/wikipage?title=BigRational&referringTitle=Home
Mit dieser kannst du Zahlen, in einem Bruch darstellen. - Du benutzt die BigInteger-Struktur und legst eine feste Anzahl an Stellen fest, welche nach dem Komma stehen.
- Du suchst dir einen thirdparty Hersteller einer solchen Klasse.
Koopakiller [kuːpakɪllɐ] (Tom Lambert)
Webseite |
Code Beispiele |
Facebook |
Twitter |
Snippets
C# ↔ VB.NET Konverter
Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke. - Unter den BCL-Klassen auf CodePlex befindet sich auch eine BigRational-Klasse:
-
Ähm ja...
die Wurzel aus 2 wirst du nie 100% exakt ermitteln können. Egal mit welchem Datentyp. Du könntest dir höchstens etwas ausdenken, was sich √2 statt 1,41... merkt um exakter rechnen zu können. Die Dezimalausgabe wird allerdings auch nicht anders. Die ganzen .NET Zahlentypen können alle höchstens Rationale Zahlen fassen.Wenn du auf Ganze Zahlen zum speichern setzt dann musst du dir merken an welcher Stelle du dir das Komma vorstellst. Wirklich anders macht .NET das auch nicht. Es wird eine ganze Zahl gespeichert und ein Exponent der angibt um wie viele Stellen das Komma verschoben werden soll (Binär).
Koopakiller [kuːpakɪllɐ] (Tom Lambert)
Webseite |
Code Beispiele |
Facebook |
Twitter |
Snippets
C# ↔ VB.NET Konverter
Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.- Bearbeitet Tom Lambert (Koopakiller)Moderator Montag, 30. Dezember 2013 12:32
- Als Antwort markiert QR-3 Montag, 30. Dezember 2013 15:27
- Tag als Antwort aufgehoben QR-3 Montag, 30. Dezember 2013 15:39
- Als Antwort markiert QR-3 Montag, 30. Dezember 2013 15:39
-
Ich glaube ich habe das Prinzip verstanden. Mir ist klar, wie ich die Zahlen sehr genau speichern kann.
- Ich verstehe aber nicht, wie ich mit diesen Zahle rechnen kann.
- Ich kann nicht mit der BigInteger-Struktur arbeiten. Wenn ich System.Numerics.BigInteger aufrufe, wird die Fehlermeldung "Der Typ 'System.Numerics.BigInteger' ist nicht definiert." ausgegeben.
QR-3
P.S. Ich bin die nächste Woche abwesend und werde deshalb solange wahrscheinlich nicht antworten.
-
Hallo,
zu 1.
Das ist nicht immer ganz einfach. Angenommen du hast 2 Zahlen: 1.23 und 2.34. Diese möchtest du nun addieren. Als Ganze Zahl könnten diese so aussehen:
1230 und 2340, die letzten 3 Stellen sind die Dezimalstellen. Wenn du nun beide Zahlen addierst und das Komma zurück verschiebst erhälst du das Ergebnis: 3570 > 3.57.
Für die Subtraktion, Multiplikation und Division läuft es genauso ab. Für den Rest wird es schwieriger. Aber mehr brauchst du nicht wirklich. Wenn du doch mal mehr brauchen solltest, vieles lässt sich auf die Exponentialfunktion zurück führen. Diese lässt sich mittels einer Reihenentsicklung berechnen. Für einige andere Dinge gibt es noch andere Entwicklungsmöglichkeiten. Wikipedia ist für diese Formeln ein ziehmlich allumfassender Anlaufpunkt mit vielen Ansätzen.
zu 2.
Du musst noch einen Verweis auf System.Numerics setzen. Mache dazu im Projektmappen Explorer einen Rechtsklick auf Verweise und wähle Verweis hinzufügen... Dort wählst du anschließend System.Numerics aus.Koopakiller [kuːpakɪllɐ] (Tom Lambert)
Webseite |
Code Beispiele |
Facebook |
Twitter |
Snippets
C# ↔ VB.NET Konverter
Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.- Als Antwort markiert QR-3 Freitag, 10. Januar 2014 15:44
-
Gut, dass mit den Biginteger-Variablen funktioniert.
Allerdings habe ich immer noch Probleme mit der Rechnerei. Die Ergebnissestimmen von den Zahlen her nicht und das Komma wird immer an der falschen Stelle eingefügt.
Hier mein Code:
Imports System.Math Imports System.Numerics Public Class Form1 Dim summeb As BigInteger Function Summe(ByVal summ1 As BigInteger, ByVal summ2 As BigInteger, ByVal summ1e As BigInteger, ByVal summ2e As BigInteger) If summ1.ToString.Length = summ2.ToString.Length Then summeb = summ1 + summ2 Else If summ1.ToString.Length > summ2.ToString.Length Then Dim dif = summ1.ToString.Length - summ2.ToString.Length For i = 0 To dif summ2 = summ2.ToString & 0 summ2e = summ2e + 1 Next summeb = summ1 + summ2 Else Dim dif = summ2.ToString.Length - summ1.ToString.Length For i = 0 To dif summ1 = summ1.ToString & 0 summ1e = summ1e + 1 Next summeb = summ2 + summ1 End If End If le = summ1e be = summ2e Return summeb End Function Dim quotientb As BigInteger Function Quotient2(ByVal quotient1 As BigInteger, ByVal quotient1e As BigInteger) quotient1 = quotient1.ToString & 0 quotient1e = quotient1e + 1 quotientb = quotient1 / 2 le = quotient1e Return quotientb End Function Dim fehlertext As String = "Lange Wurzel Rechner - Fehler!" Dim tv As Single Public l, b, le, be As BigInteger Private Sub ButtonLos_Click(sender As Object, e As EventArgs) Handles ButtonLos.Click Try tv = TextBox1.Text / 2 Catch ex As Exception MsgBox("Bitte geben Sie eine Zahl ein!", MsgBoxStyle.Critical, fehlertext) Exit Sub End Try Try tv = TextBox1.Text Catch ex As Exception If TextBox1.Text.StartsWith("-") Then MsgBox("Die eingegebene Zahl ist zu klein. Bitte geben Sie eine Zahl zwischen " & Decimal.MinValue.ToString & " und " & Decimal.MaxValue.ToString & " ein.", MsgBoxStyle.Critical, fehlertext) Else MsgBox("Die eingegebene Zahl ist zu groß. Bitte geben Sie eine Zahl zwischen " & Decimal.MinValue.ToString & " und " & Decimal.MaxValue.ToString & " ein.", MsgBoxStyle.Critical, fehlertext) End If RichTextBox1.Text = "" Exit Sub End Try l = 1 le = 0 b = tv.ToString.Split(",").First & tv.ToString.Split(",").Last be = tv.ToString.Split(",").Last.Length For i = 0 To NumericUpDown1.Value * 3 + 100 l = Quotient2(Summe(l, b, le, be), le) Next RichTextBox1.Text = l.ToString.Remove(l.ToString.Length - le) & "," & l.ToString.Remove(0, le) End Sub End Class
Wenn Wurzel 2 berechnet werden soll, bekomme ich als Ausgabe "1157894736842101207999218959208483536355633026972108967456303303817435268629075481987058544503511564039,5802373903001989611350202932333449605749106881761428307144589983401672102923987452781843775821229064192".
Diese Zahl müsste aber mit 1(,)4142... anfangen.Findet jemand den Fehler?
- Bearbeitet QR-3 Freitag, 10. Januar 2014 15:45
-
Ich helfe dir gerne, wenn du einen ansatzweise ordentlichen Programmierstil verwendest. Schreibe Option Strict On in die erste Zeile und korrigiere alle Fehler. Dann kannst du dir wenigstens sicher sein das du die Werte auch richtig umgewandelt hast.
Um beispielsweise mit 10 zu multiplizieren ist folgendes ungeeignet:
quotient1 = quotient1.ToString & 0
wie folgt wäre es besser:
quotient1 *= 10
Dann kann ich dir nur empfehlen, dich ans Debuggen zu gewöhnen. Einfach Zeile für Zeile (F11) den Quellcode ausführen und die Werte mitrechnen (Auf die Variablen zeigen um deren Werte zu erhalten).
Ich weiß von was ich rede, man braucht Teilweise ewig um einen Fehler zu finden, aber so kam ich bisher am schnellsten vorran.
Koopakiller [kuːpakɪllɐ] (Tom Lambert)
Webseite |
Code Beispiele |
Facebook |
Twitter |
Snippets
C# ↔ VB.NET Konverter
Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke. -
Ich habe Option Strict On hinzugefügt und die Fehler wie von VS vorgeschlagen verbessert. Das Debuggen bekomme ich aber nicht hin. Wenn ich F11 drücke bekomme ich folgende Meldung:
und das Programm wird ganz normal ausgeführt.
Die Ausgabe bei der Berechnung einer Wurzel ist die selbe geblieben - mit den gleichen Fehlern.- Bearbeitet QR-3 Samstag, 11. Januar 2014 08:43
-
Gut das du es korrigiert hast ;)
Die Meldung sagt aus, das Eigenschaften nicht debuggt werden.
Gehe mal an den Anfang der Methode, wo die Berechnung beginnt. Dort drückst du F9. Dadurch wird ein Haltepunkt erzeugt, welcher den Quellcode wärend der Ausführung anhält. Ab dort kannst du dann mit F11 weiter machen.Selbst nach der Meldung sollte der Debugger eigentlich bei F11 stehen bleiben. Wenn du eine Eigenschaft haben solltest, welche du debuggen willst, gehe in diese und setze dort deinen Heltepunkt.
Wenn du noch Hilfe brauchst, poste bitte deinen überarbeiteten Code.
Koopakiller [kuːpakɪllɐ] (Tom Lambert)
Webseite |
Code Beispiele |
Facebook |
Twitter |
Snippets
C# ↔ VB.NET Konverter
Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke. -
Das Debuggen funzt! :) Ich finde es aber sehr verwirrend und finde auch keinen Fehler... :(
Hier mein Code:
Option Strict On Imports System.Numerics Public Class Form1 Dim summeb As BigInteger Function Summe(ByVal summ1 As BigInteger, ByVal summ2 As BigInteger, ByVal summ1e As BigInteger, ByVal summ2e As BigInteger) As BigInteger If summ1.ToString.Length = summ2.ToString.Length Then summeb = summ1 + summ2 Else If summ1.ToString.Length > summ2.ToString.Length Then Dim dif = summ1.ToString.Length - summ2.ToString.Length For i = 0 To dif summ2 *= 10 summ2e += 1 Next summeb = summ1 + summ2 Else Dim dif = summ2.ToString.Length - summ1.ToString.Length For i = 0 To dif summ1 *= 10 summ1e += 1 Next summeb = summ2 + summ1 End If End If le = summ1e be = summ2e Return summeb End Function Dim quotientb As BigInteger Function Quotient2(ByVal quotient1 As BigInteger, ByVal quotient1e As BigInteger) As BigInteger quotient1 *= 10 quotient1e += 1 quotientb = quotient1 / 2 le = quotient1e Return quotientb End Function Dim fehlertext As String = "Lange Wurzel Rechner - Fehler!" Dim tv As Single Public l, b, le, be As BigInteger Private Sub ButtonLos_Click(sender As Object, e As EventArgs) Handles ButtonLos.Click Try tv = CSng(CDbl(TextBox1.Text) / 2) Catch ex As Exception MsgBox("Bitte geben Sie eine Zahl ein!", MsgBoxStyle.Critical, fehlertext) Exit Sub End Try Try tv = CSng(TextBox1.Text) Catch ex As Exception If TextBox1.Text.StartsWith("-") Then MsgBox("Die eingegebene Zahl ist zu klein. Bitte geben Sie eine Zahl zwischen " & Decimal.MinValue.ToString & " und " & Decimal.MaxValue.ToString & " ein.", MsgBoxStyle.Critical, fehlertext) Else MsgBox("Die eingegebene Zahl ist zu groß. Bitte geben Sie eine Zahl zwischen " & Decimal.MinValue.ToString & " und " & Decimal.MaxValue.ToString & " ein.", MsgBoxStyle.Critical, fehlertext) End If RichTextBox1.Text = "" Exit Sub End Try l = 1 le = 0 b = CType(tv.ToString.Split(CChar(",")).First & tv.ToString.Split(CChar(",")).Last, BigInteger) be = tv.ToString.Split(CChar(",")).Last.Length For i = 0 To NumericUpDown1.Value * 3 + 100 l = Quotient2(Summe(l, b, le, be), le) Next RichTextBox1.Text = l.ToString.Remove(CInt(l.ToString.Length - le)) & "," & l.ToString.Remove(0, CInt(le)) End Sub End Class
-
Hi
If summ1.ToString.Length = summ2.ToString.Length Then
vergleicht die Länger 2er Sting wobei 100 genau so lang(3) ist wie 999 ohne jetzt die BigInterger Struktur da einzubeziehen.
Da deine Methode ja Summe heist. Geh ich jetzt davon aus das zu die Zahlen addieren willst. Hierfür gibt es die Add Methode, der Struktur.
MFG
Björn -
Dein Code enthält noch Fehler. Von einfachen wie:
Du wandelst mit CSng einen String in einen Single um. Im Fehlerfall gibst du aber die Minimal- und Maximalwerte von Decimal.
Bis hin zu Syntakteischen Dingen, die ich nicht nachvollziehen kann. Stelle einen Plan auf, was du wie abändern musst. Versuche es zu begreifen, wie der Computer es bei Gleitkommazahlen macht. So musst du es auch tun.Der Code aus deiner Frage hat ja anscheinend funktioniert. Schreibe dir einfach eine Klasse, welche einen rationalen Typen nach macht und die Rechenoperationen übernimmt. Du kannst natürlich auch die BCL-Klasse BigRational verwenden.
Sicher ist es nicht es nicht leicht und man verzweifelt schnell an solchen Dingen. Aber mir fehlt die Zeit deinen Code umzuschreiben, zumal es dir nichts bringen würde.
Koopakiller [kuːpakɪllɐ] (Tom Lambert)
Webseite |
Code Beispiele |
Facebook |
Twitter |
Snippets
C# ↔ VB.NET Konverter
Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.