Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: AprendiendoAProgramar en 25 Enero 2017, 23:35 pm



Título: no tiene sentido este simple código.
Publicado por: AprendiendoAProgramar en 25 Enero 2017, 23:35 pm
Esto no tiene sentido, se supone que debería dar el cuadrado de el numero pero siempre bota el numero -1.
Ejemplo:
5^2 = 24.                         .____.
.-. Por favor, ¿qué pasó? D: Soy nuub en esto.
no sé si será mi pc o que pasará.
Código
  1. #include <iostream>
  2. #include <windows.h>
  3. #include <cmath>
  4.  
  5.  
  6.  
  7. using namespace std;
  8.  
  9. int Cuadrado(int);
  10.  
  11.  
  12. int main(){
  13.  
  14.    int Numero;
  15.  
  16.  
  17.    cout<<" Ingrese Numero "<<endl;
  18.    cin>>Numero;
  19.  
  20.    cout<<"El cuadrado del numero es: "<<Cuadrado(Numero)<<endl;
  21.  
  22.  
  23.    system("pause");
  24.  return 0;
  25.  
  26. }
  27.  
  28.  
  29. int Cuadrado(int a){
  30.  
  31.  
  32.    a = pow(a,2);
  33.  
  34.    return a;
  35.  
  36.  
  37.  
  38. }



· No se debe escribir en mayúsculas
>aquí las reglas del foro (http://foro.elhacker.net/reglas.htm)
-Engel Lex


Título: Re: NO TIENE SENTIDO ESTE SIMPLE CÓDIGO.
Publicado por: engel lex en 25 Enero 2017, 23:51 pm
el código está bueno, a mi  (quetandole windows.h y system porque ando en linux) me funciona perfecto

como lo estás ejecutando?


Título: Re: no tiene sentido este simple código.
Publicado por: AprendiendoAProgramar en 26 Enero 2017, 00:30 am
ESTO ES LO QUE SE EJECUTA. :-\ :-\ :-\ :-\ :-\ :-(




(https://i.screenshot.net/3o268i9)


Título: Re: no tiene sentido este simple código.
Publicado por: engel lex en 26 Enero 2017, 00:54 am
ya... es un lio de precisión de coma flotante...
https://es.wikipedia.org/wiki/Coma_flotante

los nuevos no se deberían dar con estos problemas pero eres desafortunado

qué pasa?

pow retorna un valor tipo double, pero por el asunto de la precisión en números de coma flotante, cuando haces pow(5,2) retorna 24.999999999 que a efectos de incluso otras cuentas matemáticas es 25.... pero cuando lo conviertes a int, el solo toma la parte entera y descarta los decimales, quedando en 24

http://www.cplusplus.com/reference/cmath/pow/


Título: Re: no tiene sentido este simple código.
Publicado por: lgamerm en 26 Enero 2017, 01:02 am
 
Esto no tiene sentido, se supone que debería dar el cuadrado de el numero pero siempre bota el numero -1.
Ejemplo:
5^2 = 24.                         .____.
.-. Por favor, ¿qué pasó? D: Soy nuub en esto.
no sé si será mi pc o que pasará.
Código
  1. #include <iostream>
  2. #include <windows.h>
  3. #include <cmath>
  4.  
  5.  
  6.  
  7. using namespace std;
  8.  
  9. int Cuadrado(int);
  10.  
  11.  
  12. int main(){
  13.  
  14.    int Numero;
  15.  
  16.  
  17.    cout<<" INGRESE NUMERO "<<endl;
  18.    cin>>Numero;
  19.  
  20.    cout<<"El cuadrado del numero es: "<<Cuadrado(Numero)<<endl;
  21.  
  22.  
  23.    system("pause");
  24.  return 0;
  25.  
  26. }
  27.  
  28.  
  29. int Cuadrado(int a){
  30.  
  31.  
  32.    a = pow(a,2);
  33.  
  34.    return a;
  35.  
  36.  
  37.  
  38. }



· No se debe escribir en mayúsculas
>aquí las reglas del foro (http://foro.elhacker.net/reglas.htm)
-Engel Lex


cambia esto: a = pow(a,2); por esto: a *= a;


Título: Re: no tiene sentido este simple código.
Publicado por: MAFUS en 26 Enero 2017, 09:33 am
Es muy raro. Tanto 5 como 25 tiene una cantidad muy baja de bits como para que se pierda información.


Título: Re: no tiene sentido este simple código.
Publicado por: do-while en 26 Enero 2017, 12:31 pm
Es muy raro. Tanto 5 como 25 tiene una cantidad muy baja de bits como para que se pierda información.
Nunca me he preocupado de los temas técnicos de los compiladores, pero puede que sea alguna particularidad del compilador que esté usando. Me acuerdo que cuando empecé a programar descubrí que distintos compiladores alineaban de forma distinta los campos de los structs (Borland y Mingw). Puede ser eso.


Título: Re: no tiene sentido este simple código.
Publicado por: engel lex en 26 Enero 2017, 15:24 pm
Es muy raro. Tanto 5 como 25 tiene una cantidad muy baja de bits como para que se pierda información.

ellos la tendran... pero los float no... aquí un visualizador

https://float-visualizer.surge.sh/


5 = 01000000101000000000000000000000
25 = 01000001110010000000000000000000

mira la perdida de precisión tu mismo cuanto da 25?

en hecho, es más preciso 510423550381407695195061911147652317184 que 25 XD (por la mantissa)


Título: Re: no tiene sentido este simple código.
Publicado por: MAFUS en 26 Enero 2017, 18:43 pm
Prueba el siguiente programa:
Código
  1. #include <stdio.h>
  2.  
  3. void bits(double n) {
  4.    for(int b = sizeof(double) * 8 - 1; b >= 0 ; --b) {
  5.        printf("%lu", *(long unsigned*)&n >> b & 1);
  6.    }
  7. }
  8.  
  9. int main() {
  10.    printf("\n\n%.25lf\n", 0.1);
  11.    bits(0.1);
  12.  
  13.    printf("\n\n%.25lf\n", 5.);
  14.    bits(5);
  15.  
  16.    printf("\n\n%.25lf\n", 25.);
  17.    bits(25);
  18. }

Como puedes ver no hay pérdida de precisión. En cambio si la hay en 0.1, que pasado a binario IEEE754:

Código:
0011111110111001100110011001100110011001100110011001100110011010

Como se puede ver hay una periodicidad que tiende a infinito.



Título: Re: no tiene sentido este simple código.
Publicado por: AprendiendoAProgramar en 26 Enero 2017, 20:52 pm

Primero que todo muchas gracias por la ayuda. ;D ;-)


¿ Pero entonces el problema es mi compilador ? Y si es así.
¿ que tengo que hacer para que no suceda eso?

recién aprendo a programar y no quiero meterme en problemas tan técnicos como estos pero que al fin y al cabo influyen de manera importante al compilar un programa, si fuera un trabajo y me salieran estos errores no sabría corregirlos de manera correcta. Y no, no se vale sumarle la cantidad que le falte.  :xD :xD

GRACIAS.


Título: Re: no tiene sentido este simple código.
Publicado por: ivancea96 en 26 Enero 2017, 23:07 pm
¿Qué compilador utilizas y qué versón?

En cualquier caso, si solo es vas a elevear a 2 o a 3, es preferible que pongas x*x o x*x*x. Es más simple, y bueno, evitas trabajar con coma flotante.

Oh y, en tu código, ¿qué muestra si cambias "int a" por "float a"?


Título: Re: no tiene sentido este simple código.
Publicado por: AprendiendoAProgramar en 27 Enero 2017, 03:56 am

El compilador que viene en Code::Blocks el GNU GCC Compiler supongo. :silbar:


Si, se que es más simple pero solo quería probar esa librería y darle uso por si se me ocurría elevar a la 45 de un numero.

Y cambiando int por float curiosamente si da 25, que raro, no entiendo como es posible jajaja  ;D


Título: Re: no tiene sentido este simple código.
Publicado por: engel lex en 27 Enero 2017, 04:05 am
es error de precisión por el float! XD

mira el enlace que dejé para que veas como está armado el float

vas como mucho poder elevar 2 a la 45... como unsigned int 2^32 es el maximo y con unsigned long int el maximo es 2^64, otros valores, especialmente floats los puedes llegar pero sin precisión


Título: Re: no tiene sentido este simple código.
Publicado por: AprendiendoAProgramar en 27 Enero 2017, 21:21 pm
¿Pero hay alguna forma o compilador para arreglar ese desfase de bits ? :silbar: :silbar: :silbar: :silbar: :silbar:



Muchas gracias por las respuestas,gracias  :D


Título: Re: no tiene sentido este simple código.
Publicado por: ivancea96 en 27 Enero 2017, 22:44 pm
También podría ser la CPU. GCC, por lo menos en mi versión, convierte el float a int con el opcode FISTPL (http://x86.renejeschke.de/html/file_module_x86_id_98.html). ¿Usas un ordenador antiguo o algo notable?
Si quieres, puedes probar a ejecutar el mismo programa en otro PC. Lo compilas y pasas el ejecutable al otro pc, a ver qué resultado te da.


Título: Re: no tiene sentido este simple código.
Publicado por: do-while en 28 Enero 2017, 15:03 pm
Si yo fuese tu utilizaría el tipo de dato que me devuelve pow que, si mal no recuerdo, como en ¿casi? todas las funciones de math.h (cmath) es double.

Si vas a asignar o mezclar variables de distintos tipos en una expresión tienes que tener en cuenta las reglas de promoción. Si a una variable le asignas el valor de otra de menor tamaño no tendrás pérdida de datos: char->int->float->double. Si a una variable le asignas el valor de otra de mayor tamaño tendrás un truncamiento (perdida de datos, sigue la lista anterior en orden inverso).

Lo anterior se traduce en que si a un entero le asignas el valor de una variable de tipo real (float/double) vas a perder datos (en el mejor de los casos perderás decimales), como en este caso, que 24'99999 pasa a ser 24.

Cuando aplicas las reglas de promoción a expresiones (operadores aritméticos/paso de parámetros) lo que pasa es que un operador promociona las variables para que sean del tipo de la de mayor tamaño involucrada en la operación. Por ejemplo int = int + float -> se promociona a float el operando int para ajustar su tamaño  al del otro operando (float)-> int = float + float -> int = float -> perdida de datos. Otro ejemplo: una función con lista de parámetros (lo que sea, double, lo que sea)-> llamada: (lo que sea, int, lo que sea) -> promocionamos el int para que sea del tipo declarado en el prototipo. Si fuese a la inversa, con prototipo declarado como (lo que sea, int, lo que sea) y llamamos con datos (lo que sea, float, lo que sea) habría una perdida de datos al forzar la conversión de float a int.

No se si ha quedado claro o no. Lee sobre el tema y tenlo en cuenta a la hora de escribir cualquier código, así evitarás problemas y errores derivados del truncamiento, que por cierto, como no son errores del lenguaje el código compilará, pero se producirán errores lógicos en tiempo de ejecución,  muy difíciles de localizar en el código.

Por ejemplo imagina que tienes una condición if(Cuadrado(x) == 25) ... En este caso la condición habría sido falsa, pero posiblemente tu al revisar el código hubieses dado por válida la expresión y te habrías vuelto loco intentando encontrar el error en otra parte.

¡Saludos!

(Por si no te ha quedado claro, las reglas de promoción las aplica el compilador al crear el binario, no nosotros. XD)