Disons que nous l'avons fait 0.33
, nous devons produire 1/3
.
Si c'est le cas 0.4
, nous devons produire 2/5
.
L'idée est de le rendre lisible par l'homme pour que l'utilisateur comprenne « x parties sur y » comme une meilleure façon de comprendre les données.
Je sais que les pourcentages sont un bon substitut, mais je me demandais s'il y avait un moyen simple de le faire?
algorithm
language-agnostic
numbers
Swaroop CH
la source
la source
.33
=>"1/3"
me concerne; Je m'attendrais à.33
=>"33/100"
. Je suppose que vous vouliez dire.33...
, bien sûr, mais cela expose un problème avec la question - avant de pouvoir nous installer sur un algorithme, nous devons décider du comportement attendu. La réponse Python de @ Debilski utilise.limit_denominator()
ce qui par défaut est un dénominateur maximum de 10 ^ 7; probablement une bonne valeur par défaut dans la pratique, mais cela peut encore introduire des bugs si vous ne faites pas attention, et ne le retour"33/100"
dans le.33
cas.Réponses:
J'ai trouvé que l' approximation rationnelle de recherche de David Eppstein au code réel C donné était exactement ce que vous demandiez. Son basé sur la théorie des fractions continues et très rapide et assez compact.
J'ai utilisé des versions de ce personnalisé pour des limites de numérateur et de dénominateur spécifiques.
la source
À partir de Python 2.6, il y a le
fractions
module.(Citant les documents.)
la source
language agnostic
et desalgorithm
balises votre réponse satisfait-elle?Si la sortie doit donner à un lecteur humain une impression rapide de l'ordre du résultat, cela n'a aucun sens de renvoyer quelque chose comme "113/211", donc la sortie devrait se limiter à l'utilisation de nombres à un chiffre (et peut-être 1 / 10 et 9/10). Si c'est le cas, vous pouvez observer qu'il n'y a que 27 fractions différentes .
Puisque le calcul sous-jacent pour générer la sortie ne changera jamais, une solution pourrait être de simplement coder en dur un arbre de recherche binaire, de sorte que la fonction effectue au plus log (27) ~ = 4 3/4 comparaisons. Voici une version C testée du code
la source
1/1000
c'est également très lisible humainement, mais l'algorithme ci-dessus ne produirait qu'une1/10
approximation très grossière ; Je crois que des améliorations peuvent être apportées en termes dont dénominateurs lisible par l' homme on peut choisir, et / ou l'ajout de<
,>
,<<
,>>
préfixes pour donner une idée de la grossièreté de l'approximation.Voici un lien expliquant les mathématiques derrière la conversion d'un décimal en fraction:
http://www.webmath.com/dec2fract.html
Et voici un exemple de fonction pour savoir comment le faire en utilisant VB (à partir de www.freevbcode.com/ShowCode.asp?ID=582):
(À partir des recherches Google: convertissez le décimal en fraction, convertissez le code décimal en fraction)
la source
Vous voudrez peut-être lire ce que tout informaticien devrait savoir sur l'arithmétique à virgule flottante .
Vous devrez spécifier une certaine précision en multipliant par un grand nombre:
alors vous pouvez faire une fraction:
et réduire via GCD ...
mais il n'y a aucun moyen d'obtenir la fraction voulue . Vous voudrez peut-être toujours utiliser des fractions dans tout votre code à la place - n'oubliez pas de réduire les fractions lorsque vous le pouvez pour éviter le débordement!
la source
Voici les versions Perl et Javascript du code VB suggérées par devinmoore:
Perl:
Et le javascript presque identique:
la source
Implémentation AC #
la source
L' arbre de Stern-Brocot induit une manière assez naturelle d'approximer les nombres réels par des fractions avec des dénominateurs simples.
la source
Une partie du problème est que tant de fractions ne sont pas facilement interprétées comme des fractions. Par exemple, 0,33 n'est pas 1/3, c'est 33/100. Mais si vous vous souvenez de votre formation à l'école élémentaire, il existe un processus de conversion des valeurs décimales en fractions, mais il est peu probable que vous donniez ce que vous voulez car la plupart du temps, les nombres décimaux ne sont pas stockés à 0,33, mais à 0,329999999999998 ou quelque chose du genre.
Faites-vous une faveur et ne vous embêtez pas avec cela, mais si vous en avez besoin, vous pouvez faire ce qui suit:
Multipliez la valeur d'origine par 10 jusqu'à ce que vous supprimiez la partie fractionnaire. Conservez ce nombre et utilisez-le comme diviseur. Faites ensuite une série de simplifications en recherchant des dénominateurs communs.
Donc 0.4 serait 4/10. Vous recherchez alors des diviseurs communs commençant par des valeurs faibles, probablement des nombres premiers. En commençant par 2, vous verriez si 2 divise le numérateur et le dénominateur de manière égale en vérifiant si le plancher de division est le même que la division elle-même.
Donc 5 ne divise pas 2 uniformément. Alors vous vérifiez le nombre suivant, disons 3. Vous faites cela jusqu'à ce que vous atteigniez ou au-dessus de la racine carrée du plus petit nombre.
Après avoir fait cela, vous avez besoin
la source
Ce n'est pas un "algorithme", juste une solution Python: http://docs.python.org/library/fractions.html
la source
"Disons que nous avons 0,33, nous devons sortir" 1/3 "."
Quelle précision attendez-vous de la «solution»? 0,33 n'est pas égal à 1/3. Comment reconnaissez-vous une «bonne» réponse (facile à lire)?
Quoi qu'il en soit, un algorithme possible pourrait être:
Si vous prévoyez de trouver une fraction la plus proche sous une forme X / Y où Y est inférieur à 10, vous pouvez alors parcourir les 9 Y possibles, pour chaque Y calculer X, puis sélectionner le plus précis.
la source
Je pense que la meilleure façon de faire est de convertir d'abord votre valeur flottante en représentation ascii. En C ++, vous pouvez utiliser ostringstream ou en C, vous pouvez utiliser sprintf. Voici à quoi cela ressemblerait en C ++:
Une approche similaire pourrait être adoptée en ligne droite C.
Ensuite, vous devrez vérifier que la fraction est dans les termes les plus bas. Cet algorithme donnera une réponse précise, c'est-à-dire que 0,33 produirait «33/100» et non «1/3». Cependant, 0,4 donnerait «4/10», qui, réduit aux termes les plus bas, serait «2/5». Ce n'est peut-être pas aussi puissant que la solution d'EppStein, mais je pense que c'est plus simple.
la source
Une solution intégrée dans R:
Cela utilise une méthode de fraction continue et a optionnel
cycles
et desmax.denominator
arguments pour ajuster la précision.la source
library(numbers)
etcontFrac(0.6666)
; pour obtenir la sortie de chaîne comme vous le souhaitez:paste(contFrac(0.666, tol=1e-03)$rat, collapse="/")
Vous devrez déterminer le niveau d'erreur que vous êtes prêt à accepter. Toutes les fractions décimales ne se réduiront pas à une simple fraction. Je choisirais probablement un nombre facilement divisible, comme 60, et déterminerais combien de 60e est le plus proche de la valeur, puis je simplifierais la fraction.
la source
Vous pouvez le faire dans n'importe quel langage de programmation en suivant les étapes suivantes:
Exemple: 0,2 = 0,2 x 10 ^ 1/10 ^ 1 = 2/10 = 1/5
Donc, cela peut être lu comme «1 partie sur 5»
la source
Une solution consiste simplement à stocker tous les nombres sous forme de nombres rationnels en premier lieu. Il existe des bibliothèques pour l'arithmétique des nombres rationnels (par exemple GMP ). Si vous utilisez un langage OO, vous pourrez peut-être simplement utiliser une bibliothèque de classes de nombres rationnels pour remplacer votre classe de nombres.
Les programmes financiers, entre autres, utiliseraient une telle solution pour être en mesure de faire des calculs exacts et de préserver la précision qui peut être perdue en utilisant un flotteur simple.
Bien sûr, ce sera beaucoup plus lent, donc ce ne sera peut-être pas pratique pour vous. Cela dépend de la quantité de calculs à faire et de l'importance de la précision pour vous.
la source
C'est faux dans le cas courant, à cause de 1/3 = 0,33333333 = 0. (3) De plus, il est impossible de trouver à partir des solutions suggérées ci-dessus est décimal peut être converti en fraction avec une précision définie, car la sortie est toujours une fraction.
MAIS, je suggère ma fonction complète avec de nombreuses options basées sur l'idée d' une série géométrique infinie , en particulier sur la formule:
Au début, cette fonction essaie de trouver une période de fraction dans la représentation sous forme de chaîne. Après cela, la formule décrite ci-dessus est appliquée.
Le code des nombres rationnels est emprunté à l' implémentation des nombres rationnels de Stephen M. McKamey en C #. J'espère qu'il n'est pas très difficile de porter mon code sur d'autres langues.
Il existe quelques exemples d'utilisations:
Votre valise avec coupe droite zéro pièce:
Démonstration de la période minimale:
Arrondi à la fin:
Le cas le plus intéressant:
D'autres tests et code que tout le monde peut trouver dans ma bibliothèque MathFunctions sur github .
la source
Ruby a déjà une solution intégrée:
Dans Rails, les attributs numériques ActiveRecord peuvent également être convertis:
la source
Répondez en C ++, en supposant que vous avez une classe «BigInt», qui peut stocker des entiers de taille illimitée.
Vous pouvez utiliser «unsigned long long» à la place, mais cela ne fonctionnera que pour certaines valeurs.
BTW, GetRational (0.0) renverra "+0/1", donc vous voudrez peut-être gérer ce cas séparément.
PS: J'utilise ce code dans ma propre classe 'RationalNum' depuis plusieurs années, et il a été testé à fond.
la source
while
boucle est limitée par la taille dedouble
, qui est généralement de 64 bits. Cela ne dépend donc pas de la valeur initiale de input (val
). LaGCD
fonction, cependant, dépend de cette valeur, bien qu'elle converge généralement vers une solution assez rapidement. Est-il possible que vous n'ayez pas implémenté correctement cette fonction?unsigned long long
place deBigInt
, cela ne donnera pas nécessairement le résultat correct pour chaque valeur d'entrée ... Mais même dans ce scénario, le code n'est pas censé "entrer dans une très longue boucle".GCD
fonction ne soit pas implémentée correctement. Avez-vous vérifié si le code s'exécute pendant une longue période pendantwhile
ou après la boucle? Je vais vérifier la valeur de 1.33333, pour voir ce qui se cache derrière cela. Merci.Cet algorithme d' Ian Richards / John Kennedy renvoie non seulement de belles fractions, mais il fonctionne également très bien en termes de vitesse. Ceci est le code C # tiré de cette réponse par moi.
Il peut tout gérer
double
valeurs à l'exception des valeurs spéciales comme NaN et +/- infinity, que vous devrez ajouter si nécessaire.Il renvoie un
new Fraction(numerator, denominator)
. Remplacez par votre propre type.Pour plus d'exemples de valeurs et une comparaison avec d'autres algorithmes, allez ici
Exemples de valeurs renvoyées par cet algorithme:
la source
Vous allez avoir deux problèmes de base qui rendront cela difficile:
1) La virgule flottante n'est pas une représentation exacte, ce qui signifie que si vous avez une fraction de "x / y" qui aboutit à une valeur de "z", votre algorithme de fraction peut renvoyer un résultat autre que "x / y".
2) Il existe une infinité de nombres plus irrationnels que rationnels. Un nombre rationnel est celui qui peut être représenté sous forme de fraction. Irrationnel étant ceux qui ne le peuvent pas.
Cependant, d'une manière peu coûteuse, puisque la virgule flottante a une précision limite, vous pouvez toujours la représenter comme une forme de faction. (Je pense...)
la source
A complété le code ci-dessus et l'a converti en as3
la source
Voici une implémentation rapide et sale en javascript qui utilise une approche de force brute. Pas du tout optimisé, il fonctionne dans une plage de fractions prédéfinie: http://jsfiddle.net/PdL23/1/
Ceci est inspiré de l'approche utilisée par JPS.
la source
Comme beaucoup de gens l'ont dit, vous ne pouvez vraiment pas convertir une virgule flottante en une fraction (à moins que ce soit extrêmement exact comme 0,25). Bien sûr, vous pouvez créer un type de recherche pour un large éventail de fractions et utiliser une sorte de logique floue pour produire le résultat que vous recherchez. Encore une fois, cela ne serait pas exact et vous auriez besoin de définir une limite inférieure de la taille que vous voulez que le dénominateur aille.
.32 <x <.34 = 1/3 ou quelque chose comme ça.
la source
Voici l'implémentation pour ruby http://github.com/valodzka/frac
la source
Je suis tombé sur une solution Haskell particulièrement élégante utilisant un anamorphisme. Cela dépend du package récursivité-schémas .
Si vous essayez ceci dans ghci, cela fonctionne vraiment!
la source