2012-03-31 25 views
6

He implementado un algoritmo para aproximación decimal de coma flotante a fracción racional (ejemplo: 0.333 -> 1/3) y ahora me pregunto, ¿hay alguna manera de encontrar un número irracional que satisfaga la condición? Por ejemplo, dada la entrada 0.282842712474 quiero que el resultado sea sqrt (2)/5 y no 431827/1526739 que produce mi algoritmo. La única condición es que los primeros dígitos del resultado (convertido de nuevo a punto flotante) deben ser los dígitos de la entrada, el resto no importa. ¡Gracias por adelantado!Aproximación de fracción decimal a fracción irracional

+2

Usted tendría al menos que tenga que colocar un poco de c onstraints sobre posibles resultados. ¿Solo te interesan los enteros enteros? –

+0

"La única condición" no parece compatible con querer "sqrt (2)/5": su R + sqrt (2)/10^k racional para algunas k grandes funcionaría de lo contrario. – DSM

+0

Si solo hay raíces cuadradas en el numerador y/o denominador que le interesan, por qué, puede cuadrar la entrada antes de alimentarlo con su algoritmo. Pero, por supuesto, esto es derrotado por números tan simples como el seno de 15 grados, que es (sqrt (3.0) -1.0)/(2.0 * sqrt (2.0)). – thb

Respuesta

2

Se me ocurrió una solución, que a partir de un conjunto dado de posibles denominadores y nominadores encuentra la mejor aproximación de un número dado.

Por ejemplo, este conjunto puede contener todos los números que pueden ser creados por:
= radicando < = 100000
= root_index < = 20

Si conjunto tiene N elementos, que esta solución encuentra mejor aproximación en O (N log N).

En esta solución X representa el denominador y el nominador Y.

  1. Ordenar números de serie
  2. para cada X número de serie:
    utilizando binario encontrar más pequeño Y tal que Y/X> = número_entrada
    comparar Y/X, actualmente con mejor aproximación de número_entrada

no pude resistir y me implementado:

#include <cstdio> 
#include <vector> 
#include <algorithm> 
#include <cmath> 
using namespace std; 

struct Number { 
    // number value 
    double value; 

    // number representation 
    int root_index; 
    int radicand; 

    Number(){} 
    Number(double value, int root_index, int radicand) 
    : value(value), root_index(root_index), radicand(radicand) {} 

    bool operator < (const Number& rhs) const { 
    // in case of equal numbers, i want smaller radicand first 
    if (fabs(value - rhs.value) < 1e-12) return radicand < rhs.radicand; 
    return value < rhs.value; 
    } 

    void print() const { 
    if (value - (int)value < 1e-12) printf("%.0f", value); 
    else printf("sqrt_%d(%d)",root_index, radicand); 
    } 
}; 

std::vector<Number> numbers; 
double best_result = 1e100; 
Number best_numerator; 
Number best_denominator; 

double input; 

void compare_approximpation(const Number& numerator, const Number& denominator) { 
    double value = numerator.value/denominator.value; 

    if (fabs(value - input) < fabs(best_result - input)) { 
     best_result = value; 
     best_numerator = numerator; 
     best_denominator = denominator; 
    } 
} 

int main() { 

    const int NUMBER_LIMIT = 100000; 
    const int ROOT_LIMIT = 20; 

    // only numbers created by this loops will be used 
    // as numerator and denominator 
    for(int i=1; i<=ROOT_LIMIT; i++) { 
    for(int j=1; j<=NUMBER_LIMIT; j++) { 
     double value = pow(j, 1.0 /i); 
     numbers.push_back(Number(value, i, j)); 
    } 
    } 

    sort(numbers.begin(), numbers.end()); 

    scanf("%lf",&input); 

    int numerator_index = 0; 

    for(int denominator_index=0; denominator_index<numbers.size(); denominator_index++) { 
    // you were interested only in integral denominators 
    if (numbers[denominator_index].root_index == 1) { 
     // i use simple sweeping technique instead of binary search (its faster) 
     while(numerator_index < numbers.size() && numbers[numerator_index].root_index && 
    numbers[numerator_index].value/numbers[denominator_index].value <= input) { 
     numerator_index++; 
     } 

     // comparing approximations 
     compare_approximpation(numbers[numerator_index], numbers[denominator_index]); 
     if (numerator_index > 0) { 
    compare_approximpation(numbers[numerator_index - 1], numbers[denominator_index]); 
     } 
    } 
    } 

    printf("Best approximation %.12lf = ", best_numerator.value/best_denominator.value); 
    best_numerator.print(); 
    printf("/"); 
    best_denominator.print(); 
    printf("\n"); 
} 
Cuestiones relacionadas