¿Cómo puedo convertir un número en coma flotante en la fracción más cercana representada por un numerador y el denominador de bytes?

StackOverflow https://stackoverflow.com/questions/1656945

Pregunta

¿Cómo puedo escribir un algoritmo que le da un número de coma flotante, y se trata de representar la mayor precisión posible el uso de un numerador y un denominador, tanto limita a la gama de un byte de Java?

La razón de esto es que un dispositivo I2C quiere un numerador y el denominador, mientras que tendría sentido para darle un flotador.

Por ejemplo, 3.1415926535... resultaría en 245/78, en lugar de 314/100 o 22/7.

En términos de eficiencia, esto se llamaría alrededor de tres veces en el inicio del programa, pero después de eso en absoluto. Por lo que un algoritmo lenta no es también mal.

¿Fue útil?

Solución

He escrito algo de código (en Java, incluso) para hacer exactamente lo que estás pidiendo. En mi caso, tenía que mostrar un factor de escala tanto como un porcentaje y una relación. El ejemplo más conocido de esto es el diálogo de zoom que se ve en los editores de imágenes, tales como el GIMP.

Puede encontrar el código de aquí , en el método updateRatio () a partir de la línea 1161. simplemente puede usarlo, siempre y cuando la licencia LGPL que funciona para usted. Lo que hice en esencia sigue lo que se hace en el GIMP --- esta es una de esas cosas donde hay más o menos sólo una manera eficiente, sensible a hacerlo.

Otros consejos

Este es el código que utilicé en el final (basado en el código de uckelman)

public static int[] GetFraction(double input)
{
    int p0 = 1;
    int q0 = 0;
    int p1 = (int) Math.floor(input);
    int q1 = 1;
    int p2;
    int q2;

    double r = input - p1;
    double next_cf;
    while(true)
    {
        r = 1.0 / r;
        next_cf = Math.floor(r);
        p2 = (int) (next_cf * p1 + p0);
        q2 = (int) (next_cf * q1 + q0);

        // Limit the numerator and denominator to be 256 or less
        if(p2 > 256 || q2 > 256)
            break;

        // remember the last two fractions
        p0 = p1;
        p1 = p2;
        q0 = q1;
        q1 = q2;

        r -= next_cf;
    }

    input = (double) p1 / q1;
    // hard upper and lower bounds for ratio
    if(input > 256.0)
    {
        p1 = 256;
        q1 = 1;
    }
    else if(input < 1.0 / 256.0)
    {
        p1 = 1;
        q1 = 256;
    }
    return new int[] {p1, q1};
}

Gracias por los que ayudaron

¿Qué tan preocupado está usted acerca de la eficiencia? Si usted no está llamando a esta función de conversión de 100s de veces por segundo o más, entonces probablemente no sería tan difícil de fuerza bruta a través de todas las posibles denominador (más probable es que sólo 255 de ellos) y encontrar la que se da el más cercano aproximación (calculando el numerador para ir con el denominador es la constante de tiempo).

Me gustaría comentar, pero no tengo representante embargo ...

La respuesta de Eric anterior no considera el caso en que un resultado exacto es posible. Por ejemplo, si se utiliza 0,4 como entrada, a continuación, la representación debe ser 2/5, en cuyo caso se termina con una división por cero en la tercera iteración del bucle (r = 0 en segundo bucle => r = 1 / error r en tercera).

Así que usted quiere modificar el bucle while para excluir esa opción:

while(true)

debería ser

while(r != 0)

Usted debe mirar la secuencia de Farey.
Dado un límite en el denominador d, la secuencia de Farey es cada fracción que tiene denominador <= d.

A continuación, sólo tendría que tomar su flotador y compararlo con el valor de la fracción resuelto Farey. Esto le permitirá representar a su flotador en términos reales de repetir-decimales.

Esta es una página sobre su aplicación en Java:
http://www.merriampark.com/fractions.htm

Esta es una buena demostración de su uso:
http://www.maths.surrey.ac .uk / sitios alojados / R.Knott / fracciones / fareySB.html

¿Qué pasa con el uso de BigFraction de Apache:

import org.apache.commons.math3.fraction.BigFraction;

public static BigFraction GetBigFraction(double input)
{
    int precision = 1000000000;
    return new BigFraction((int)(input * (double)precision), precision);
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top