2016-06-24 8 views
1

Von dem, was ich verstehe, in C der unsigned Typ wie Arithmetik verhält (unsigned hat 32-Bit-Länge vorausgesetzt) ​​in dem Integer-Ring Modulo 4294967296.in C unter Verwendung unsigned mit negativen temporären Ergebnissen

So scheint es zu folgen aus der grundlegenden Ringtheorie, dass, wenn wir eine ganze Zahl haben (jetzt ich meine ℤ!) Berechnung mit *+-, dann egal, welche Art von Überläufen und Unterläufen vorübergehend passieren, das Endergebnis wird korrekt sein, solange das Ende Ergebnis liegt im Bereich [0, 2^32]?

Zum Beispiel in der folgenden Berechnung:

#include <stdio.h> 

int main(void){ 

    unsigned v = 50000; 
    unsigned w = 100000; 
    unsigned x = 300000; 
    unsigned y = 20000; 
    unsigned z = 4000000000; 

    unsigned r = v*w - x*y + z; 

    printf("v*w - x*y + z = %u \n", r); 

    return 0; 
} 

wir temporäre Ergebnisse, die von den Ergebnissen abweichen, die wir bekommen, wenn wir in z berechnen würden, aber wir haben noch die richtige Antwort.

Ist das richtig oder kann irgendetwas schiefgehen?

+4

Das ist richtig. Es gibt keine negativen temporären Ergebnisse, alle Schritte werden mit modularer Arithmetik durchgeführt. – Barmar

+0

Als eine persönliche Anmerkung: '4 * 1000 * 1000 * 1000' ist ein bisschen mehr tippen, aber viel besser lesbar (und ich bezweifle, dass Sie dies sehr oft eingeben). Zu schlecht C erlaubt keine Unterstriche in Integer-Konstanten. – Olaf

+1

Oder '# define BILLION * 1000 * 1000 * 1000' gefolgt von' unsigned z = 4 MILLIARDE; '- Ich habe oft gefunden, dass lesbarer. Zumindest, bis wir benutzerdefinierte Literale a la C++ oder Perls schlaue '1_000_000'-Typ-Literale erhalten. – paxdiablo

Antwort

2

Per C11 6.2.5 Types /9 (Hervorhebung von mir):

Eine Berechnung ohne Vorzeichen Operanden beinhalten, können nie überlaufen, weil ein Ergebnis, das nicht durch die resultierende unsigned Integer-Typ dargestellt werden kann, wird Modulo reduziert die Zahl, die um eins größer ist als der größte Wert, der durch den resultierenden Typ dargestellt werden kann.

Mit anderen Worten, vorausgesetzt, die Typen sind nicht signiert, und der Modulwert Sie verwenden möchten, ist UINT_MAX + 1 und die Art ist die richtige Breite (alle diese wahr sind, ist in diesem speziellen Fall), das funktioniert wie erwartet.

Sie sollten die Konstanten jedoch korrekt als unsigniert angeben, um sicherzustellen, dass in der Konstante selbst kein Überlauf auftritt (C verwendet in diesem Fall einen breiteren signierten Typ, vorausgesetzt, Sie können diesen breiteren Typ zuweisen ein unsigned int, sollte es keine Probleme geben - es kann Probleme geben, wenn Sie zum Beispiel keine Zweierkomplement-Implementierung verwenden, unwahrscheinlich, dass das ist.

Sie sollten auch einen Typ garantiert verwenden, um groß genug zu sein, da unsigned int auf einigen Plattformen weniger als 32 Bit breit sein kann.

Mit anderen Worten, sollten Sie Ihre Aussagen der Form sein:

unsigned long z = 4000000000U; 

Das, bedeutet natürlich, müssen Sie Ihre eigenen Modul-Operationen, da ein unsigned long tun kann mehr als 32 sein Bits breit.

Natürlich, wenn Ihre Plattform bietet, ist es weit mehr vorzuziehen, die feste Breite Typen, uint32_t in Ihrem Fall zu verwenden. Auf diese Weise erhalten Sie einen Goldilocks-Typen (weder zu klein noch zu groß, und auf jeden Fall Zweierkomplement)) und Sie können lassen C selbst die Modulo-Operationen handhaben:

uint32_t z = 4000000000U; 

dass die Lösung wäre ich gehen für.

+1

Der zitierte Standard Absatz ist irrelevant; es sagt, dass die Sache, die der Standard "Überlauf" nennt, was ein undefiniertes Verhalten ist, nicht für vorzeichenlose Operanden auftritt, weil es nicht definiert ist. Stattdessen passiert etwas anderes, dass die meisten Leute immer noch "Überlauf" nennen, aber der Standard nicht. – immibis

+0

@immibis, war ich vielleicht nicht klar dort, das Schnipsel gibt spezifisch das Verhalten des Bewegens über den Enden des Bereichs an. Ich habe den ganzen Absatz eingefügt, aber das wichtige ist nicht "kann nie überlaufen", wie Sie vorschlagen, aber "ist modulo reduziert ...". Ich werde das hervorheben, um es klarer zu machen. Für das, was es wert ist (was vielleicht nicht viel ist), was "am meisten [Zitat benötigt :-)] Leute Überlauf nennen, rufe ich Wraparound. – paxdiablo

+0

Was meinen Sie mit: * Technisch gesehen ist 4000000000 eine vorzeichenbehaftete Konstante und wird wahrscheinlich Ihren vorzeichenbehafteten 32-Bit-Integer-Typ überlaufen lassen. *? OP weist vorzeichenlose Typen zu, die nicht überlaufen können. – 2501

Verwandte Themen