2010-01-13 31 views
49

Tuve esta extraña experiencia con el problema número 10 en Project Euler (gran sitio por cierto). La tarea era calcular la suma de todos los números primos por debajo de dos millones.Sin excepción de desbordamiento para int en C#?

Usé un int para la suma, y ​​mi algoritmo produjo una respuesta, pero cuando pegué para verificar la respuesta, estaba equivocado.

Resultó que el resultado era demasiado grande para caber en un int, pero ¿no causaría esto un error de desbordamiento o algo así? En cambio, simplemente devolvió un valor muy alejado de la respuesta real.

Cuando cambié el tipo a largo, todo era Hunky Dory.

+5

Está seguro de querer cada operación de número entero para comprobar si hay desbordamiento? –

+4

Bueno, me hubiera ahorrado algo de tiempo en este caso particular;) – erikric

+1

En este caso, sí. La gran mayoría de las operaciones no pueden desbordarse sin embargo. Sería interesante si el compilador pudiera probar esto y deshabilitar la comprobación como resultado, pero dudo mucho que lo haga. – Thorarin

Respuesta

73

C# operaciones enteras no arrojan excepciones al desbordamiento de forma predeterminada. Usted puede lograr que a través de la configuración del proyecto, o al hacer el cálculo checked:

int result = checked(largeInt + otherLargeInt); 

Ahora la operación arrojará.

Lo opuesto es unchecked, lo que hace que cualquier operación esté explícitamente desmarcada. Obviamente, esto solo tiene sentido cuando tienes operaciones comprobadas habilitadas en la configuración del proyecto.

+0

A menos que esté en modo de depuración, donde creo que las operaciones int están marcadas por defecto. – Ant

+5

No. Corrí en modo de depuración cuando esto ocurrió. – erikric

+0

Oh. Estoy corregido. Estaba seguro de que mis proyectos Project Euler me informaron sobre los desbordamientos en el modo de depuración.:/ – Ant

19

En C# no se lanza OverflowException (en VB se produce la excepción por defecto).

Para obtener el excpetion hay que incrustar el código en un contexto checked:

byte value = 241; 
checked 
{ 
    try 
    { 
     sbyte newValue = (sbyte) value; 
     Console.WriteLine("Converted the {0} value {1} to the {2} value {3}.", 
      value.GetType().Name, value, 
      newValue.GetType().Name, newValue); 
    } 
    catch (OverflowException) 
    { 
     Console.WriteLine("Exception: {0} > {1}.", value, SByte.MaxValue); 
    } 
}  

MSDN explica con más detalle:

Para la aritmética, la fundición, o conversión de la operación de tirar una OverflowException, la operación debe ocurrir en un contexto verificado. Por predeterminado, las operaciones aritméticas y los desbordamientos en Visual Basic están marcados; en C#, no lo son. Si la operación se produce en un contexto sin marcar, el resultado se trunca al descartar cualquier bits de orden superior que no quepan en el tipo de destino.

6

i ya ha añadido un cmt, pero es tal vez interesante para algunos de ustedes:

msdn nos dice:

desbordamiento aritmética de enteros ya sea lanza una OverflowException o descartes la mayoría de bits significativos de el resultado

pero

Desglose aritmético decimal siempre arroja una OverflowException.

también

Cuando se produce desbordamiento de enteros, lo que sucede depende del contexto de ejecución , que puede ser marcada o sin marcar. En un contexto verificado, se genera una OverflowException . En un contexto sin marcar , la mayoría de los bits significativos del resultado se descartan y la ejecución continúa. Por lo tanto, C# le ofrece la opción de manipular o ignorar el desbordamiento.

+0

Lo cual tiene sentido, ya que los decimales se usan principalmente para cálculos monetarios o científicos, y probablemente preferiría que se lanzaran y luego fallaran silenciosamente. – Snellface

6

De forma predeterminada, C# no comprueba el desbordamiento aritmético en enteros. Puede cambiar esto con /checkedcompiler option o habilitando "Comprobar el desbordamiento/subdesbordamiento aritmético" en Visual Studio (propiedades del proyecto - Construir - Avanzado).

Puede usar checked and unchecked keywords para anular el valor predeterminado caso por caso. Si confía en que la verificación tiene lugar en un código, habilitarlo explícitamente usando checked sería una buena idea.

int j = checked(i * 2); 

checked 
{ 
    int j = i * 2; 
    // Do more stuff 
} 

Tenga en cuenta que las operaciones de punto flotante no lanzan una OverflowException, y las operaciones decimales siempre lanzan una OverflowException. Consulte también C# operators.

9

Se debe a que, de forma predeterminada, C# no arroja ninguna excepción para el desbordamiento de enteros ni para el subdesbordamiento. Hay un par de cosas que puedes hacer aquí.

Opción 1

Tienes que habilitar la excepción de ser arrojado por ir a Proyecto => propiedades => Construir tab => Avanzada => comprobar si hay desbordamiento desbordamiento aritmético. (Asegúrese marque la opción)

enter image description here

Asegúrese de marcar la opción

Opción 2

Use un bloque comprobado y lanzar una excepción de desbordamiento de manejar la situación. Un fragmento de código de muestra sería

 try 
     { 
      checked 
      { 
       int y = 1000000000; 
       short x = (short)y; 
      } 
     } 
     catch (OverflowException ex) 
     { 
      MessageBox.Show("Overflow"); 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show("Error"); 
     } 

Hope esto le ayudará a ... :)

+2

La opción 1 es el punto crucial que muchas personas no conocen. Obtienes mi +1. – RBT

Cuestiones relacionadas