C: Berechnung Summe negativer Zahlen?
Hi,
die Funktion soll die Summe aller negativen, ungeraden, ganzen Zahlen, die >= einer Zahl x < 0 sind, berechnen.
Beispiel:
Mein Teilcode:
int i;
int n;
void Summe(int k) {
if (k > 0) {
printf("Error\");
}
else {
for (i = 0; i <= k; i++) {
n = n + 1;
}
}
}
Ich denke, der Fehler liegt in der if-Schleife. Wenn ich -8 eingebe, kommt 0 raus.
5 Antworten
Die Schleifenbedingung ist i<=k. 0 ist aber nie kleiner als eine negative Zahl. Dass k negativ ist, stellst du sogar schon im if sicher. Entweder du lässt i rückwärts laufen (i--) oder du musst bei i=k starten.
Übrigens: Der Code ist optimierbar.
Desweiteren lässt sich die Summe von ungeraden Zahlen als Quadratzahlen schreiben.
Upps, du musst noch die geraden Zahlen heraus fischen:
for(i=k; i<0; i++)
if(i%2==1)
n+=i
Oder Vorweg k auf die nächste ungerade Zahl stellen und dann mit 2 inkrementieren:
if(k%2==0)
k++;
for(i=k; i<0; i+=2)
n+=i
Achtung, negative Zahlen! (i%2==1) wird nicht klappen ;-)
Natürlich klappt das. Was sollte daran nicht klappen? Modulo funktioniert bei negativen Zahlen genauso.
Dann ist der Modulo schlecht programmiert worden in der Programmiersprache. Der Modulo liefert standardmäßig den kleinsten nichtnegativen Repräsentanten.
Nö, es ist schlichtweg kein Modulo, sondern Remainder. Andere Funktion, andere Semantik.
Macht bei positiven Operanden keinen Unterschied. Python, Ruby, Perl implementieren ein mod bei % während C/C++, Java... den Remainder implementieren.
Mit der Formel (a/b)*b +a%b =a stimmt etwas nicht. (a/b) * b lässt sich vereinfachen zu a.
a + a%b = a bedeutet, dass a%b = 0 ist. Das ist aber nicht allgemeingültig.
/ ist dabei natürlich die Ganzzahldivision, mein Fehler.
(Also Beispiel 9/2 =4 (*2 =8), also liefert a%b=1, analog -7/2 = -3 ( *2= -6) entsprechend liefert hier a%b -1. Gelegentlich wird es auch als symmetrisches Modulo bezeichnet, nicht zu verwechseln mit dem Modulo, wie wir es in der Zahlentheorie kennen.
Letztlich liegt die Wurzel im Rechenwerk, C ist da recht nah an der Maschine. Wenn ich die Division als Folge von Subtraktionen (respektive Additionen) darstelle, zähle die Anzahl mit, bis der Remainder im Betrag zu klein geworden ist, erhalte ich das Ganzzahldivisionsergebnis und im Quellregister verbleibt dann der Remainder.
Viele ISAs haben dann eben auch die Operation, die gleich beides liefert. Und viele Programmiersprachen bieten diese Operation dann auch direkt an, wobei auch hier die Ergebnisse überraschen können. Python meint divmod (-7,2) ist (-4,1), C sagt div(-7,2) ist (-3,-1).
Und so kann man jede Menge Spaß haben, wenn man vorher nicht genau die Spezifikation durchliest :-/.
C finde ich an dieser Stelle intuitiver als Pyhon. Wenn ich Remainder mit Rest übersetze, ist -7/2 = -3 Rest -1, da -7 = -3 * 2 + (-1) ist.
Auf das Ergebnis käme man auch mittels schriftlicher Division, die wir noch aus der Grundschule kennen.
Bei Python hingegen scheinen wir mit divmod wieder den richtigen Modulo zu haben, denn dort wird wieder der kleinste nichtnegative Repräsentant zurück gegeben.
Japp, intuitiver ist der Remainder allemal im neg. Bereich, ganz klar.
Man muß halt nur wissen, daß eben % der Remainderoperator in der einen Sprache und das 'echte' Modulo in der anderen ist. Wenn man aber mit mehr als nur einer Sprache hantiert ist die unterschiedliche Nutzung (Mod/Remainder bzw. Residue) eine echt miese Stolpferfalle.
https://en.wikipedia.org/wiki/Modulo_operation
Dort ist eien schöne Liste diverser Sprachen, anfangs war es in C noch implementierungsabhängig, das ist dann ganz lecker, wenn Du bedingte Compilierung in Abhängigkeit des verwendeten Compilers genutzt hast :-D.
1) Es gibt keine if-Schleife. Es handelt sich um eine Struktur für eine Verzweigung. Sie liefert also einen funktionalen Unterschied zur Schleife.
2) Nimm den Backslash hinter Error raus. Andernfalls maskierst du das Anführungszeichen danach und der String wird nicht beendet.
3) Wieso deklarierst du i global? Es reicht, die Variable in dem Kontext anzuführen, in dem sie gebraucht wird. In deinem Fall wäre dies der else-Körper. Auch n muss wohl nicht global sein.
4) Gib n einen expliziten Startwert, bevor du die Variable verwendest. Vergib nach Möglichkeit immer explizite Startwerte vor einer Nutzung einer Variablen. Das reduziert Fehlerquellen.
5) Deine Schleife läuft so lange, wie die Bedingung i <= k erfüllt wird. Die Variable i hat den Startwert 0, die Variable k den Wert -8. Die Bedingung kann also nicht erfüllt werden, -8 ist kleiner als 0. Die Schleife läuft nicht, der Wert von n bleibt 0.
Wenn du nur die ungeraden negativen Zahlen haben willst, dann starte bei -1 und zähle einfach in Zweier-Schritten runter:
int sumfoo(const int k) {
int result = 0;
for (int i = -1; i >= k; i -= 2) {
result += i;
}
return result;
}
Das erschlägt dir auch die Behandlung des Sonderfalls bei " >= 0", weil dann immer automatisch "0" zurück gegeben wird. Falls du allerdings wirklich eine Fehlermeldung ausgeben willst, weißt du ja schon, wie man das macht.
Außerdem solltest du die Variablen Funktionslokal deklarieren, und auf Globals verzichten. :)
PS: Habe gerade noch eine wesentlich bessere Lösung mithilfe einer Abwandlung der Gauß'schen Summenformel gebaut. Damit lässt sich dein Problem völlig ohne Schleifen mithilfe von ein paar Grundrechenoperationen durchführen. Aber egal, das war ja nicht die Aufgabenstellung ... :)
Bevor du mit einer langweiligen FOR Schleife auf das Problem losgehst, solltest du es erst mal vom mathematischen Standpunkt aus etwas genauer betrachten.
So wie das der 11jährige Carl Friedrich Gauß im Jahre 1786 bereits tat:
https://de.wikipedia.org/wiki/Gau%C3%9Fsche_Summenformel#Verwandte_Summen
Zwei Idioten, ein Gedanke. :)
Lies mal den Kommentar unter meiner Antwort! ;)
Vielleicht eher so:
int summe(int k){
if (k>=0) return 0; /* Fehlerhafte Eingabe */
int sum=0;
for (int i=k;i<0;++i) if (i%2!=0) sum+=i;
return sum;
}
Alternativ: Prüfe Anfangs ob k gerade ist, wenn nein, dann erhöhe um 1 und mache dann ein 2er Stepping in der Schleife.
PPS: Was soll eigentlich n = n + 1 bewirken?
Vorschlag: