2012-01-18 8 views
15

Me enseño a mí mismo C y descubro que cuando hago una ecuación para una conversión temporal no funcionará a menos que cambie la fracción a un decimal. es decir,¿Por qué la división resulta en cero en lugar de decimal?

tempC=(.555*(tempF-32)) funcionarán pero tempC=((5/9)*(tempF-32)) no funcionará.

¿Por qué?
De acuerdo con C Primer Plus debería funcionar ya que estoy usando flotadores para tempC y tempF.

Respuesta

16

Parece que usted tiene una división entera en el segundo caso:

tempC=((5/9)*(tempF-32)) 

El 5/9 conseguirá truncada en cero.

Para corregir esto, es necesario hacer una de ellas un tipo de punto flotante:

tempC=((5./9.)*(tempF-32)) 
+2

Es truncamiento, sin embargo, no se redondea. – jmkeyes

+0

Gracias por la corrección terminológica. :) – Mysticial

+0

doh! Gracias ... eso tiene sentido ahora. Vi algunos ejemplos con el decimal pero el centavo no cayó. ¡Gracias a todos! –

0

Si pones 5/9 entre paréntesis, esto se calculará en primer lugar, y puesto que esas son dos números enteros, se realizará por división entera y el resultado será 0, antes de que se evalúe el resto de la expresión.

Puede reorganizar su expresión para que la conversión a flotar ocurra primero:

tempC=((5/9)*(tempF-32));tempC=(5*(tempF-32))/9;

o, por supuesto, como dicen los otros, utilizar constantes de coma flotante.

+0

Incluso si no estuvieran entre paréntesis, aún podrían evaluarse como enteros. El orden de evaluación de esta expresión es un comportamiento no especificado en C, el compilador puede elegir evaluar de izquierda a derecha o de derecha a izquierda, y no puede saber qué orden de evaluación se aplica. – Lundin

+1

No del todo cierto. ¡El paréntesis tiene un efecto! Si se asegura de que el primer cálculo que se realiza da como resultado un flotante, el resto de la expresión no volverá a ser un número entero. He aumentado mi respuesta para mostrar lo que quiero decir. –

+0

El ejemplo reescrito no es equivalente a eliminar el paréntesis, ha cambiado intencionalmente el orden de evaluación. 'tempC = 5/9 * (tempF-32);' es un ejemplo con el paréntesis eliminado. Este ejemplo puede dar o no el resultado deseado, según si el compilador evalúa de izquierda a derecha o de derecha a izquierda: se basa en un comportamiento no especificado. – Lundin

1

5/9 es una expresión entera, como tal, se trunca a 0. su compilador debería advertirle acerca de esto, de lo contrario, debería considerar habilitar advertencias.

+3

Realmente no veo por qué debería advertir. No hay forma de que el compilador indique el valor que alguien quiere que tengan sus constantes enteras. – Lundin

+1

@Lundin: es por eso que sería una advertencia (pedante). si una expresión entera constante arroja cero, debería ser cero o hubo un descuido. – Necrolis

+0

No necesariamente, puede haber muchos casos en los que desee una expresión constante con el resultado 0. Por ejemplo, 'result = SOME_CONSTANT & MASK;' bien puede dar como resultado cero. Digamos que tienes operaciones similares de enmascaramiento de bits en todo el código, con máscaras diferentes. Entonces no querrás cientos de advertencias, ¿por qué deberías ser castigado solo porque escribes un código genérico y consistente sin ningún número mágico? – Lundin

2

Al hacer 5/9, 5 y 9 son ambos enteros y división de enteros sucede. El resultado de la división entera es un número entero y es el cociente de los dos operandos. Entonces, el cociente en el caso de 5/9 es 0 y dado que se multiplica por 0, el valor de tempC es 0. Para no tener una división entera, al menos uno de los dos operandos debe ser float.

E.g. si usa 5.0/9 o 5/9.0 o 5.0/9.0, funcionará como se esperaba.

5

Otros ya le han dicho, 5 y 9 son ambos enteros y es por eso que el resultado se trunca.

voy a añadir una explicación para la comprensión más profunda de lo que realmente sucede entre las líneas:

double tempC; 
double tempF; 
tempC = (5/9) * (tempF-32); // removed unnecessary parenthesis 

dependiendo de qué orden de evaluación, de izquierda a derecha o de derecha a izquierda su compilador específico utiliza, o comenzará a evaluar la sub-expresión (5/9) o (tempF-32).

¡No puede saber cuál de estos dos se evalúa primero! Porque el orden de evaluación es un comportamiento no especificado en C, lo que significa que el compilador puede hacerlo de cualquier manera sin documentar cómo. Por lo tanto, nunca se debe escribir un código que dependa del orden de evaluación, o no será portátil y posiblemente incorrecto.


Supongamos que un compilador específico utiliza la evaluación de izquierda a derecha.

  • Las reglas de precedencia del operador de C deciden dónde comienza la evaluación. El operador de paréntesis tiene la prioridad más alta en C, por lo que el compilador comenzará evaluando el contenido del primer paréntesis encontrado.
  • Por lo tanto, comenzará con la expresión (5/9).
  • El compilador comprueba el tipo de cada operando.
  • En este caso, ambos son literales enteros constantes. Los literales enteros siempre son del tipo int en C.
  • Como ambos operandos son del mismo tipo, no se necesitan conversiones de tipo implícitas.
  • El cálculo se realiza en un tipo int y el resultado es un int.

Así que ahora la expresión se evalúa ahora a:

tempC = (int)0 * (tempF-32);

  • El compilador evalúa entonces (tempF-32).
  • Los tipos de operandos son double y int. No son del mismo tipo.
  • Se producen conversiones de tipo implícito. En este caso, algo llamado balanceo (formalmente llamado las conversiones aritméticas usuales).
  • Las reglas de equilibrio dicen que si un tipo es doble y el otro es algo diferente, el otro tipo debe convertirse a doble.
  • Después de la conversión de tipo implícita, la expresión ahora es equivalente a (double)tempF - (double)32.0. El resultado de esto se calcula y almacena en una variable temporal e invisible de tipo double. Esta variable invisible se almacena en un registro de CPU o en la pila.

Ahora la expresión puede ser descrito como

tempC = (int)result1 * (double)result2;

donde "RESULT1" es 0 y "result2" es el resultado de tempF - 32.0.

  • El compilador luego evalúa esta nueva expresión. Encuentra un int y un double.
  • De nuevo, se produce el equilibrio y el int se convierte en un doble.
  • La multiplicación se realiza en dos dobles, y el resultado es un doble.
  • El resultado se almacena en otra variable temporal e invisible.

tempC = (double)result3;

  • El compilador evalúa esta nueva expresión.Encuentra que un doble debe guardarse dentro de un doble. Eso no es un problema, por lo que no se necesitan conversiones implícitas. "result3" se almacena en tempC.
+4

El orden de las subexpresiones de evaluación no importa en absoluto aquí, ya que ninguno tiene ningún efecto secundario. – aschepler

+1

El orden de evaluación importaría solo si lo escribió así: '5/9 * (tempF-32)' ahora se eliminan todos los paréntesis innecesarios. Evaluado desde tempF "hacia afuera" daría un doble. Si pones '(5/9) * cualquier cosa' siempre será '0', a menos que algún compilador levante mágicamente dicha expresión, lo que probablemente incluso sería contrario al estándar, pero no apostaría a ello. – luk32

2

5/9 es una división de números enteros y no de coma flotante. Es por eso que estás obteniendo resultados incorrectos.

Haga 5 o 9 coma flotante variable y obtendrá la respuesta correcta.

Me gusta 5.0/9 O 5/9.0

+0

De acuerdo. Siempre es una buena práctica agregar también el 'f' que denota punto flotante a las constantes. Del mismo modo, el 'u' para las constantes de enteros sin signo – Andrew

Cuestiones relacionadas