tan(90000) = 1.#inf

Started by HaCkZJuaNN, February 23, 2009, 08:15:22 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

HaCkZJuaNN

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.

SplinterGU

q version de bennu usas?

los valores que retorna son los valores que da las funciones en C, no voy a cambiar eso...
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

HaCkZJuaNN

Utilizo r22. Comprueba lo que te estoy diciendo, haz un simple say(tan(90000)), o say(cos(90000)+"/"+1.0/cos(90000))...

SplinterGU

ya lo hice cuando te respondi, es el comportamiento de las funciones C, devuelven eso...
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

Sandman

#4
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.
-- Sandman

HaCkZJuaNN

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.

SplinterGU

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...
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

SplinterGU

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))
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

HaCkZJuaNN

Oh, funciona, 1.0/sin(0) = 1.#inf. Buena idea, gracias. Un saludo.

HaCkZJuaNN

Vale, funciona con 0, pero 1.0/sin(180000) no da infinito. Supongo que da lo mismo, tampoco es demasiado grave, está bien.

SplinterGU

es cierto, dame unos minutos...
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

Sandman

#11
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.
-- Sandman

SplinterGU

#12
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...
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

HaCkZJuaNN

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.

HaCkZJuaNN

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.