簡體   English   中英

正整數的總和返回負數 - C

[英]sum of positive integer returning negative number - C

C語言初學者。 我懷疑這可能是由於溢出,但無法解決這個簡單的練習:計算所有小於 10000 的自然數的平方和的程序

我最初嘗試:

#include <stdio.h>

int main() {
   
    int a = 10000;
    
    int square(int num) {
        return num * num;
    };
    
    int total = 0;
    while (a > 0) {
        a--;
        total += square(a);
        //printf("a is %d and square is %d and total %d \n", a, square(a), total );
    
    }; 
    
    printf("total is %d ", total );
    
    
    
    return total;
}

結果: total is -1724114088

奇怪的是:

...
a is 9936 and square is 98724096 and total 2063522144 
a is 9935 and square is 98704225 and total -2132740927 
...

所以我嘗試將 total 更改為long ,嘗試將聲明 square 函數更改為long square(int num ) ,但沒有任何改變。

你能解釋為什么總和變成負數嗎? 是因為溢出嗎? 但是為什么不重置為 0 或正數,而不是變為負數? 我怎么知道我不知道的計算機中有多少 int 位(例如雲?例如我在這里編碼:[https://www.programiz.com/c-programming/online-compiler/]

哪個是修復它的最佳實踐?

您需要將int所有用途更改為long

#include <stdio.h>

int main() {
   
    long a = 10000;
    
    long square(long num) {
        return num * num;
    };
    
    long total = 0;
    while (a > 0) {
        a--;
        total += square(a);
        //printf("a is %ld and square is %ld and total %ld \n", a, square(a), total );
    
    }; 
    
    printf("total is %ld ", total );
    
    return 0;
}

打印total is 333283335000

編輯

或者,您可以更改總計、 square的返回類型,並在計算平方值時執行適當的轉換:

#include <stdio.h>

int main() {
   
    int a = 10000;
    
    long square(int num) {
        return (long)num * (long)num;
    };
    
    long total = 0;

    while (a > 0) {
        a--;
        total += square(a);
        //printf("a is %ld and square is %ld and total %ld \n", a, square(a), total );
    
    }; 
    
    printf("total is %ld ", total );
    
    return 0;
}

產生與上述相同的結果。

在線gdb在這里

相反,您可以使用公式。

前 N 個自然數的平方和 = (N * (N + 1) * (2 * N + 1) / 6

現在,讓 N 為 10000。

忽略公式中的6,平方和有10^12那么大。 它不適合整數。 您應該使用可以容納更大值的數據類型,例如 long 或 long long int。

這是修改后的代碼。

#include <stdio.h>

int main() {
   
    int a = 10000;
    
    int square(int num) {
        return num * num;
    };
    
    // Change int to long long int
    long long int total = 0;
    while (a > 0) {
        a--;
        total += square(a);
        //printf("a is %d and square is %d and total %d \n", a, square(a), total );
    
    }; 
    
    
    // Change %d to %lld
    printf("total is %lld ", total );
    
    
    
    return total;
}

不要在函數中定義函數。

int main() {
   int square() { // NO!

函數屬於文件范圍

int square() { //OK
}
int main() { //OK
}

代碼編譯是因為編譯器對該語言進行了擴展 它不是 C 編程語言的一部分。

你能解釋為什么總和變成負數嗎?

見例。 為什么 sum 的值為負? 和其他問題。 總和在您的平台上“環繞”。

是因為溢出嗎?

是的。

但是為什么不重置為 0 或正數,而不是變為負數?

因為現在的系統是二進制補碼,所以先實現一條用於加數的硬件指令,然后再實現兩條具有特殊溢出語義的獨立指令,會更簡單。 無符號和有符號二進制補碼在對它們進行運算時的行為相同,因此在添加有符號數時,與其對溢出執行特殊語義,不如將它們添加為無符號數(僅添加位),然后結果為解釋為有符號數(在 C 程序中),因為最高有效位設置為負數。

無論如何,編譯器根本不在乎,因為有符號溢出是未定義的行為,編譯器不必在意。 編譯器只生成一個用於有符號加法的硬件指令,其行為如上所述。

我怎么知道我不知道的計算機中有多少 int 位

您可以查看編譯器文檔。

但通常它更簡單,只是編譯,你用一個簡單的C程序CHAR_BIT -位的字節數-和sizeof(int) -字節在數int -並檢查該程序的輸出。 例如,一個程序,例如:

#include <stdio.h>
#include <limits.h>
int main() {
    printf("There are %d bits in int\n", (int)sizeof(int) * CHAR_BIT);
}

請注意,類型中的位數不僅會隨平台和操作系統而變化,還會隨編譯器、編譯器版本和編譯選項而變化。

哪個是修復它的最佳實踐?

這取決於您想要什么樣的行為。

要計算更大的值使用更大的數據類型- longlong long 當語言功能不夠時,請移動您的程序使用一些大數字庫

如果您想在出現問題時終止程序 - 您可以檢查溢出並在發生時調用abort()或類似方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM