Bennu Game Development

Foros en Español => Sugerencias => Topic started by: HaCkZJuaNN on February 23, 2009, 08:15:22 PM

Title: tan(90000) = 1.#inf
Post by: HaCkZJuaNN on February 23, 2009, 08:15:22 PM
Qué activo estoy últimamente xD, se me nota no?

Bien, así de casualidad he descubierto que tan(90000) da un valor muy alto (concretamente 16331778499280896), pero lo cierto es que ya que te has molestado en incluir el 1.#inf cuando un valor se hace infinito, matemáticamente tan(90000) = infinito, así que se podría hacer que esto diera así realmente. Idem para tan(-90000) = tan(270000) = -1.#inf

Por cierto, he comprobado que mientras que sin(90000) = 1 y cos(90000) = 0, sin(90000)/cos(90000) = el número ese grande; y también, mientras que 1.0/0.0 = 1.#inf, 1.0/cos(90000) = el número grande de nuevo, así que parece que el problema está en la función coseno que da un valor que es cero sin serlo al mismo tiempo, y a lo mejor es lo mismo que origina mi problema del otro post.

Un saludo.
Title: Re: tan(90000) = 1.#inf
Post by: SplinterGU on February 23, 2009, 08:52:18 PM
q version de bennu usas?

los valores que retorna son los valores que da las funciones en C, no voy a cambiar eso...
Title: Re: tan(90000) = 1.#inf
Post by: HaCkZJuaNN on February 24, 2009, 12:34:30 PM
Utilizo r22. Comprueba lo que te estoy diciendo, haz un simple say(tan(90000)), o say(cos(90000)+"/"+1.0/cos(90000))...
Title: Re: tan(90000) = 1.#inf
Post by: SplinterGU on February 24, 2009, 03:02:26 PM
ya lo hice cuando te respondi, es el comportamiento de las funciones C, devuelven eso...
Title: Re: tan(90000) = 1.#inf
Post by: Sandman on February 24, 2009, 05:07:57 PM
Mathematically the tangens of an odd multiple of 90 degrees does not exist. This is the same as saying that the tangens of an odd multiple of (PI/2) does not exist. This shows the problem: A computer cannot calculate PI/2, because it has an infinite precision. C (math.h) uses the constant M_PI to approach PI (and M_PI_2 for PI/2). But because this is only approaching PI (and PI/2), it is not 100% accurate. So if you use it to calculate the tangens, you get what you ask for: the tangens of the value (which does NOT equal PI/2).

Now like I did suggest to SplinterGU earlier, this can be justified in Bennu. Bennu says that the tangens of an odd multiple of 90 degrees exists (16331778499280896), which is mathematically incorrect. Because Bennu uses 1/1000th of a degree as precision, we can fix it for special cases.


static int math_tan( INSTANCE * my, int * params )
{
    float param = *( float * ) & params[0] ;
    float res;
    if( ( (int)( param+90000) % 180000 ) == 0 )
        res = 0.0/0.0;
    else
        res = ( float )tan(( double )( param * M_PI / 180000.0 ) ) ;
    return *(( int * )&res ) ;
}


Similar solutions can be made for cos() and others. It is a decision.

I realize that this solution only has the range -2^31 .. 2^31-1. There are most probably better solutions available, but I did not look into the problem that deep. Yes, modulo is not the cheapest operation.
Title: Re: tan(90000) = 1.#inf
Post by: HaCkZJuaNN on February 24, 2009, 07:04:59 PM
yes, i get it, that was my suggestion, although i understand that if it consumes a lot more than it consumes without including that, it is not that necessary, but if a specific condition for that case can be added easily, then it is perfect.

Btw, in the case it is an odd multiple of 90000, the tangent is infinite, that is to say, 1.0/0.0, not indetermined(0.0/0.0), because the tangent is equal to sinus/cosinus, which is 1.0/0.0 in the case of 90000 or pi/2.

***************************************************************

Si lo cojo, esa era mi sugerencia, aunque entiendo que si éso consume mucho más que sin incluirlo, no es realmente necesario, pero si una condición especial para ese caso puede ser añadido fácilmente, entonces perfecto.

Por cierto, en el caso the un múltiplo impar de 90000, la tangente es infinitio, es decir, 1.0/0.0, no indeterminado(0.0/0.0), dado que la tangente es igual a seno/coseno, que es 1.0/0.0 en el caso de 90000 o pi/2.

Un saludo.
Title: Re: tan(90000) = 1.#inf
Post by: SplinterGU on February 24, 2009, 07:21:45 PM
no, consumir no consume nada...

la cosa es que podria emparchar la funcion tan, pero no puedo resolver esta expresion "sin(90000)/cos(90000)" si da un valor incorrecto... y para hacer las cosas a medias es mejor no hacerlas, si es un error de las funciones C, supongo que en algun momento se resolvera.

por lo pronto quizas puedas hacer una excepcion por codigo... pero supongo que habra algunas otras cuantas excepciones... y no puedo contemplar todas emparchandolas...
Title: Re: tan(90000) = 1.#inf
Post by: SplinterGU on February 24, 2009, 07:46:15 PM
creo que encontre la solucion...
por que en vez de usar "cos" usas "sin" como inversa de "cos"

ejemplo:


import "mod_math";
import "mod_say";
begin
say (cos(90000.0));
say (sin(90000.0));
say (sin(90000.0-90000.0));
say (cos(33000.0));
say (sin(33000.0));
say (sin(90000.0-33000.0));

say (sin(90000.0)/sin(90000.0-90000.0)); // sin(90000.0 - (angle))
say (sin(90000.0)/cos(90000.0));

end


posiblemente seria

#define cos2(a) sin(90000-((int)(a)%90000))
Title: Re: tan(90000) = 1.#inf
Post by: HaCkZJuaNN on February 24, 2009, 07:49:34 PM
Oh, funciona, 1.0/sin(0) = 1.#inf. Buena idea, gracias. Un saludo.
Title: Re: tan(90000) = 1.#inf
Post by: HaCkZJuaNN on February 24, 2009, 08:18:28 PM
Vale, funciona con 0, pero 1.0/sin(180000) no da infinito. Supongo que da lo mismo, tampoco es demasiado grave, está bien.
Title: Re: tan(90000) = 1.#inf
Post by: SplinterGU on February 24, 2009, 08:23:59 PM
es cierto, dame unos minutos...
Title: Re: tan(90000) = 1.#inf
Post by: Sandman on February 24, 2009, 08:29:32 PM
lim x->90 ( tan(x) ) is not defined, because:
lim x->90- ( tan(x) ) is infinite+
lim x->90+ ( tan(x) ) is infinite-

otherwise said:
lim x->0+ ( tan(90-x) ) is inifinite+
lim x->0+ ( tan(90+x) ) is inifinite-

otherwise said:
lim x->0+ ( sin(90-x)/cos(90-x) ) is inifinite+
lim x->0+ ( sin(90+x)/cos(90+x) ) is inifinite-

Checkout the picture (http://upload.wikimedia.org/wikipedia/commons/7/79/Graf_tangens.png).
Title: Re: tan(90000) = 1.#inf
Post by: SplinterGU on February 24, 2009, 08:31:01 PM
decime si esto da ok


import "mod_math";
import "mod_say";

function float cos2(int ang)
begin
    if ( ang < 0 ) ang = -ang ; end
    if ( ang > 360000 ) ang %= 360000 ; end
    if ( ang > 270000 ) return sin(90000 - (360000 - ang)) ; end
    if ( ang > 180000 ) return -sin(90000 - (180000 - ang)) ; end
    if ( ang > 90000  ) return -sin(90000 - (ang - 180000)) ; end

    return sin(90000 - ang);
end

begin
say (cos(30000));
say (cos2(30000));

say (cos(70000));
say (cos2(70000));

say (cos(90000.0));
say (cos2(90000.0));

say (cos(170000.0));
say (cos2(170000.0));

say (cos(180000.0));
say (cos2(180000.0));

say (cos(190000.0));
say (cos2(190000.0));

say (cos(230000.0));
say (cos2(230000.0));

say (cos(270000.0));
say (cos2(270000.0));

say (cos(280000.0));
say (cos2(280000.0));

say (cos(340000.0));
say (cos2(340000.0));


say (sin(90000.0)/cos(90000.0));
say (sin(90000.0)/cos2(90000.0));

say (sin(90000.0)/cos(180000.0));
say (sin(90000.0)/cos2(180000.0));

end


bien, ahora, yo puedo reemplazar las funciones cos por esta funcion y la de tangente por sin(x)/cos(x), para que de valores correctos, pero imagino que otras funciones tambien deben estar imprecisas... si conoces las formulas pasamelas y puedo intentar hacer un mod_math mas preciso...
Title: Re: tan(90000) = 1.#inf
Post by: HaCkZJuaNN on February 24, 2009, 11:03:19 PM
Ok, sandman is correct, i forgot that tan(90000) could be plus or minus infinite, so its indeterminate. I'm checking what splintergu wrote...

**************************************

Ok, sandman tiene razón, se me olvidó que tan(90000) podría ser más o menos infinito, así que es indeterminado. Estoy comprobando lo que escribió splintergu.

Para splintergu: No creo que haya otras funciones que sean imprecisas en ese sentido. Qué más funciones complejas de este tipo hay??? pow, que lleva la inexactitud propia de lo que significan(para exponentes no enteros), que es incorregible matemáticamente en un sistema decimal con número limitado de cifras, sqrt, más de lo mismo, y el resto creo que funcionan bien. De todas maneras, yo me estoy haciendo mi propio módulo programado en bennu de matemáticas, mucho más complejo que esto, muchísimo más, pero en algunas cosas me baso en lo que hay en bennu y una de ellas son las funciones trigonométricas, dado que sino tendría que hacer series de Taylor, muy largas y que consumirían muchíiiisima CPU.
Title: Re: tan(90000) = 1.#inf
Post by: HaCkZJuaNN on February 24, 2009, 11:20:09 PM
Vale, splinter, creo que te has armado más follón del que era necesario, y para 270º no funciona como debe.

Ahora, siendo estrictamente correctos, tiene razón sandman, tan(90000) = ind y tan(270000) = ind, pero dado que a pesar de ser indeterminado, en realidad tiene que ser + o - infinito, podríamos decir que es simplemente infinito, ni más ni menos, para identificar su naturaleza, y para poder decir que 1/tan(90000) = 0, porque lo es, mientras que 1/1.#ind da 1.#ind. Personalmente soy partidario de decir que tanto tan(90000) como tan(270000) son infinito, teniendo en cuenta que el signo es indeterminado(quiero decir que lo tiene que tener en cuenta el programador al hacer su programa). Sobre el tema de las indeterminaciones, 1.0/0.0 también es indeterminado, puesto que el 0 puede ser 0 positivo o negativo, dando + o - infinito, pero se asume que 1.#inf puede ser tanto + como - infinito, es más práctico a la hora de programar.

Con respecto a cómo hacerlo, recomiendo simplemente esto:
[code language="bennu"]
function float cos2(float angulo)
begin
    if(angulo == 90000.0 or angulo == 270000.0)
        return 0.0;
    end
    return cos(angulo);
end

function float sin2(float angulo)
begin
    if(angulo == 0.0 or angulo == 180000.0)
        return 0.0;
    end
    return sin(angulo);
end

function float tan2(float angulo)
begin
    return sin2(angulo)/cos2(angulo);
end
[/code]

Eso debería funcionar.

Por cierto, las otras funciones trigonométricas(las funciones arco), funcionan bien, asin y acos devuelven indeterminado cuando el parámetro está fuera de rango(-1..1), y a atan a veces hay que sumarle 180º para que te de el ángulo correcto, pero eso también pasa con la función arcotangente más correcta que tengas, dado que sólo le pasas el resultado de una división, y no las dos componentes...

De todas formas, yo tengo mis propias funciones seno y coseno para el programa este que menciono, utilizando tipos definidos y tal, pero el hecho de que tan(90000) me diera un valor me jorobaba un poco el tema. Sin embargo, si pudieras incluir esto dentro del propio bennu, se agradecería :)

Un saludo.

Title: Re: tan(90000) = 1.#inf
Post by: SplinterGU on February 24, 2009, 11:23:51 PM
como que con 270000 no funciona? esta en el ejemplo, si que funciona.
Title: Re: tan(90000) = 1.#inf
Post by: osk on February 24, 2009, 11:26:46 PM
Oye HaCkZJuaNN, ¿publicarás esa librería matemática que estás haciendo? Digo yo que podría servir para facilitar algunos calculillos para física de juegos y similares, si dices que es tan completa, no?
Title: Re: tan(90000) = 1.#inf
Post by: SplinterGU on February 24, 2009, 11:27:46 PM
no, las funciones asi tan simples no sirven, que pasa si le paso 540000 (360000+180000) o 450000 (360000+90000) o incluso valores negativos...

no es tan simple como un simple if... y por otra parte, eso que puse no es invento mio, esta originalmente de Fenix y hay algunas libs que lo hacen...
Title: Re: tan(90000) = 1.#inf
Post by: HaCkZJuaNN on February 25, 2009, 05:27:31 PM
Supongo que sí la publicaré, primero la pienso utilizar para hacer un programa de matemáticas propiamente dicho y luego tengo pensado hacer algunos de física y demás ciencias. De todas formas aún le queda tiempo, y aviso para los posibles interesados de que lo que es performance no va a tener demasiado, aunque muchos parámetros son ajustables para elegir entre precisión y velocidad, pero tiene límites(sobre todo en velocidad). Además, debido a las limitaciones de bennu con tipos definidos y retornos de funciones(hay que pasar variables como punteros, etc), algunas cosas se pueden hacer un poco tediosas, pero bueno, a mi me sirve, y si alguien más quiere utilizarla cuando la haya terminado, pues bien :)

Sobre lo de 270000, lo que no funciona es la tangente, prueba sin2(270000)/tan2(270000), da un valor, y debería dar infinito o indeterminado.

Sobre lo de ángulos mayores, basta con sustituir el if(angulo == 90000.0 or angulo = 270000.0) por if(abs(angulo%360000) == 90000.0 or abs(angulo%360000) == 270000.0) y lo mismo para el seno. El resto de casos da valores determinados que funcionan bien con las funciones directamente pasadas de c.

De todas formas, ya me he equivocado 2 veces, así que seguramente me esté olvidando de algo otra vez xDDD

Otro saludo más.