2008-12-18 10 views
7

¿Hay una biblioteca que convertirá un Doble en una Cadena con el número entero, seguido de una fracción?Formato Doble como Fracción

Por ejemplo

1.125 = 1 1/8 

Sólo estoy buscando para las fracciones a un 64o de una pulgada.

Respuesta

5

Un problema con el que pueden toparse es que no todos los valores fraccionarios se pueden representar por dobles. Incluso algunos valores que parecen simples, como 0.1. Ahora con el algoritmo de pseudocódigo. Probablemente sea mejor que determine la cantidad de 64ths de una pulgada, pero dividiendo la porción decimal por 0.015625. Después de eso, puedes reducir tu fracción al mínimo común denominador. Sin embargo, dado que indica las pulgadas, es posible que no desee utilizar el denominador común más pequeño, sino solo los valores para los que usualmente se representan las pulgadas, 2,4,8,16,32,64.

Sin embargo, una cosa para señalar es que, dado que está usando pulgadas, si los valores son todas fracciones de una pulgada, con un denominador de 2,4,8,16,32,64, entonces el valor nunca debería contienen errores de punto flotante, porque el denominador siempre tiene una potencia de 2. Sin embargo, si tu conjunto de datos tuviera un valor de .1 pulgada allí, entonces comenzarías a tener problemas.

+0

Los datos que entra es buena (siempre en 64ths de una pulgada) – Milhous

3

No estoy de acuerdo, basándome en el hecho de que Milhous quiere cubrir pulgadas hasta 1/64 " Supongamos que el programa exige una precisión de 1/64" en todo momento, que debería ocupar 6 bits de la mantisa. En un carro, hay 24-6 = 18, lo que (si mis cálculos son correctos), debería significar que tiene un rango de +/- 262144 + 63/64 "

Eso podría ser suficiente precisión en el flotador para convertir correctamente en la facción sin pérdida.

Y puesto que la mayoría de las personas que trabajan en pulgadas utiliza denominador de potencias de 2, que debería estar bien.

Pero volviendo a la pregunta original, no sé ninguna biblioteca que haría eso.

1

La función para esto en una variante C llamada LPC sigue. Algunas notas:

  1. La adición al valor de entrada al principio es tratar de hacer frente a problemas de precisión que de lo contrario terminaría diciendo que 5 es 4 999999/1000000.
  2. La función to_int() trunca a entero.
  3. El lenguaje tiene un to_string() que convertirá algunos flotantes en notación exponencial.

string strfrac(float frac) { 
    int main = to_int(frac + frac/1000000.0); 
    string out = to_string(main); 
    float rem = frac - to_float(main); 
    string rep; 
    if(rem > 0 && (to_int(rep = to_string(rem)) || member(rep, 'e') == Null)) { 
     int array primes = ({ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47 }); 
     string base; 
     int exp; 
     int num; 
     int div; 
     if(sscanf(rep, "%se%d", base, exp) == 2) { 
      num = to_int(replace(base, ".", "")); 
      div = to_int(pow(10, abs(exp))); 
     } else { 
      rep = rep[2..]; 
      num = to_int(rep); 
      div = to_int(pow(10, strlen(rep))); 
     } 
     foreach(int prime : primes) { 
      if(prime > num) 
       break; 
      while((num/prime) * prime == num && (div/prime) * prime == div) { 
       num /= prime; 
       div /= prime; 
      } 
     } 
     out += " " + num + "/" + div; 
    } 
    return out; 
} 
10

Su problema es bastante simple, ya que está asegurado el denominador siempre dividirá 64. en C# (que alguien se sienta libre de traducir una versión de Java):

string ToMixedFraction(decimal x) 
{ 
    int whole = (int) x; 
    int denominator = 64; 
    int numerator = (int)((x - whole) * denominator); 

    if (numerator == 0) 
    { 
     return whole.ToString(); 
    } 
    while (numerator % 2 == 0) // simplify fraction 
    { 
     numerator /= 2; 
     denominator /=2; 
    } 
    return string.Format("{0} {1}/{2}", whole, numerator, denominator); 
} 

Bono: Código Golf

public static string ToMixedFraction(decimal x) { 
    int w = (int)x, 
     n = (int)(x * 64) % 64, 
     a = n & -n; 
    return w + (n == 0 ? "" : " " + n/a + "/" + 64/a); 
} 
+0

atención al activar el denominador, incluso para-dad es innecesaria. Ver mi versión de Java – erickson

+0

egads, tienes razón :) – Jimmy

+0

Ahora mira lo que me hiciste hacer ... una vez que comienzas a recortar el código simplemente no puedes parar. – Jimmy

0

Mi código es así.

public static int gcd(int a, int b) 
    { 
     if (b == 0) 
      return a; 
     else 
      return gcd(b, a % b); 
    } 

public static String doubleToStringFraction(Double d) 
    { 
     StringBuffer result = new StringBuffer(" " + ((int) Math.floor(d))); 
     int whole = (int) ((d - Math.floor(d)) * 10000); 
     int gcd = gcd(whole, 10000); 
     result.append(" " + (whole/gcd) + "/" + 10000/gcd + " "); 
     return result.toString(); 
    } 
-1

Para resolver este problema (en uno de mis proyectos), tomé los siguientes pasos:

  • Se construyó un diccionario de cadenas decimal/fracción.
  • Escribió una función para buscar en el diccionario la fracción de coincidencia más cercana dependiendo de la parte "decimal" del número y los criterios coincidentes.
4

¿Qué tal org.apache.commons.math? Tienen una clase Fraction que toma un doble.

http://commons.apache.org/math/api-1.2/org/apache/commons/math/fraction/Fraction.html

Usted debe ser capaz de extender y darle funcionalidad para la 64a. Y también puede agregar un toString que imprimirá fácilmente la parte del número entero de la fracción por usted.

Fracción (valor doble, Int maxDenominator) Crear una fracción dado el valor doble y máximo denominador.

+0

Le doy un vistazo, gracias. – Milhous

0

Como han salido muchas otras, las fracciones de 64 pueden ser representadas con precisión por IEEE-floats. Esto significa que también podemos convertir a una fracción moviendo y enmascarando bits.

Este no es el lugar para explicar todos los detalles de las representaciones de punto flotante, consulte wikipedia para obtener más información.

En pocas palabras: un número de punto flotante se almacena como (signo) (exp) (frac) donde signo es 1 bit, exp es 11 bits y frac es la parte de fracción (después de 1.) y es 52 bits. Esto se enterpreted como el número:

(sign == 1 ? -1 : 1) * 1.(frac) * 2^(exp-1023) 

Por lo tanto, podemos obtener la 64 moviendo el punto de accoring al exponente y el enmascaramiento de los 6 bits después de la coma. En Java:

private static final long MANTISSA_FRAC_BITMAP = 0xfffffffffffffl; 
private static final long MANTISSA_IMPLICIT_PREFIX = 0x10000000000000l; 
private static final long DENOM_BITMAP = 0x3f; // 1/64 
private static final long DENOM_LEN = 6; 
private static final int FRAC_LEN = 52; 

public String floatAsFrac64(double d) { 
    long bitmap = Double.doubleToLongBits(d); 
    long mantissa = bitmap & MANTISSA_FRAC_BITMAP | MANTISSA_IMPLICIT_PREFIX; 
    long exponent = ((bitmap >> FRAC_LEN) & 0x7ff) - 1023; 
    boolean negative = (bitmap & (1l << 63)) > 0; 

    // algorithm: 
    // d is stored as SE(11)F(52), implicit "1." before F 
    // move point to the right <exponent> bits to the right: 
    if(exponent > FRAC_LEN) System.out.println("warning: loosing precision, too high exponent"); 
    int pointPlace = FRAC_LEN-(int)exponent; 
    // get the whole part as the number left of the point: 
    long whole = mantissa >> pointPlace; 
    // get the frac part as the 6 first bits right of the point: 
    long frac = (mantissa >> (pointPlace-DENOM_LEN)) & DENOM_BITMAP; 
    // if the last operation shifted 1s out to the right, we lost precision, check with 
    // if any of these bits are set: 
    if((mantissa & ((MANTISSA_FRAC_BITMAP | MANTISSA_IMPLICIT_PREFIX) >> (pointPlace - DENOM_LEN))) > 0) { 
     System.out.println("warning: precision of input is smaller than 1/64"); 
    } 
    if(frac == 0) return String.format("%d", whole); 
    int denom = 64; 
    // test last bit, divide nom and demon by 1 if not 1 
    while((frac & 1) == 0) { 
     frac = frac >> 1; 
     denom = denom >> 1; 
    } 
    return String.format("%d %d/%d", whole, frac, denom); 
} 

(este código, probablemente, puede hacerse más corto, pero la lectura de bit-flipping-código como esto es suficiente ya que es difícil ...)

1

escribí esto para mi proyecto espero podría ser útil:

//How to "Convert" double to fraction("a/b") - [email protected] 
private boolean isInt(double number){ 
    if(number%2==0 ||(number+1)%2==0){ 
     return true; 
    } 
    return false; 
} 
private String doubleToFraction(double doub){ 
    //we get the whole part 
    int whole = (int)doub; 
    //we get the rest 
    double rest = doub - (double)whole; 
    int numerator=1,denominator=1; 
    //if the whole part of the number is greater than 0 
    //we'll try to transform the rest of the number to an Integer 
    //by multiplying the number until it become an integer 
    if(whole >=1){ 
     for(int i = 2; ; i++){ 
      /*when we find the "Integer" number(it'll be the numerator) 
      * we also found the denominator(i,which is the number that transforms the number to integer) 
      * For example if we have the number = 2.5 when it is multiplied by 2 
      * now it's 5 and it's integer, now we have the numerator(the number (2.5)*i(2) = 5) 
      * and the denominator i = 2 
      */ 
      if(isInt(rest*(double)i)){ 
       numerator = (int)(rest*(double)i); 
       denominator = i; 
       break; 
      } 
      if(i>10000){ 
       //if i is greater than 10000 it's posible that the number is irrational 
       //and it can't be represented as a fractional number 
       return doub+""; 
      } 
     } 
     //if we have the number 3.5 the whole part is 3 then we have the rest represented in fraction 0.5 = 1/2 
     //so we have a mixed fraction 3+1/2 = 7/2 
     numerator = (whole*denominator)+numerator; 
    }else{ 
     //If not we'll try to transform the original number to an integer 
     //with the same process 
     for(int i = 2; ; i++){ 
      if(isInt(doub*(double)i)){ 
       numerator = (int)(doub*(double)i); 
       denominator = i; 
       break; 
      } 
      if(i>10000){ 
       return doub+""; 
      } 
     } 
    } 
    return numerator+"/"+denominator; 
} 
0

Creo simplemente la biblioteca Fraction.

La biblioteca está disponible aquí: https://github.com/adamjak/Fractions

Ejemplo:

String s = "1.125"; 
Fraction f1 = Fraction.tryParse(s); 
f1.toString(); // return 9/8 

Double d = 2.58; 
Fraction f2 = Fraction.createFraction(d); 
f2.divide(f1).toString() // return 172/75 (2.29) 
Cuestiones relacionadas