2012-06-29 22 views
13
 string[] strArray = new string[10] { "21.65", "30.90", "20.42", "10.00", "14.87", "72.19", "36.00", "45.11", "18.66", "22.22" }; 
     float temp = 0.0f; 
     Int32 resConvert = 0; 
     Int32 resCast = 0; 
     for (int i = 0; i < strArray.Length; i++) 
     { 
      float.TryParse(strArray[i], out temp); 
      resConvert = Convert.ToInt32(temp * 100); 
      resCast = (Int32)(temp * 100); 
      Console.WriteLine("Convert: " + resConvert + " ExplCast: " + resCast); 
     } 

Respuesta:Entero Conversión en C#

Convert: 2165 ExplCast: 2164 // ?? 
    Convert: 3090 ExplCast: 3089 // ?? 
    Convert: 2042 ExplCast: 2042 
    Convert: 1000 ExplCast: 1000 
    Convert: 1487 ExplCast: 1486 //?? 
    Convert: 7219 ExplCast: 7219 
    Convert: 3600 ExplCast: 3600 
    Convert: 4511 ExplCast: 4511 
    Convert: 1866 ExplCast: 1865 //?? 
    Convert: 2222 ExplCast: 2221 //?? 

Por qué el valor difiere veces mientras se hace conversión explícita, pero no siempre. ¿Alguna razón?

+0

intente Int64 en el lugar de Int32 –

+0

@Rana: ¿Cuál es el problema con Int32? ¿Alguna razón específica? –

+1

R.S. Rana: Eso es una tontería por valores tan pequeños. – Joey

Respuesta

9

Para tomar un ejemplo, el formato 21.65 en float en realidad está representado por un número como 21.6499999. El Convert.ToInt32 redondea el número al entero más cercano, obteniendo 21.65, mientras que el molde explícito (Int32) simplemente trunca (redondeando hacia cero), por lo que obtiene 21.64.

Si desea que los números de coma flotante se representen en la computadora de la misma manera en que se ven impresos, use decimal en lugar de float o double.

+0

Gracias por la respuesta Gabe. Pero por qué no está en todos los escenarios. Por ej. Convertir: 4511 ExplCast: 4511 // OK Convertir: 2222 ExplCast: 2221 // ?? –

+1

22.22 no se puede codificar exactamente como un número de coma flotante. Cuando multiplicas por 100, terminas con un valor como 2221.999999 – spender

+0

Round-to-even es el comportamiento '.Round' predeterminado en .NET, ¿no? Ver http://stackoverflow.com/questions/311696/why-does-net-use-bankers-rounding-as-default –

4

Convert.ToInt32rounds to the nearest integer, el lanzamiento directo solo trunca el número.

lo tanto, si, debido a la imprecisión punto flotante, tiene un valor de 2165.99999whatever en lugar de 2165.0, el reparto directo trunca todo después de la coma flotante, mientras que Convert.ToInt32 redondea al número entero más cercano.

Ejemplo:
22.22f * 100.0f produce algo así como 2221.99993133544921875.
Así que Convert.ToInt32 lo redondeará hasta al valor esperado 2222, mientras que el molde lo truncará a 2221.

45.11f * 100.0f en los otros resultados mano en cerca de 4511.00006103515625,
que Convert.ToInt32 rondas abajo, lo que resulta en 4511, el mismo resultado que cuando se lanza directamente.

+0

Gracias, no sabía que – Kane

1

Creo que encontrará que el problema está causado por imprecisiones con precisión de punto flotante, específicamente al usar float. Encontrará que el problema desaparece al usar un decimal. Hay una muy buena respuesta sobre las diferencias entre decimal y doble (y flotante) aquí: decimal vs double! - Which one should I use and when?

+0

Hola otra vez @Kane. Esto es engañoso. Pruebe esto: (int) ((1 m/3 m) * 300 m) (pista, no es 100). Los decimales pueden ser más apropiados para algunos tipos de números, flotadores binarios para otros, pero ambos son susceptibles a este tipo de problema. (pero en el caso de que las cadenas de decimales sean analizadas, el decimal sería el camino correcto) – spender

2

Después de la respuesta Botz3000, secciones relevante de MSDN:

Convert.ToInt32 Method (Single)

Valor devuelto Tipo: System.Int32 valor, redondeado a la de 32 bits entero con signo más cercano. Si el valor está a medio camino entre dos números enteros, se devuelve el número par ; es decir, 4,5 se convierte en 4, y 5.5 se convertidos a 6.

Explicit Numeric Conversions Table

• Cuando se convierte a partir de un valor doble o flotador para un tipo entero, se redondea el valor hacia cero al valor integral más cercano.Si el valor integral resultante está fuera del rango del valor de destino, el resultado depende del contexto de verificación de desbordamiento. En un contexto comprobado , se lanza una OverflowException, mientras que en un contexto sin marcar , el resultado es un valor no especificado del tipo de destino.

1

Calling Convert.ToInt32 es como decir:

(int) Math.Round(floatValue, 0);

colada directa es como llamar

(int) Math.Floor(float);

piso siempre le da un valor menor o igual al valor usted suministra en el argumento. Las representaciones de coma flotante no son "precisas". Entonces, 21.65 probablemente se representa como 21.649999 o similar, ya que no hay suficiente precisión.

Así: 21,65 * 100 = 2164,9999 Pisos este valor debe darle un número entero que es menor o igual a 2.164,9 ... es decir: 2164

Completando 2.164,99 por el contrario le daría: 2165

Se puede ver el efecto aquí:

Console.WriteLine(Math.Round(21.65f*100)); //2165 
Console.WriteLine(Math.Floor(21.65f*100)); //2164 

el uso de dobles en lugar de de flotador (más precisión, pero todavía no es infinita):

Console.WriteLine(Math.Round(21.65d*100)); //2165 
Console.WriteLine(Math.Floor(21.65d*100)); //2165 
+0

Gracias por la respuesta. Pero por qué no está en todos los escenarios –

+0

Ah, es por la forma en que los números de punto flotante se almacenan en la memoria. Algunos números se pueden representar con precisión, algunos números no pueden ser.Un montón de detalles sangrientos aquí: http://en.wikipedia.org/wiki/Single_precision – Grynn

+1

Pruebe esta página: http://www.binaryconvert.com/result_float.html?decimal=050049046054053 La mejor representación de 21.65 = 2.16499996185302734375E1 La mejor representación de 20.42 = 2.042E3 (¡agradable y precisa!) – Grynn

Cuestiones relacionadas