Nehmen wir an, wir haben 0.33
, wir müssen ausgeben 1/3
.
Wenn ja, müssen 0.4
wir ausgeben 2/5
.
Die Idee ist, es für den Menschen lesbar zu machen, damit der Benutzer " x Teile aus y " versteht, um Daten besser zu verstehen.
Ich weiß, dass Prozentsätze ein guter Ersatz sind, aber ich habe mich gefragt, ob es einen einfachen Weg gibt, dies zu tun.
algorithm
language-agnostic
numbers
Swaroop CH
quelle
quelle
.33
=>"1/3"
Beispiel betrifft mich; Ich würde erwarten.33
=>"33/100"
. Ich nehme an, Sie haben das.33...
natürlich gemeint , aber es wirft ein Problem mit der Frage auf - bevor wir uns für einen Algorithmus entscheiden können, müssen wir über das erwartete Verhalten entscheiden. @ Debilskis Python-Antwort verwendet.limit_denominator()
standardmäßig einen maximalen Nenner von 10 ^ 7; wahrscheinlich ein guter Standard in der Praxis, aber das kann noch Fehler einführen , wenn man nicht aufpasst, und tut Rückkehr"33/100"
in dem.33
Fall.Antworten:
Ich habe festgestellt, dass David Eppsteins rationale Annäherung an einen gegebenen Code der reellen Zahl C genau das ist, wonach Sie fragen. Es basiert auf der Theorie der fortgesetzten Brüche und ist sehr schnell und ziemlich kompakt.
Ich habe Versionen davon verwendet, die für bestimmte Zähler- und Nennergrenzen angepasst wurden.
quelle
Ab Python 2.6 gibt es die
fractions
Modul.(Zitiert aus den Dokumenten.)
quelle
language agnostic
undalgorithm
Tags erfüllt Ihre Antwort?Wenn die Ausgabe einem menschlichen Leser einen schnellen Eindruck von der Reihenfolge des Ergebnisses vermitteln soll, ist es nicht sinnvoll, so etwas wie "113/211" zurückzugeben. Daher sollte sich die Ausgabe auf die Verwendung einstelliger Zahlen (und möglicherweise 1 /) beschränken. 10 und 9/10). Wenn ja, können Sie beobachten, dass es nur 27 verschiedene gibt Fraktionen gibt.
Da sich die zugrunde liegende Mathematik zum Generieren der Ausgabe niemals ändern wird, könnte eine Lösung darin bestehen, einen binären Suchbaum einfach hart zu codieren, so dass die Funktion höchstens log (27) ~ = 4 3/4 Vergleiche ausführt. Hier ist eine getestete C-Version des Codes
quelle
1/1000
auch sehr gut lesbar ist, aber der obige Algorithmus würde nur eine sehr grobe1/10
Annäherung erzeugen ; Ich glaube , dass Verbesserungen in Bezug auf denen menschlich lesbare Nenner gemacht werden , um einen von der Abholung können, und / oder die Zugabe von<
,>
,<<
,>>
Präfixen einer Vorstellung von der Grobkörnigkeit der Annäherung zu geben.Hier ist ein Link, der die Mathematik erklärt, die hinter der Konvertierung einer Dezimalstelle in einen Bruch steht:
http://www.webmath.com/dec2fract.html
Und hier ist eine Beispielfunktion, wie man es tatsächlich mit VB macht (von www.freevbcode.com/ShowCode.asp?ID=582):
(Bei Google-Suchanfragen: Dezimal in Bruch umwandeln, Dezimal in Bruch umwandeln)
quelle
Vielleicht möchten Sie lesen, was jeder Informatiker über Gleitkomma-Arithmetik wissen sollte .
Sie müssen eine gewisse Genauigkeit angeben, indem Sie mit einer großen Zahl multiplizieren:
dann können Sie einen Bruch machen:
und über GCD reduzieren ...
Es gibt jedoch keine Möglichkeit, die beabsichtigte Fraktion herauszuholen. Möglicherweise möchten Sie stattdessen immer Brüche in Ihrem Code verwenden - denken Sie daran, Brüche zu reduzieren, wenn Sie können, um einen Überlauf zu vermeiden!
quelle
Hier sind Perl- und Javascript-Versionen des von devinmoore vorgeschlagenen VB-Codes:
Perl:
Und das fast identische Javascript:
quelle
AC # Implementierung
quelle
Das Stern-Brocot-Baum induziert eine ziemlich natürliche Methode, um reelle Zahlen durch Brüche mit einfachen Nennern zu approximieren.
quelle
Ein Teil des Problems ist, dass so viele Brüche nicht einfach als Brüche zu interpretieren sind. ZB ist 0,33 nicht 1/3, sondern 33/100. Wenn Sie sich jedoch an Ihre Grundschulausbildung erinnern, werden Dezimalwerte in Brüche umgewandelt. Es ist jedoch unwahrscheinlich, dass Sie das erhalten, was Sie möchten, da Dezimalzahlen meistens nicht bei 0,33, sondern bei 0,329999999999998 oder einem ähnlichen Wert gespeichert werden.
Tun Sie sich selbst einen Gefallen und kümmern Sie sich nicht darum, aber wenn Sie müssen, können Sie Folgendes tun:
Multiplizieren Sie den ursprünglichen Wert mit 10, bis Sie den Bruchteil entfernen. Behalten Sie diese Nummer und verwenden Sie sie als Teiler. Führen Sie dann eine Reihe von Vereinfachungen durch, indem Sie nach gemeinsamen Nennern suchen.
0,4 wäre also 4/10. Sie würden dann nach gemeinsamen Teilern suchen, die mit niedrigen Werten beginnen, wahrscheinlich Primzahlen. Beginnend mit 2 würden Sie sehen, ob 2 sowohl den Zähler als auch den Nenner gleichmäßig teilt, indem Sie prüfen, ob der Teilungsboden mit der Teilung selbst identisch ist.
5 teilt also 2 nicht gleichmäßig. Dann überprüfen Sie die nächste Zahl, sagen wir 3. Sie tun dies, bis Sie an oder über der Quadratwurzel der kleineren Zahl treffen.
Nachdem Sie das getan haben, brauchen Sie
quelle
Dies ist kein "Algorithmus", sondern nur eine Python-Lösung: http://docs.python.org/library/fractions.html
quelle
"Nehmen wir an, wir haben 0,33, wir müssen" 1/3 "ausgeben."
Welche Präzision erwarten Sie von der "Lösung"? 0,33 ist nicht gleich 1/3. Woran erkennt man eine "gute" (leicht zu lesende) Antwort?
Egal was, ein möglicher Algorithmus könnte sein:
Wenn Sie erwarten, einen nächsten Bruch in einer Form X / Y zu finden, in der Y kleiner als 10 ist, können Sie für jede Y-Berechnung X alle 9 möglichen Ys durchlaufen und dann den genauesten auswählen.
quelle
Ich denke, der beste Weg, dies zu tun, besteht darin, zuerst Ihren Float-Wert in eine ASCII-Darstellung umzuwandeln. In C ++ können Sie ostringstream oder in C sprintf verwenden. So würde es in C ++ aussehen:
Ein ähnlicher Ansatz könnte in Straight C gewählt werden.
Danach müssten Sie überprüfen, ob der Bruch am niedrigsten ist. Dieser Algorithmus gibt eine genaue Antwort, dh 0,33 würde "33/100" ausgeben, nicht "1/3". 0,4 würde jedoch "4/10" ergeben, was, wenn es auf die niedrigsten Terme reduziert würde, "2/5" wäre. Dies ist möglicherweise nicht so leistungsfähig wie die Lösung von EppStein, aber ich glaube, dass dies einfacher ist.
quelle
Eine integrierte Lösung in R:
Dies verwendet eine fortgesetzte Bruchmethode und verfügt über Optionen
cycles
undmax.denominator
Argumente zum Anpassen der Genauigkeit.quelle
library(numbers)
undcontFrac(0.6666)
; um die String-Ausgabe wie gewünscht zu erhalten:paste(contFrac(0.666, tol=1e-03)$rat, collapse="/")
Sie müssen herausfinden, welche Fehlerstufe Sie akzeptieren möchten. Nicht alle Dezimalbrüche werden auf einen einfachen Bruch reduziert. Ich würde wahrscheinlich eine leicht teilbare Zahl wie 60 auswählen und herausfinden, wie viele 60stel dem Wert am nächsten kommen, und dann den Bruch vereinfachen.
quelle
Sie können dies in jeder Programmiersprache mit den folgenden Schritten tun:
Beispiel: 0,2 = 0,2 x 10 ^ 1/10 ^ 1 = 2/10 = 1/5
Das kann also als "1 Teil von 5" gelesen werden.
quelle
Eine Lösung besteht darin, zunächst alle Zahlen als rationale Zahlen zu speichern. Es gibt Bibliotheken für rationale Zahlenarithmetik (zB GMP ). Wenn Sie eine OO-Sprache verwenden, können Sie möglicherweise nur eine rationale Nummernklassenbibliothek verwenden, um Ihre Nummernklasse zu ersetzen.
Finanzprogramme würden unter anderem eine solche Lösung verwenden, um genaue Berechnungen durchführen und die Präzision bewahren zu können, die mit einem einfachen Float verloren gehen könnte.
Natürlich wird es viel langsamer sein, so dass es für Sie möglicherweise nicht praktisch ist. Hängt davon ab, wie viele Berechnungen Sie durchführen müssen und wie wichtig die Präzision für Sie ist.
quelle
Im Normalfall ist dies falsch, da 1/3 = 0,3333333 = 0. (3) Darüber hinaus ist es unmöglich, aus den oben vorgeschlagenen Lösungen herauszufinden, dass die Dezimalzahl mit definierter Genauigkeit in einen Bruch umgewandelt werden kann, da die Ausgabe immer ein Bruch ist.
ABER ich schlage meine umfassende Funktion mit vielen Optionen vor, die auf der Idee einer unendlichen geometrischen Reihe basieren , insbesondere auf der Formel:
Diese Funktion versucht zunächst, die Bruchperiode in der Zeichenfolgendarstellung zu finden. Danach wird die oben beschriebene Formel angewendet.
Der Code für rationale Zahlen stammt aus der Implementierung rationaler Zahlen von Stephen M. McKamey in C #. Ich hoffe, es ist nicht sehr schwer, meinen Code auf andere Sprachen zu portieren.
Es gibt einige Beispiele für Verwendungen:
Ihr Fall mit dem Trimmen des rechten Teils des Nullteils:
Min. Demostration:
Rundung am Ende:
Der interessanteste Fall:
Weitere Tests und Codes finden alle in meiner MathFunctions-Bibliothek auf github .
quelle
Ruby hat bereits eine integrierte Lösung:
In Rails können auch numerische ActiveRecord-Attribute konvertiert werden:
quelle
Antworten Sie in C ++ unter der Annahme, dass Sie eine 'BigInt'-Klasse haben, in der Ganzzahlen mit unbegrenzter Größe gespeichert werden können.
Sie können stattdessen 'unsigned long long' verwenden, dies funktioniert jedoch nur für bestimmte Werte.
Übrigens gibt GetRational (0.0) "+0/1" zurück, daher möchten Sie diesen Fall möglicherweise separat behandeln.
PS: Ich verwende diesen Code seit mehreren Jahren in meiner eigenen 'RationalNum'-Klasse und er wurde gründlich getestet.
quelle
while
Schleife ist durch die Größe von begrenztdouble
, die typischerweise 64 Bit beträgt. Es kommt also nicht auf den Anfangswert der Eingabe an (val
). DieGCD
Funktion hängt jedoch von diesem Wert ab, obwohl sie normalerweise ziemlich schnell zu einer Lösung konvergiert. Ist es möglich, dass Sie diese Funktion nicht richtig implementiert haben?unsigned long long
stattdessen verwendenBigInt
, nicht unbedingt für jeden Eingabewert das richtige Ergebnis erzielt ... Aber selbst in diesem Szenario ist der Code nicht soll "in eine sehr lange Schleife gehen".GCD
Funktion nicht richtig implementiert ist. Haben Sie überprüft, ob der Code währendwhile
oder nach der Schleife längere Zeit ausgeführt wird ? Ich werde den Wert von 1,33333 überprüfen, um zu sehen, was dahinter steckt. Vielen Dank.Dieser Algorithmus von Ian Richards / John Kennedy liefert nicht nur schöne Brüche, sondern ist auch sehr schnell. Dies ist der C # -Code, den ich aus dieser Antwort entnommen habe.
Es kann alle
double
Werte verarbeiten, mit Ausnahme von Sonderwerten wie NaN und +/- unendlich, die Sie bei Bedarf hinzufügen müssen.Es gibt a zurück
new Fraction(numerator, denominator)
. Ersetzen Sie durch Ihren eigenen Typ.Weitere Beispielwerte und einen Vergleich mit anderen Algorithmen finden Sie hier
Von diesem Algorithmus zurückgegebene Beispielwerte:
quelle
Sie werden zwei grundlegende Probleme haben, die dies schwierig machen:
1) Gleitkomma ist keine exakte Darstellung. Wenn Sie also einen Bruchteil von "x / y" haben, der zu einem Wert von "z" führt, gibt Ihr Bruchalgorithmus möglicherweise ein anderes Ergebnis als "x / y" zurück.
2) Es gibt unendlich viel mehr irrationale Zahlen als rationale. Eine rationale Zahl kann als Bruch dargestellt werden. Irrationales Sein, das nicht kann.
Da Gleitkommazahlen jedoch eine begrenzte Genauigkeit haben, können Sie sie auf eine billige Art und Weise immer als eine Form von Fraktion darstellen. (Meiner Ansicht nach...)
quelle
Vervollständigte den obigen Code und konvertierte ihn in as3
quelle
Hier ist eine schnelle und schmutzige Implementierung in Javascript, die einen Brute-Force-Ansatz verwendet. Überhaupt nicht optimiert, funktioniert es innerhalb eines vordefinierten Bereichs von Brüchen: http://jsfiddle.net/PdL23/1/
Dies ist inspiriert von dem Ansatz von JPS.
quelle
Wie viele Leute angegeben haben, kann man einen Gleitkommawert wirklich nicht zurück in einen Bruch umwandeln (es sei denn, er ist extrem genau wie 0,25). Natürlich können Sie eine Art Suche nach einer großen Anzahl von Brüchen erstellen und eine Art Fuzzy-Logik verwenden, um das gewünschte Ergebnis zu erzielen. Auch dies wäre jedoch nicht genau und Sie müssten eine Untergrenze dafür definieren, wie groß der Nenner sein soll.
.32 <x <.34 = 1/3 oder so ähnlich.
quelle
Hier ist die Implementierung für Ruby http://github.com/valodzka/frac
quelle
Ich stieß auf eine besonders elegante Haskell-Lösung, die einen Anamorphismus nutzte. Dies hängt vom Rekursionsschema- Paket ab.
Wenn Sie dies in ghci ausprobieren, funktioniert es wirklich!
quelle