日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

计算机中整数加法满足结合律吗

發布時間:2023/12/18 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 计算机中整数加法满足结合律吗 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
今天看《程序設計語言概念》(Concepts of Programming Language),第七章“結合性”一節中有這么一段: 某些計算機中的整數加法不具有結合性。例如,假設一個程序要計算“A + B + C + D”,其中A、C是很大的正數,B、D是絕對值很大的負數。在這種情況下,將B加到A并不會導致溢出,但將C加到A就會溢出。B和D與此類似。 這段話很好理解,因為只要是程序員,整數計算可能會溢出是基本的常識。但這段話只談到計算的中間結果發生溢出的情況。如果不考慮中間結果而將重點放在最終結果上,計算順序是否依然會對結果產生影響呢?也就是說,計算機中的加法滿足結合律嗎?即: (a + b) + c 是否一定等于 (a + c) + b 呢? 首先,如果每個中間結果以及最終結果都沒有溢出,可以肯定必然是滿足結合律的,否則就是計算機自身有錯誤。 如果中間結果發生了溢出會怎樣?我們不妨編寫一個簡單的程序驗證一下。這里我們選擇四個整數,a和c是兩個是很大的正數,b和d是兩個很小的負數(即絕對值很大的負數)。 int a = 2147483392; //0x7fffff00; int b = -2147479553; //0x80000fff; int c = 2146500592; //0x7ff0fff0; int d = -2147421968; //0x8000f0f0; int sum1 = ((a + b) + c) + d; int sum2 = (a + b) + (c + d); int sum3 = (a + c) + (b + d); System.out.println("((a + b) + c) + d=" + sum1); System.out.println("(a + b) + (c + d)=" + sum2); System.out.println("(a + c) + (b + d)=" + sum3);

?

sum1為從左到右依次計算a+b+c+d的和;sum2先計算a+b和c+d,然后再計算二者的和;sum3則先計算a+c和b+d,然后再求和。通過代碼可以看出,sum1和sum2的中間結果沒有發生溢出,但sum3在計算a+c和b+d時都發生了溢出。下面來看看實際運行結果: ((a + b) + c) + d=-917537 (a + b) + (c + d)=-917537 (a + c) + (b + d)=-917537

?

可以看到無論順序如何結果都是正確的。所以我們可以得出結論: 計算機中的整數加法運算滿足結合律 這里還有一個問題,在上面的例子中,雖然中間結果發生了溢出,但最終結果是沒溢出的。那如果最終結果也溢出了會怎么樣?答案是不同計算順序得到的結果仍然一樣,只不過結果都是錯的(都溢出了)。這是由計算機本身有限的精度導致的,和結合律無關,所以這種情況仍然認為是符合結合律的。你可以自己寫個程序來驗證這一點。 不過要注意,這個結論是有限定條件的,對現代大多數計算機系統來說該結論都成立,因為這些系統通常都采用“二進制補碼”的方式來存儲整數,而二進制補碼的加法運算是符合結合律的。不滿足結合律的例子也是有的,比如BCD碼的加法運算。 ------------------------------------------------------------------ 寫到這里,我想到了一個老題目:如何在不引入臨時變量的情況下交換2個整數的值?一般來說,有2種方法可以做到,一種是使用加法,另一種是使用異或: a = a + b; b = a - b; a = a - b;

?

a = a ^ b; b = a ^ b; a = a ^ b;

?

有人說第一種方法有問題,原因是將a和b相加時可能會溢出。如果你看了這篇文章,就會知道這種說法是錯誤的了——雖然a+b可能會溢出,但最后仍能得到正確的結果。要說缺點,只是它的效率比第二種要低一些。但話說回來,它的可讀性卻要優于第二種。 ------------------------------------------------------------------ 補碼簡介 下面簡單介紹一下補碼,如果對此不感興趣或已比較熟悉請略過。二進制補碼(Two's complement)采用“2^N的補”的方式存儲的整數編碼(其中N為整數的位長)。相比而言,另一種存儲方式“反碼”采用的是“1的補”,即逐位計算各個位的補(1的補為0,0的補為1,在二進制中這和取反是一樣的),因此反碼的英文名稱為“One's complement”。 補碼可以認為是對反碼的改進,這不但因為補碼中統一了“正零和負零”,還因為其計算也要比反碼容易。最主要的一點是補碼不用考慮進位(即溢出位),而反碼則必須考慮。補碼的另一個優點是其符號位同時也是計算位,因此計算時無需對正數和負數區別對待,這一點和反碼一樣。與補碼和反碼不同,原碼則必須同時考慮數的正負和進位,因此很少有系統采用原碼的方式來存儲整數。 下面分別用補碼和反碼的方式來計算“10 - 1”,以此加深理解。 由于大多數計算機只實現了加法而沒有減法,因此“10 - 1”實際上是轉換為“10 + (-1)”來計算的。為了簡單,這里假設整數只有8位。 補碼的計算過程如下(-1的補碼為“1111 1111”): 0000 1010 + 1111 1111 —————— 1?0000 1001 結果發生了溢出,產生了一個進位,對補碼來說簡單忽略即可,因此最后的結果為“9”。 注意這里的溢出屬于正常溢出。相比之下,如果正數+正數結果為負數,或負數+負數結果為正數時,則說明發生了不正常的溢出。正常的溢出結果仍然是正確的(這正是補碼的特性),而不正常的溢出得到的是錯誤的結果。 反碼的計算過程為(-1的反碼為“1111 1110”): 0000 1010 + 1111 1110 —————— ?1?0000 1000 同樣發生了溢出,但此時不能忽略進位,否則將得到錯誤結果“8”,因此還需要把進位加到結果上: 0000 1000 + ? ? ? ? ? ? ? ?1 —————— 0000 1001 得到最終結果“9”。 總結 最后再來簡單總結一下。在大多數計算機系統中,整數的加法運算滿足結合律。具體來說,如果最終結果沒有溢出,即使計算過程的中間結果出現了溢出也不會影響最終結果。而如果最終結果本身就是溢出的,改變計算順序仍然會得到一致的結果,這時候仍然認為是滿足結合律的。 雖然這篇文章對實際編程可能用處不大,因為我們通常只需注意最終結果不要溢出即可,對中間過程無需在意。但這篇文章為這個結論提供了一定的理論支持,以幫助我們加深對計算機整數加法運算的理解。
參考資料: 有符號數的表示:http://en.wikipedia.org/wiki/Signed_number_representations 反碼:http://en.wikipedia.org/wiki/Ones%27_complement 補碼:http://en.wikipedia.org/wiki/Two%27s_complement BCD碼:http://en.wikipedia.org/wiki/BCD_code

轉載于:https://www.cnblogs.com/antineutrino/p/4211284.html

總結

以上是生活随笔為你收集整理的计算机中整数加法满足结合律吗的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。