Lorsque vous convertissez une fraction en nombre décimal et que vous souhaitez stocker ce nombre, vous devez souvent l'arrondir, car vous ne souhaitez utiliser qu'une certaine quantité de mémoire. Disons que vous ne pouvez stocker que 5 chiffres décimaux, puis 5/3 devient 1,6667. Si vous ne pouvez stocker que 2 chiffres décimaux, ce sera 1,7 (en supposant maintenant qu'il est toujours compris entre 0 et 9,99 ...).
Si vous essayez maintenant d'inverser ce processus avec 1.7 et que vous souhaitez récupérer votre fraction, cela peut être difficile, car vous savez que 1.7 n'est qu'un nombre arrondi. Bien sûr, vous pouvez essayer le 17/10 mais c'est plutôt une fraction "moche" par rapport au 5/3 "élégant".
Le but est donc maintenant de trouver la fraction a / b avec le plus petit dénominateur b, ce qui donne le nombre décimal arrondi lorsqu'il est correctement arrondi.
Détails
L'entrée contient une chaîne avec un nombre de 1 à 5 chiffres compris entre 0 (y compris) et 10 (non compris) avec un '.' après le premier chiffre. Disons que n
dénote le nombre de chiffres. La sortie doit être une liste / un tableau de deux nombres entiers [numerator, denominator]
ou un type de données rationnel (vous pouvez créer le vôtre ou utiliser la fonction intégrée) où le numérateur est non négatif et le dénominateur est positif. Le numérateur / dénominateur de fraction doit être égal à l'entrée lorsqu'il est correctement arrondi à des n
chiffres (ce qui signifie des n-1
chiffres après la virgule décimale).
Restriction: une seule instruction de boucle autorisée. Cela signifie que vous ne pouvez utiliser qu'une seule instruction de bouclage (comme for
ou while
ou goto
etc. ainsi que des boucles fonctionnelles comme map
ou fold
qui appliquent du code à chaque élément d'une liste / tableau) dans tout votre code, mais vous êtes libre d'en abuser ou utiliser la récursivité, etc.
Vous devez écrire une fonction. Si votre langue n'a pas de fonctions (ou même si c'est le cas), vous pouvez également supposer que l'entrée est stockée dans une variable (ou entrée via stdin) et imprimer le résultat ou l'écrire dans un fichier. Le plus petit nombre d'octets gagne.
Arrondi
L'arrondi doit suivre les règles d'arrondi «conventionnelles», c'est-à-dire que si le dernier chiffre qui sera coupé est 5 ou plus, vous arrondirez et vous arrondirez vers le bas pour tous les autres cas, par exemple:
4,5494 résultera de l'arrondi à
- 1 chiffre: 5
- 2 chiffres: 4,5
- 3 chiffres: 4,55
- 4 chiffres: 4.549
Exemples
Veuillez inclure les cas de test suivants et d'autres cas «intéressants»:
Input 1.7 Output 5/3
Input 0. Output 0/1
Input 0.001 Output 1/667
Input 3.1416 Output 355/113
repeat
crée une liste infinie de son argument. I t semble boucler mais il a en fait une complexité temporelle de O (1). Mais je suppose que trier chaque cas individuellement est préférable à ne pas autoriser les langages fonctionnels.for n in numbers: f(g(n))
est équivalent àmap(f, map(g, numbers))
. La version fonctionnelle utilisemap
deux fois, cela devrait-il vraiment être interdit?Réponses:
CJam,
414036 octetsSuppose que la chaîne d'entrée est stockée dans Q, ce qui est explicitement autorisé par la question. Essayez-le en ligne.
Cas de test
Comment ça marche
la source
T-SQL 254
Bien que T-SQL ne soit pas vraiment adapté à ce genre de choses, il est amusant d'essayer. La performance devient vraiment mauvaise plus le dénominateur est élevé. Il est limité à un dénominateur de 1000.
L'entrée est une variable flottante @
Une ventilation de la requête
la source
3.14159
et ça m'a donné355/113
Haskell,
6259si seulement les noms n'étaient pas si longs ...
il s'agit d'une fonction renvoyant une
Rational
valeur.explication: la fonction
approxRational
est une fonction qui prend un nombre flottant et un flottant epsilon et renvoie le rationnel le plus simple qui est en distance epsilon de l'entrée. fondamentalement, renvoie l'approximation la plus simple du flotteur à un rationnel dans une distance "d'erreur pardonnable".exploitons cette fonction pour notre usage. pour cela, nous devrons déterminer quelle est la surface des flotteurs qui arrondissent au nombre donné. puis obtenir ceci dans la
approxRational
fonction nous obtiendra la réponse.essayons 1.7, par exemple. le flotteur le plus bas arrondi à 1,7 est 1,65. une valeur inférieure ne sera pas arrondie à 1,7. de même, la limite supérieure des flotteurs arrondis à 1,7 est de 1,75.
les deux limites sont les limites sont le nombre d'entrée +/- 0,05. on peut facilement montrer que cette distance est toujours
5 * 10 ^ -(the length of the input - 1)
(le -1 est parce qu'il y a toujours un '.' dans l'entrée). à partir d'ici, le code est assez simple.cas de test:
malheureusement, cela ne fonctionne pas sur "0". parce que la fonction d'analyseur de Haskell ne reconnaît pas un
.
à la fin d'un flottant. cela peut être fixé pour 5 octets en remplaçantread s
parread$s++"0"
.la source
Rubis,
127125 octetsDéfinit une fonction
f
qui renvoie le résultat sous la forme d'unRational
. Par exemple, si vous ajoutez ce codeVous recevez
La boucle est au-dessus des dénominateurs. Je commence par la fraction complète, par exemple
31416/10000
pour le dernier exemple. Ensuite, je décrémente le dénominateur, décrémente proportionnellement le numérateur (et l'arrondis). Si les arrondis rationnels résultants sont identiques au nombre d'entrée, je me souviens d'une nouvelle meilleure fraction.la source
Mathematica,
4953 caractèresUsage:
Sortie:
Cas de test:
Le cas de 0,001 me semble étrange; car la fonction rationaliser n'a pas fonctionné selon sa description, quand elle n'a pas trouvé le cas 1/667. Il doit afficher le nombre avec le plus petit dénominateur qui se trouve dans les limites spécifiées.
la source
0.001
ne correspond pas à l'OP car elleRationalize
n'est pas sous la contrainte de minimiser le dénominateur. Comme je l'ai mentionné à fier haskeller, une fonction d'approximation rationnelle soumise à la minimisation du dénominateur est très ésotérique (en bref parce que c'est une façon moche et inefficace d'approximer les nombres). Je ne m'attendrais pas à ce que ce soit une fonction de bibliothèque standard.1/999
. 999 devient le plus petit dénominateur (acceptable) uniquement pour une erreur comprise entre environ 1e-6 et 2e-6. La borne d'erreur est clairement 5e-4. Donc, quoi que Mathematica fasse dans ce cas, cela ne fonctionne vraiment pas selon les spécifications. : PPython 2.7+, 111 caractères
Preuve que vous pouvez écrire un code horrible dans n'importe quelle langue:
Sortie
la source
APL, 50
Tant que vous ne comptez pas
eval
ettoString
que des bouclesExplication
L'approche consiste à itérer sur 1 à 10000 comme dénominateur et à calculer le numérateur qui correspond le mieux au flottant, puis à vérifier si l'erreur se situe dans les limites. Enfin, sélectionnez la plus petite paire parmi toutes les fractions trouvées.
(⍎x←⍞)
Prendre une chaîne de caractères à partir de l'écran, attribuer àx
et évaluer⍳1e5
Générer un tableau de 1 à 10000{...}¨
Pour chaque élément du tableau, appeler la fonction avec lui et(⍎x←⍞)
et les arguments (boucle)⍺×⍵
Multipliez les arguments⌊.5+
Arrondissez (en ajoutant 0,5 puis en arrondissant vers le bas)n←
Attribuez àn
⍺-⍵÷⍨
Diviser par l'argument de droite, puis soustrayez de l'argument de gauche(10*⍴x)×
Multipliez par 10 à la puissance de "longueur dex
"|
Prenez la valeur absolue50>
Vérifiez si moins de 50 (la longueur dex
est 2 de plus que le nombre de dp, utilisez donc 50 ici au lieu de 0,5):n ⍵⋄''
Si la vérification précédente renvoie vrai, retournez le tableau den
et l'argument de droite, sinon retournez une chaîne vide.⍎⍕
toString
puiseval
pour obtenir un tableau de tous les nombres du tableau2↑
Sélectionnez uniquement les 2 premiers éléments, qui est la première paire numérateur-dénominateur trouvéela source
GNU dc, 72 octets
Pas de boucles - DC ne les a même pas. Au lieu de cela, le contrôle provient d'une seule macro récursive de queue - idiomatique pour dc.
Sortie:
Phew. Explication partielle dans cette réponse .
la source
Mathematica, 111 caractères
Vraiment assez simple, et je ne pense pas que cela converge nulle part aussi vite que les autres solutions, car le numérateur et le dénominateur ne font qu'un incrément. Je voulais surtout trouver la solution simple à cela. Je vais devoir voir les autres réponses et voir ce qui se passe là-bas.
Sortie
Quelqu'un ici célèbre-t-il le jour de l'approximation de Pi ?
la source
Applescript,> 300 octets
Je voulais le faire dans une langue qui fait nativement le type d'arrondi requis. Il s'avère qu'Applescript correspond au projet de loi. Ensuite, j'ai vu l'énumération
rounding as taught in school
et je n'ai pas pu résister à son utilisation, malgré l'incompétence flagrante d'Applescript à des fins de golf:Cela peut être joué un peu plus, mais cela n'en vaut probablement pas la peine.
Sortie:
la source
BC,
151148 octetsEdit - version plus rapide et plus courte
même cas de test.
Beaucoup de choses sont similaires à la version précédente, mais au lieu d'essayer toutes les combinaisons n / d possibles, nous escaladons les résidus de v et les quotients arrières des multiples m == v * d et des dénominateurs d. Encore une fois, la précision du calcul est la même.
Le voici démêlé:
Cette version n'a vraiment qu'une seule boucle et ne fait que $ \ Theta \ left (\ operatorname {fractional_decimals} (v) \ right) $ opérations arithmétiques.
Original - version lente
Cette fonction calcule le plus petit nominateur n et le plus petit dénominateur d de sorte que la fraction n / d arrondie aux chiffres fractionnaires_décimaux (v) soit égale à une valeur décimale donnée v.
cas de test:
Et le voici démêlé:
J'avoue que j'ai un peu triché en émulant une deuxième boucle interne à l'intérieur d'une seule boucle externe, mais sans utiliser d'autres instructions de boucle. Et c'est pourquoi il effectue en réalité $ \ Theta \ left (v \ operatorname {fractional_decimals} (v) ^ 2 \ right) $ des opérations arithmétiques.
la source
C, 233
Cela fonctionne en appelant une fonction de rationalisation r () avec un dénominateur de départ de 1. La fonction commence à incrémenter un numérateur et à vérifier à chaque incrément si le nombre résultant, lorsqu'il est arrondi au même nombre de chiffres que l'original, a la même chaîne représentation comme l'original. Une fois que le numérateur a été tellement incrémenté que le résultat est supérieur à l'original, la fonction incrémente le dénominateur et s'appelle.
Bien sûr, cela utilise beaucoup plus de code, mais je pense que l'esprit du problème exonère cette approche à nu; pour tout ce que nous savons, les fonctions rationalize () internes des langages modernes ont beaucoup de boucles internes.
Notez que cela ne fonctionne pas pour une entrée de "0". car ce n'est pas une façon standard d'écrire un flottant, donc quand il réécrit le flottant dans la chaîne, le résultat ne sera jamais un "0".
Les spécifications veulent une fonction qui renvoie des valeurs au lieu de simplement imprimer à l'écran, d'où le passage d'arguments.
Code (non golfé):
Usage:
Code golf:
la source
approxRational
a juste une fonction d'assistance récursive, et pas plus de bouclage que cela.Pure Bash, 92 octets
Comme explication partielle de cette réponse , elle est ici portée à bash:
Notamment:
Sortie:
la source
int
port assez simple pour cJavaScript (E6) 85
Non golfé
Tester dans la console FireFox / FireBug
Sortie
la source