Nächsten Bruch errechnen?

meilon

Erfahrenes Mitglied
Halli Hallo!

Ich schreibe ein Programm, welches am Ende nicht nur Dezimalzahlen anzeigen soll, sondern auch Brüche.

Wegen dem Datentyp kann ich keine dirketen Brüche speichern. Wie kann ich den nächsten Bruch errechnen?

Sagen wir mal, wir teilen 1 durch 7, da kommt dann 0,14285714285714285714285714285714 mit dem Windows Taschenrechner raus. Dieser Wert wäre jetzt mit der dem Datentyp entsprechender Genauigkeit (sagen wir mal Double aus C# (15 stellige Genauigkeit)) im Programmspeicher. Dann würde in der Variable 1,428571428571428 * 10 -1 stehen.

Wie macht man daraus wieder 1/7

-meilon
 
Verschiedene Vorhgehensweisen.

Entweder iterierst Du Dich annäherungsweise an den Bruch heran (eine wunderbar simple Rekursion) oder aber Du benutzt Dein Wissen um Gleitkommazahlberechnung (http://de.wikipedia.org/wiki/Gleitkommazahl) und exterapolierst Mantisse und Exponent und behandelst Sie entsprechend ihrer Werte.

Alternativ kannst Du Dich ja mal an Mathematik verssuchen:

m/n = a

wenn Du 1/7 = 0,14285714285714285714285714285714 hast, dann ist

1/7 = 14285714285714285714285714285714/100000000000000000000000000000000 (10^15)
Das Kürzen bis zum Ende und schon hast Du Deinen Bruch.

Da die Gleitkommaberchnung im Rechner aber nur bedingt genau ist, würde ich die erste Variante wählen oder aber die letzte mit ein wenig Fuzzy-Logic berechnen.

Letztendlich wirst Du aber nicht in jedem Fall auf den Ursprungsbruch zurückkommen, denn die Darstellung der Gleitkommazahlen mit hinreichend großen Nachkommastellen wird zunehmend "ungenauer".
 
Ich würde dir empfehlen, eine eigene Klasse zu schreiben.


Code:
class TBruchzahl (Tobject) {
  var  
    zaehler: float;
    nenner: float;
  procedure 
    kuerzen;
    usw..
}
(ist nur ein in kurzer Zeit hingeschmierter Pseudocode)

Jede Zahl deines Rechners wird in einen Bruch gepackt (Ganzzahlen einfach mit dem neutralen Nenner "1" ) und du musst dann nurnoch Funktionen zur Addition, Multiplikation etc. schreiben.
Wurde eine Zahl errechnet soll sie sich selber Kürzen und schon hast du dein Ergebnis.

MFG
Van

Edit: Achso, du solltest dir dann nur noch überlegen, wie du einen Bruch darstellst. Hast du nur ein klassisches "Editfeld" musst du das anders handhaben, als wenn du z.b. eine HTML-Oberfläche hast in der du das ganze durch eine "kleine Tabelle" darstellen lässt.
 
Zuletzt bearbeitet:
Hiho!
Also mir ist da auch noch was eingefallen, was weniger mit dem Rechnen selbst zu tun hat:

Ich nehme den bereits errechneten Wert als String, nehme die ersten 5 Zahlen (oder weniger würde auch schon reichen) nach dem Komma und Vergleiche sie mit den Anfängen von bekannten Brüchen. Vll. eine Schleife, könnte aber zur Endlosschleife werden.

Oder noch was: Vordefinierte Bereiche, wie 1/4 = 0,25, 1/5 = 0,2, wenn der Wert jetzt näher an 0,2 liegt, schreib ich 1/5 hin, näher an 0,25, dann 1/5. Dass das nicht genau ist, ist mir klar, gefällt dem User aber sicher besser, wenn ich ihm dort ? 1/4 hinschreibe als = 31345/124873, oder?

-meilon
 
Mach es auf die richtige Art:

Berechnung von:
0,71428571428571428571428571428571

1 x 2^(-1) (rest 0,21428571428571428571428571428571)
0 x 2^(-2)
1 x 2^(-3) (rest 0,089285714285714285714285714285714)
1 x 2^(-4) (rest 0,026785714285714285714285714285714)
0 x 2^(-5)
1 x 2^(-6) (rest 0,011160714285714285714285714285714)
1 x 2^(-7) (rest 0,0033482142857142857142857142857143)
0 x 2^(-8)
1 x 2^(-9) (rest 0,0013950892857142857142857142857143)
1 x 2(^-10) (rest 0,000418526785714285714285714285)

usw...

dann hast Du mit n Iterationsschritten näherungsweise
1/2+1/8+1/16+1/64+1/128+1/512+1/1024+...+1/(2^n) ~ 0,71428571428571428571428571428571

(btw: Ich habe hier 3/7 gewählt)

Wie Du siehst kann man diesem Problem nur näherungsweise beikommen.

Sehr gut zu lösen über Rekursion einen kleinen Stack zum Zwischenspeichern der in Frage kommenden Exponenten.

Da braucht man auch keine eigene Klasse oder sonstwas, denn das hat mit dem Problem rein gar nichts zu tun, sondern beschreibt einfach nur das spätere Handling mit dem fertigen Problem im Kontext des Programmes.
 
Hallo!

Mach es auf die richtige Art:
... es gibt zwar mehrere Arten das gewünschte zu vollbringen, aber ich finde das die Vorgehensweise im obigen Link:
Java:
 /**
     * Create a fraction given the double value.
     * @param value the double value to convert to a fraction.
     * @throws ConvergenceException if the continued fraction failed to
     *         converge.
     */
    public Fraction(double value) throws ConvergenceException {
        this(value, 1.0e-5, 100);
    }
...
    /**
     * Create a fraction given the double value.
     * <p>
     * References:
     * <ul>
     * <li><a href="http://mathworld.wolfram.com/ContinuedFraction.html">
     * Continued Fraction</a> equations (11) and (22)-(26)</li>
     * </ul>
     * </p>
     * @param value the double value to convert to a fraction.
     * @param epsilon maximum error allowed.  The resulting fraction is within
     *        <code>epsilon</code> of <code>value</code>, in absolute terms.
     * @param maxIterations maximum number of convergents
     * @throws ConvergenceException if the continued fraction failed to
     *         converge.
     */
    public Fraction(double value, double epsilon, int maxIterations)
        throws ConvergenceException
    {
...
1) richtig ist ;-)
und
2) einfacher zu Implementieren (nachzubauen) als den Weg den du beschreibst...

Beispiel:
Java:
/**
 * 
 */
package de.tutorials;

import org.apache.commons.math.fraction.Fraction;

/**
 * @author Thomas.Darimont
 *
 */
public class FractionTest {

  /**
   * @param args
   */
  public static void main(String[] args) throws Exception{
    double threeDividedBySeven = 3.0/7.0;
    Fraction fraction = new Fraction(threeDividedBySeven);
    System.out.println(fraction.getNumerator() +"/"+fraction.getDenominator());
  }

}
Ausgabe:
Code:
3/7

Gruß Tom
 
Heya, danke! Werde dann mal bei C# schaun, ob es die Funktion schon gibt, ansonsten ist es ja ein leichtes, den Code zu kopieren!

mfg
 
> 1) richtig ist ;-)

Das ist auch "nur" das einfache Konvergenzverfahren.

> und
> 2) einfacher zu Implementieren (nachzubauen) als den Weg den du beschreibst...

Huh?

Was genau ist schwer an:
Code:
proc frac(float value, int exponent, int max)
{
  if exponent <= max or value != 0
  {
    float temp = value - (1/expo(2, exponent))
    if temp >= 0 
    {
      insertintostack(exponent)
      frac(temp, exponent+1, max)
    }
    else
    {
      frac{value, exponent+1, max)
    }
  }
}

Einen Stack zu setzen ist einfach (notfalls macht man das über ein Array) und die Addition von Exponentialzahlen ist auch trivial.

Im übrigen ist diese Vorgehensweise fast genau die, mit der ein Bruch im TR berechnet wird...

BTW: Eigentlich halte ich ja nicht viel davon jemand einfach ein Stück Code hinzuwerfen, dann lernt das Gegenüber nur schwer von einer Idee zur Implementation.
 
Hallo!

Das ist auch "nur" das einfache Konvergenzverfahren.
Na und? Die Werte sind doch (innerhalb der geforderten Genauigkeit) richtig. Was spricht denn deiner Meinung nach gegen dieses Konvergenzverfahren?

> und
> 2) einfacher zu Implementieren (nachzubauen) als den Weg den du beschreibst...

Huh?

Was genau ist schwer an:
Meinte das ganz pragmatisch ;-) Das genannte Verfahren ist im Link erklärt und man hat noch ne Implementierung dazu.

BTW: Eigentlich halte ich ja nicht viel davon jemand einfach ein Stück Code hinzuwerfen, dann lernt das Gegenüber nur schwer von einer Idee zur Implementation.
Na ja, ich denke beides ist wichtig. Erstmal ein Stück COde zum herumspielen und ausprobieren, anschließend kann man
das dann analysieren. ( Was Meilon, ja ganz bestimmt machen wird ;-) )

Also immer schön die Füße still halten ;-)

Gruß Tom
 

Neue Beiträge

Zurück