Digamos que tenemos 0.33
, necesitamos generar 1/3
.
Si es así 0.4
, tenemos que generar 2/5
.
La idea es hacerlo legible por humanos para que el usuario comprenda " x partes de y " como una mejor forma de comprender los datos.
Sé que los porcentajes son un buen sustituto, pero me preguntaba si había una forma sencilla de hacer esto.
algorithm
language-agnostic
numbers
Swaroop CH
fuente
fuente
.33
=>"1/3"
me concierne; Yo esperaría.33
=>"33/100"
. Supongo que quiso decir,.33...
por supuesto, pero expone un problema con la pregunta: antes de que podamos establecer un algoritmo, debemos decidir el comportamiento esperado. La respuesta de Python de @ Debilski utiliza.limit_denominator()
el valor predeterminado de un denominador máximo de 10 ^ 7; probablemente un buen valor por defecto en la práctica, pero esto todavía puede introducir errores si no tiene cuidado, y lo hace de retorno"33/100"
en el.33
caso.Respuestas:
He descubierto que la aproximación racional de David Eppstein al código C del número real dado es exactamente lo que estás pidiendo. Se basa en la teoría de las fracciones continuas y es muy rápido y bastante compacto.
He usado versiones de esto personalizadas para límites específicos de numerador y denominador.
fuente
Desde Python 2.6 en adelante está el
fractions
módulo.(Citando de los documentos).
fuente
language agnostic
yalgorithm
etiquetas satisface su respuesta?Si el resultado es para darle a un lector humano una impresión rápida del orden del resultado, no tiene sentido devolver algo como "113/211", por lo que el resultado debería limitarse a usar números de un dígito (y tal vez 1 / 10 y 9/10). Si es así, puede observar que solo hay 27 fracciones diferentes .
Dado que la matemática subyacente para generar la salida nunca cambiará, una solución podría ser simplemente codificar un árbol de búsqueda binario, de modo que la función funcione como máximo log (27) ~ = 4 3/4 comparaciones. Aquí hay una versión C probada del código
fuente
1/1000
también es muy legible por humanos, pero el algoritmo anterior solo produciría una1/10
aproximación muy burda ; Creo que se pueden hacer mejoras en términos de los cuales denominadores humanamente legible, uno puede escoger de, y / o la adición de<
,>
,<<
,>>
prefijos para dar una idea de la tosquedad de la aproximación.Aquí hay un enlace que explica las matemáticas detrás de la conversión de un decimal a una fracción:
http://www.webmath.com/dec2fract.html
Y aquí hay una función de ejemplo sobre cómo hacerlo realmente usando VB (de www.freevbcode.com/ShowCode.asp?ID=582):
(De las búsquedas de Google: convertir decimal a fracción, convertir decimal a código de fracción)
fuente
Es posible que desee leer Lo que todo científico informático debería saber sobre la aritmética de coma flotante .
Tendrá que especificar cierta precisión multiplicando por un número grande:
entonces puedes hacer una fracción:
y reducir vía GCD ...
pero no hay forma de sacar la fracción deseada . Es posible que desee utilizar siempre fracciones en todo el código en su lugar, ¡solo recuerde reducir las fracciones cuando pueda para evitar el desbordamiento!
fuente
Aquí están las versiones de Perl y Javascript del código VB sugeridas por devinmoore:
Perl:
Y el javascript casi idéntico:
fuente
Implementación AC #
fuente
El árbol de Stern-Brocot induce una forma bastante natural de aproximar números reales por fracciones con denominadores simples.
fuente
Parte del problema es que muchas fracciones no son fáciles de interpretar como fracciones. Por ejemplo, 0,33 no es 1/3, es 33/100. Pero si recuerda su capacitación en la escuela primaria, entonces hay un proceso para convertir valores decimales en fracciones, sin embargo, es poco probable que le dé lo que desea, ya que la mayoría de las veces los números decimales no se almacenan en 0.33, sino en 0.329999999999998 o algo así.
Hágase un favor y no se moleste con esto, pero si es necesario, puede hacer lo siguiente:
Multiplica el valor original por 10 hasta que elimines la parte fraccionaria. Conserve ese número y utilícelo como divisor. Luego haz una serie de simplificaciones buscando denominadores comunes.
Entonces 0.4 sería 4/10. Luego, buscaría divisores comunes que comiencen con valores bajos, probablemente números primos. Comenzando con 2, verá si 2 divide el numerador y el denominador de manera uniforme al verificar si el piso de la división es el mismo que la división en sí.
Entonces, 5 no divide a 2 uniformemente. Entonces marca el siguiente número, digamos 3. Haz esto hasta que llegues a la raíz cuadrada del número más pequeño o por encima de ella.
Después de hacer eso, entonces necesitas
fuente
Esto no es un "algoritmo", solo una solución de Python: http://docs.python.org/library/fractions.html
fuente
"Digamos que tenemos 0.33, necesitamos generar" 1/3 "".
¿Qué precisión espera que tenga la "solución"? 0.33 no es igual a 1/3. ¿Cómo reconoce una respuesta "buena" (fácil de leer)?
Pase lo que pase, un posible algoritmo podría ser:
Si espera encontrar una fracción más cercana en una forma X / Y donde Y es menor que 10, entonces puede recorrer las 9 posibles Y, para cada Y calcular X, y luego seleccionar la más precisa.
fuente
Creo que la mejor manera de hacer esto es convertir primero su valor flotante en una representación ascii. En C ++ puedes usar ostringstream o en C, puedes usar sprintf. Así es como se vería en C ++:
Se podría adoptar un enfoque similar en C.
Luego, deberá verificar que la fracción esté en los términos más bajos. Este algoritmo dará una respuesta precisa, es decir, 0,33 daría como resultado "33/100", no "1/3". Sin embargo, 0.4 daría "4/10", que cuando se reduce a los términos más bajos sería "2/5". Puede que esto no sea tan poderoso como la solución de EppStein, pero creo que es más sencillo.
fuente
Una solución integrada en R:
Este utiliza un método fracción continua y tiene opcional
cycles
ymax.denominator
argumentos para el ajuste de la precisión.fuente
library(numbers)
ycontFrac(0.6666)
; para obtener la salida de la cadena como se desea:paste(contFrac(0.666, tol=1e-03)$rat, collapse="/")
Tendrá que averiguar qué nivel de error está dispuesto a aceptar. No todas las fracciones decimales se reducirán a una fracción simple. Probablemente elegiría un número fácilmente divisible, como 60, y calcularía cuántos 60 está más cerca del valor, luego simplificaría la fracción.
fuente
Puede hacer esto en cualquier lenguaje de programación siguiendo los siguientes pasos:
Ejemplo: 0,2 = 0,2 x 10 ^ 1/10 ^ 1 = 2/10 = 1/5
Entonces, eso se puede leer como '1 parte de 5'
fuente
Una solución es almacenar todos los números como números racionales en primer lugar. Hay bibliotecas para aritmética de números racionales (por ejemplo, GMP ). Si usa un lenguaje OO, es posible que pueda usar una biblioteca de clases de números racionales para reemplazar su clase de números.
Los programas financieros, entre otros, utilizarían una solución de este tipo para poder realizar cálculos exactos y preservar la precisión que se puede perder con un simple flotador.
Por supuesto, será mucho más lento, por lo que puede que no sea práctico para usted. Depende de la cantidad de cálculos que necesite hacer y de la importancia que tenga la precisión para usted.
fuente
Es incorrecto en el caso común, debido a 1/3 = 0.3333333 = 0. (3) Además, es imposible averiguar a partir de las soluciones sugeridas anteriormente si el decimal se puede convertir a fracción con precisión definida, porque la salida siempre es fracción.
PERO, sugiero mi función integral con muchas opciones basadas en la idea de series geométricas infinitas , específicamente en la fórmula:
Al principio, esta función intenta encontrar un período de fracción en la representación de cadena. Después se aplica la fórmula descrita anteriormente.
El código de números racionales se toma prestado de la implementación de números racionales de Stephen M. McKamey en C #. Espero que no sea muy difícil migrar mi código a otros idiomas.
Hay algunos ejemplos de usos:
Su caso con el recorte de piezas cero de la pieza correcta:
Demostración de período mínimo:
Redondeo al final:
El caso más interesante:
Otras pruebas y códigos que todos pueden encontrar en mi biblioteca MathFunctions en github .
fuente
Ruby ya tiene una solución incorporada:
En Rails, los atributos numéricos de ActiveRecord también se pueden convertir:
fuente
Responda en C ++, asumiendo que tiene una clase 'BigInt', que puede almacenar enteros de tamaño ilimitado.
En su lugar, puede usar 'unsigned long long', pero solo funcionará para ciertos valores.
Por cierto, GetRational (0.0) devolverá "+0/1", por lo que es posible que desee manejar este caso por separado.
PD: He estado usando este código en mi propia clase 'RationalNum' durante varios años y se ha probado a fondo.
fuente
while
bucle está limitado por el tamaño dedouble
, que normalmente es de 64 bits. Por tanto, no depende del valor inicial de la entrada (val
). LaGCD
función, sin embargo, no depende de este valor, aunque por lo general converge a una solución bastante rápido. ¿Es posible que no hayas implementado esta función correctamente?unsigned long long
lugar deBigInt
, entonces no necesariamente dará el resultado correcto para cada valor de entrada ... Pero incluso en ese escenario, el código no es se supone que "entra en un bucle muy largo".GCD
función no esté implementada correctamente. ¿Ha comprobado si el código se ejecuta durante mucho tiempo durante elwhile
bucle o después? Verificaré el valor de 1.33333 para ver qué hay detrás de esto. Gracias.Este algoritmo de Ian Richards / John Kennedy no solo devuelve buenas fracciones, sino que también funciona muy bien en términos de velocidad. Este es el código C # tomado de esta respuesta por mí.
Puede manejar todos los
double
valores excepto los valores especiales como NaN y +/- infinito, que tendrá que agregar si es necesario.Devuelve un
new Fraction(numerator, denominator)
. Reemplace por su propio tipo.Para obtener más valores de ejemplo y una comparación con otros algoritmos, vaya aquí
Valores de ejemplo devueltos por este algoritmo:
fuente
Vas a tener dos problemas básicos que dificultarán esto:
1) El punto flotante no es una representación exacta, lo que significa que si tiene una fracción de "x / y" que da como resultado un valor de "z", su algoritmo de fracción puede devolver un resultado distinto de "x / y".
2) Hay infinitos muchos más números irracionales que racionales. Un número racional es aquel que se puede representar como una fracción. Ser irracionales los que no pueden.
Sin embargo, de una manera barata, dado que el punto flotante tiene una precisión límite, siempre puedes representarlo como alguna forma de facción. (Yo creo que...)
fuente
Completó el código anterior y lo convirtió a as3
fuente
Aquí hay una implementación rápida y sucia en javascript que utiliza un enfoque de fuerza bruta. Nada optimizado, funciona dentro de un rango predefinido de fracciones: http://jsfiddle.net/PdL23/1/
Esto está inspirado en el enfoque utilizado por JPS.
fuente
Como muchas personas han dicho, realmente no se puede convertir un punto flotante en una fracción (a menos que sea extremadamente exacto como 0,25). Por supuesto, puede crear algún tipo de búsqueda para una gran variedad de fracciones y usar algún tipo de lógica difusa para producir el resultado que está buscando. Nuevamente, esto no sería exacto y necesitaría definir un límite inferior de cuán grande desea que sea el denominador.
.32 <x <.34 = 1/3 o algo así.
fuente
Aquí está la implementación para ruby http://github.com/valodzka/frac
fuente
Me encontré con una solución Haskell especialmente elegante que utiliza un anamorfismo. Depende del paquete de esquemas de recursividad .
Si prueba esto en ghci, ¡realmente funciona!
fuente