Kommazahl in Bruch umrechnen

Gast #274855
Lesenswert?

Ich habe eine Gleitkommazahl und möchte daraus einen Bruch erstellen.
Da es durchaus vorkommen kann, dass des keinen exakten Bruch gibt,
möchte ich den bestmöglichen Bruch verwenden.
Wie kann man diesen ermitteln, ohne alle möglichen Kombinationen
durchspielen zu müssen ?
Konkret geht es um eine PLL. Ich gebe die gewünschte Ausgangsfrequenz
vor, und der uC (ein kleiner AVR) soll daraus die Werte für den PLL
bestimmen:
f=(2 x 14.31818MHz x P/Q)/D
Gast #274856
Lesenswert?

Am einfachsten geht es binaer - genau so, wie es selbst im Rechner
umgerechnet wird, also 0.5 ist 1/2, 0.25 - 1/4, 0.125 - 1/8 und so
weiter. Wenn man so macht, dann kriegt man aus 0.7 0.1011....
Es ist doch klar, das es ein Bruch sein sollte (1/2 + 1/8 + 1/16 z.B. =
11/16). Ich glaube, dass man den Algorithmus aus dem GCC nehmen koennte.
Gast #274858
Lesenswert?

Sind das getrennt einstellbare Referenz - und Oszillatorteiler? Dann
gibt es vermutlich eine sehr große Zahl von möglichen Quotienten, die
der gewünschten Frequenz nahekommen - ich fürchte, dafür gibt es keine
geschlossene Lösung. ich hatte auch schon mal das Problem, eine
Siemens-PLL auf möglich kleine Schrittweite bei gegebenem Referenzquarz
einzustellen, und habe am Schluß eine Tabelle in ein Eprom geschrieben,
anders ging es nicht.
ein ähnliches Problem - eine Tabelle aller mit den Widerständen der E24
oder E96-Reihe möglichen Quotienten aufsteigend sortiert - ist auch nur
mit Berechnen und anschließendem Sortieren möglich
Gast #274859
Lesenswert?

Hm... also bei Float ist es schwer, aber wenn du dich auf eine
Fixkommastelle einigen kannst ginge es so:

12.09875 = 1209875/100000

Das kanst du dan noch versuchen gegen zu kürzen in diesem Falle z.B.
mit 5 wenn du das mit den ersten 10 Zahlen versuchst solltest du schon
auf einen einigermassen guten Bruch kommen

(0.24 ist z.b. 24/100 ist durch 2 kürzbar: 12/50 ist durch 2 kürzbar =
6/25 ist nicht kürzbar durch 2, 3, 4, 5 ... also zu ende gekürzt)

Ist natürlich etwas aufwand in enr Schleife aber sollte schafbar sein.
Gast #274860
Lesenswert?

@Läubi,

netter Einfall! Ich denke das kann noch vereinfacht werden. Da Du immer
Zehnerpotenzen nimmst, kann das kürzen noch wie folgt gemacht werden:

10=2*5  100=10^2=(2*5)^2   usw.

d.h. Du brauchst nur durch zwei und fünf dividieren. Voila.

Allerdings hat die Sache einen Haken: sowas wie bsp. 22/7 für PI wird
dabei nicht rauskommen, da die "probierten" Teiler vielfache von 2
und/oder fünf sind.


Gruß
Mario
Gast #274861
Lesenswert?

> Ich habe eine Gleitkommazahl und möchte daraus einen Bruch
> erstellen. Da es durchaus vorkommen kann, dass des keinen
> exakten Bruch gibt,

In Mathe wohl nicht aufgepasst?

Wie ist denn eine Rationale Zahl definiert? Doch nicht etwa als Bruch
aus einer ganzen Zahl und einer natürlichen Zahl?!?!

Naja, und den Bruch hast Du in Deiner Gleitkommadarstellung ja schon,
nämlich die Mantisse.

Was genau ist eigentlich Dein Problem? Was willst Du überhaupt
berechnen?
Gast #274863
Lesenswert?

Hm... ja ich denke das läßt sich noch optimieren, aber das sit u.A. ne
gute möglichkeit im Kopf Brüche auszurechnen, aber es gibt bestimmt
auch nen Anderen/Einfachen Algorithmus, weil jeder Billig
Taschenrechner kann ja heutzutage sowas relativ gut.

Also erzähl doch mal was genau du vor hast, eventuell läßt sich das
ganze sogar einfacher mit einer Tabelle lösen?
Gast #274864
Lesenswert?

Hier mal ein konkretes Beispiel:
P/Q=2,7587

Mach ich es mal nach dem Läubi Verfahren:
2,7587=27587/10000
Das ganze kann man durch 5 teilen:
P/Q=5157/2000
weiter geht nichts.
Da P und Q aber 7bit Zahlen sind geht es so nicht.

Wenn ich das nach dem Binärverfahren mache, dann bekomme ich doch nur
1,2,4,8,16,32,64 für den Nenner, oder ?
In diesem Beispiel wären das 2+1/2+1/4+1/128+1/2048
Addiere ich das auf, komme ich auf 11/4=2,75. Das ist ziemlich weit vom
gewünschten Wert weg...

Auf eine Tabelle möchte ich verzichten, da ich am Ende eine beliebige
Frequenz eingebe, und der PLL diese so genau wie möglich erzeugen
soll.

Wenn ich das nach dem Try&Error Prinzip mache, also mit Q=1 und P=1
anfange und alles solange erhöhe bis ich bei 127 und 127 angekommen
bin, und mir die Kombination mit dem kleinsten Fehler merke  brauche
ich 16384 möglichkeiten. Wenn ich von ms für eine float Berechnung
ausgehe, dann dauert es über 10s und das ist eindeutig zu lange.

Macht mal Vorschläge, mal schauen wer am nähesten an die 2,7587 ran
kommt...
Gast #274865
Lesenswert?

mit 7 bit wirst du da fürchte ich dann nicht weit kommen, und 2,75 ist
dch shcon recht nah an 2,7587 wie genau muß den das ganze sein?
Ich meine du kanst ja sogar die Tests einschränken, wenn du es
interativ verwendest, weil z.b. wenn die Zahl > 1 ist mußt du ja Zahlen
die sowieso Zahlen ergeben die immer kleiner 1 sind (also z.b. 1 / 7 ist
immer < 1 muß also garnicht ausprobiert werden).

for (i=1;i<127;i++) {
 for (j=1;j<127;j++) {
  if (i>j) teste
 }
}

Oder du benuzt die Binärmethode und gehst von dort aus:
Wenn der Fehler kleiner geht -> Mache weiter, wenn der fehler größer
wird -> abbrechen
Gast #274866
Lesenswert?

Hallo Benedikt,

nimm P/Q=80/29, stimmt glaub ich ganz gut (2,7586206896551726) :).

Ich hab das noch im Hinterkopf gehabt, das es sowas gibt:
Lösung Kettenbrüche.

Da kannst Du das online machen.
http://www.arndt-bruenner.de/mathe/scripts/bruchrechnung1.htm#kettenbruch
unter: Approximation von Dezimalbrüchen durch echte Brüche

Den Algorithmus kannst Du Dir direkt aus dem java-skript holen.

Die Erklärung gibts hier:
http://de.wikipedia.org/wiki/Kettenbruch

@Unbekannter: ... der Du ja am besten von allen in Mathe aufgepasst
hast, kannst nachlesen was bei irrationalen Zahlen passiert. Zumindest
hast Du Dich als nicht Bastler geoutet, sonst wüsstest Du von dem
Problem bescheid ...

Gruß
Mario
Gast #274867
Lesenswert?

Die Lösung 80/29 für 2,7587 stimmt.
Die Kettenbruckmethode sieht gut ist, allerdins scheint das ganze
relativ aufwendig zu sein, wenn ich mir so den Java Code anschaue.
Ob dafür 2kByte Flash reichen ?
Gast #274868
Lesenswert?

Abwechselnd Zähler und Nenner erhöhen und vergleichen, ob zu groß oder
zu klein ( Wägemethode ähnlich der AD-Wandlung mit sukzessiver
Approximation).
Die Werte müßten dann um den Sollwert herum pendeln, und den
nächstgelegenen kann man am Schluß nehmen. Bei 2*7Bit ist das noch nin
endlicher Ziet machbar.

Ich wollte mal die Trägerfrequenz eines UHF-Fernsehsenders in eine
Normalfrequenz herunterteilen, mit einem n/m-Impulsverschluckzähler.
Diese Frequenzen haben ziemlich krumme Werte, mit der
Farbträgerfrequenz 4,433MHz irgendwie verknüpft um die Störungen zu
minimieren, daher war das eine ziemliche Rechnerei, aber nach der
genannten Methode habe ich Brüche gefunden, die auf 10 Stellen genau
stimmten.
Gast #274869
Lesenswert?

@Benedikt,

Also sooo kompliziert ist das nun auch nicht ....

In Matlab sieht das qanze so aus:

k=[];

number = 2.7587;
r = 10000;
q = number * r;

% Erstelle den Kettenbruch
for i=1:5
    k(i) = floor(q/r);
    h = r;
    r = mod(q, r);
    q = h;
end

% Errechne aus dem Kettenbruch p und q.
p=k(5);
q=1;
for i=4:-1:1
    h=p;
    p=k(i)*p+q;
    q=h;
end

Danach ist p=80 und q=29.
Wenn Du's aber umständlich machst, wirst Du 2k sicher voll kriegen -
kein Zweifel :).

Gruß
Mario
Gast #274870
Lesenswert?

Sollwert = 2,7587

Anfangswert 2/1 =2  zu klein, also Zähler erhöhen
3/1 =3 zu groß, also Nenner vergrößern
3/2 =1,5 zu klein, Zähler erhöhen
4/2 =2 immer noch zu klein
5/2 =2,5 immer noch zu klein
6/2 =3  zu groß
6/3 =2 zu klein

und so weiter, das sollte ja zum Ziel führen
Gast #274871
Lesenswert?

Ergänzung zu meinem obrigen Beitrag: Kann natürlich alles in
integer-Arithmetik gemacht werden, und mit ein bisschen überlegen auch
noch viel effizienter gestaltet (Hifsvariable h kann wahrs. eleminiert
werden).
Das denke ich ist auch der Hauptvorteil gegenüber Christoph's Ansatz -
der aber sonst auch sehr nett ist.
Persönliche Seite #788801
Lesenswert?

Auch wenn der Thread schon steinalt ist, ich aber vor dem gleichen 
Problem stehe/stand und möglicherweise es noch weitere suchenden 
interessiert. Ich habe eine Lösung bei der nur eine Variable 
druchprobiert werden muss:
1
private void convertAndStore(double value) {
2
//calculate best fitting a/b value
3
double error = Double.MAX_VALUE;
4
int besta = 1, bestb = 1;
5
int b = 1;
6
while ((error > 0) && (b < 65555)) {
7
  int a = (int)(value*((double)b)); //+0.5 for rounding?
8
  double nerror = Math.abs(((double)a)/((double)b) -value);
9
  if (a > 65555) //all following numbers will be even greater
10
    break;
11
  if ((nerror < error)){
12
    error = nerror;
13
    besta = a;
14
    bestb = b;
15
  }
16
  b++;
17
}
18
//now store besta and bestb
19
}
konkret darf eben a und b nur im Bereich einer unsigned 16 Bit Variable 
liegen und ich war auf der Suche nach einer besseren Methode.
Hätte ich die Begrenzung nicht, würde ich bei dem Nenner "das Komma 
streichen" und dann als Zähler 10^(Zahl der Nachkommastellen) setzen. 
Dann von Nenner und Zähler den ggt bestimmen und entsprechend teilen.
#788824
Lesenswert?

Weils mich selber interessiert hat, habe ich das Verfahren von Christoph 
mal als Exceltabelle "nachprogrammiert"
angefangen wird mit 1/1 und anschließend wird Zähler bzw Nenner erhöht.
Einfach in die Exceltabelle oben links den gewünschten Wert eingeben.
Die Treffer werden dann markiert und ich komm auf die gleiche Werte wie 
hier im Thrad geposted wurden. (z.B. 22/7 für PI)

Gruß
Roland
Angehängte Dateien:

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren