2010-01-13 10 views
49

Ich hatte diese seltsame Erfahrung mit Problem Nummer 10 auf Project Euler (tolle Seite übrigens). Die Aufgabe bestand darin, die Summe aller Primzahlen unter zwei Millionen zu berechnen.Keine Überlauf-Ausnahme für int in C#?

Ich benutzte ein int für die Summe, und mein Algorithmus produzierte eine Antwort, aber als ich es eingefügt habe, um die Antwort zu verifizieren, war es falsch.

Es stellte sich heraus, dass das Ergebnis zu groß war, um in einen Int zu passen, aber würde dies nicht zu einem Überlauffehler oder etwas führen? Stattdessen hat es nur einen Wert zurückgegeben, der weit von der wirklichen Antwort entfernt ist.

Als ich den Typ zu lang änderte, war alles gut.

+5

Wollen Sie wirklich jede Integer-Operation für einen Überlauf zu überprüfen? –

+4

Nun, es hätte mir in diesem speziellen Fall etwas Zeit gespart;) – erikric

+1

In diesem Fall ja. Die überwiegende Mehrheit der Operationen kann jedoch möglicherweise nicht überlaufen. Es wäre interessant, wenn der Compiler dies beweisen und die Überprüfung als Ergebnis deaktivieren könnte, aber ich bezweifle es sehr. – Thorarin

Antwort

73

C# Integer-Operationen geben standardmäßig keine Ausnahmen bei Überlauf aus. Sie können das über die Projekteinstellungen erreichen, oder durch die Berechnung machen checked:

int result = checked(largeInt + otherLargeInt); 

Nun wird die Operation werfen.

Das Gegenteil ist unchecked, die jede Operation explizit deaktiviert. Dies ist natürlich nur dann sinnvoll, wenn Sie in den Projekteinstellungen die aktivierten Kontrollkästchen aktiviert haben.

+0

Es sei denn, Sie sind im Debug-Modus, wo ich denke, Int-Operationen sind standardmäßig aktiviert. – Ant

+5

Nein. Ich lief im Debug-Modus, als dies geschah. – erikric

+0

Oh. Ich stehe korrigiert. Ich war mir sicher, dass meine Project Euler-Projekte mir von Überläufen im Debug-Modus erzählt haben.:/ – Ant

19

In C# wird kein OverflowException geworfen (in VB wird die Ausnahme standardmäßig ausgelöst).

Um die excpetion Sie Ihren Code in einem checked Kontext einbetten müssen:

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 erklärt im Detail:

Für die Arithmetik, Gießen oder Umwandlungsoperation zu werfen Eine OverflowException muss die Operation in einem überprüften Kontext auftreten. Von Standard, arithmetische Operationen und Überläufe in Visual Basic werden überprüft; in C# sind sie nicht. Wenn die Operation in einem ungeprüften Kontext auftritt, wird das Ergebnis abgeschnitten durch irgendwelche höherwertigen Bits zu verwerfen, die in der Zieltyp nicht passen.

6

ich habe hinzugefügt, die bereits ein cmt, aber es ist vielleicht interessant für einige von Ihnen:

msdn sagt uns:

Integer-Arithmetik-Überlauf entweder löst eine Overflow oder verwirft die meisten signifikante Bits von das Ergebnis

aber

Dezimal arithmetischer Überlauf löst immer eine OverflowException aus.

auch

Wenn Integer-Überlauf auftritt, was geschieht, hängt von der Ausführung Kontext, der oder ungeprüft geprüft werden kann. In einem überprüften Kontext wird eine OverflowException ausgelöst. In einem unmarkierten Kontext werden die meisten signifikanten Bits des Ergebnisses verworfen und die Ausführung wird fortgesetzt. Somit gibt Ihnen C# die Möglichkeit den Überlauf zu behandeln oder zu ignorieren.

+0

Das ist sinnvoll, da Dezimalzahlen meist für Währungsrechnungen oder wissenschaftliche Berechnungen verwendet werden und Sie sie wahrscheinlich lieber werfen und dann stumm schlagen würden. – Snellface

6

Standardmäßig überprüft C# nicht auf arithmetischen Überlauf auf Ganzzahlen. Sie können dies mit dem /checkedcompiler option ändern oder indem Sie in Visual Studio (Projekteigenschaften - Build - Advanced) "Auf arithmetischen Überlauf/Unterlauf prüfen" aktivieren.

Sie können den Standard von Fall zu Fall mit checked and unchecked keywords überschreiben. Wenn Sie sich darauf verlassen, dass die Überprüfung in einem Codeabschnitt stattfindet, wäre es eine gute Idee, sie explizit mit checked zu aktivieren.

int j = checked(i * 2); 

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

Beachten Sie, dass Gleitkommaoperationen nie eine OverflowException werfen, und Dezimal-Operationen immer ein OverflowException werfen. Siehe auch C# operators.

9

Das liegt daran, dass C# standardmäßig keine Ausnahme für Integer-Überlauf und Unterlauf auslöst. Es gibt ein paar Dinge, die Sie hier tun können.

Option 1

Sie haben die Ausnahme zu ermöglichen gehen geworfen werden, indem man auf Projekt => Eigenschaften => Build tab => Erweitert => prüfen Unterlauf arithmetischer Überlauf. (Stellen Sie sicher, tick die Option)

enter image description here

Achten Sie darauf, die Option ankreuzen

Option 2

Verwenden Sie einen Block geprüft und einen Überlauf Ausnahme auslösen, die Situation zu bewältigen. Ein Beispielcode-Ausschnitt würde

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

Hoffnung, dies wird Ihnen helfen ... :)

+2

Option 1 ist die Crux, die viele Leute nicht kennen. Du bekommst meine +1. – RBT