c語言整數溢出
㈠ 如何判斷整數數據的溢出
整數溢出,如何判斷整數溢出 收藏
c語言中存在兩類整數算術運算,有符號運算和無符號運算。在無符號運算里,沒有了符號位,所以是沒有溢出的概念的。
所有的無符號運算都是以2的n次方為模。如果算術運算符的一個操作數是有符號書,另一個是無符號數,那麼有符號數
會被轉換為無符號數(表示範圍小的總是被轉換為表示範圍大的),那麼溢出卜族也不會發生。但是,當兩個操作數都是有符號數
時,溢出就有可能山弊此發生。而且溢出的結果是未定義的。當一個運算的結果發生溢出時,任何假設都是不安全的。
例如,假定a和b是兩個非負的整型變數(有符號),我們需要檢查a+b是否溢出,一種想當然的方式是:
if (a + b < 0)
溢出;
實際上,在現實世界裡,逗迅這並不能正常運行。當a+b確實發生溢出時,所有關於結果如何的假設均不可靠。比如,在某些
機器的cpu,加法運算將設置一個內部寄存器為四種狀態:正,負,零和溢出。在這種機器上,c編譯器完全有理由實現以上
的例子,使得a+b返回的不是負,而是這個內存寄存器的溢出狀態。顯然,if的判斷會失敗。
一種正確的方式是將a和b都強制轉換為無符號整數:
if ( (unsigned)a + (unsigned)b > INT_MAX)
溢出;
這里的int_max值為有符號整型的最大值。在一般的編譯器里是一個預定義的常量。ANSI C在limits里定義了INT_MAX,值為
2的31次方-1.
不需要用到無符號算數運算的另一種可行方法是:
if (a > INT_MAX - b )
溢出;
PS : 有符號數的最高位(31位)為符號位,最高位為0的時候,表示正,為1的時候表示負。運算時,符號位不參加運算,但是如果兩個數相加,30位需要進1時,那麼即表示溢出。
㈡ 在c語言編程中,如何避免整數運算溢出問題
要麼用足夠大的數據類型,要麼使用數組自己實現大數的運算,亦可直接使用GMP庫實現任意精度數學運算
㈢ C語言編程問題,數據溢出。
你的演算法有問題:
你這個程序的演算法沒有你想的這么容易,因為實際上中間你是在做冪運算,而冪運算是非常容易溢出的;
但是考慮到實際上你只是需要輸出後面三位數字即可,那麼按照乘法(冪運算其實是乘法運算)的規則,我們知道其實影響最後三位的是兩個乘數的後三位,高於後三位的是不參與對乘積的後三位的影響的{(1000*x1+y1)*(1000*x1+y1),分析一下就知道了}。
所以,基於以上分析,我們只要將每一次乘積的後三位拿出來進行運算即可。
即你的進行冪運算的這段代碼要改(未調試):
while (i<=n)
{
j*=a;
j=%1000;
i++;
}
如果還怕出現溢出,先將a也取余數就可以了。
㈣ C語言中怎麼處理溢出
C
中調用積運算符之後做溢出檢測已經太晚,但調用和運算符之後做檢測則一點也不遲,
所以你可以通過對和運算結果的檢測實現能檢測溢出的積運算,因為
a
*
b
既是
a
個
b
的和:
-5000000
*
1374389539
等於
-(5000000
*
1374389539)。括弧里是
5000000
個
1374389539
的和。
我把能檢測溢出的和運算包在
add(
)
里,然後在
multiply(
)
里重復調用
add(
)。
add(
)
怎麼檢測溢出?
和運算的結果若溢出將導致數值的環繞。上溢導致往下環繞,下溢導致往上環繞。
邊界狀況:
(1)最輕微的上溢是
INT_MAX
+
1
:結果是
INT_MIN。
(2)最嚴重的上溢是
INT_MAX
+
INT_MAX
:結果是
-2。
(3)最輕微的下溢是
INT_MIN
-
1
:結果是
INT_MAX。
(4)最嚴重的下溢是
INT_MIN
-
INT_MIN
:結果是
0。
結論:
(1)所有上溢結果都小於任何一個操作數。
(2)所有下溢結果都大於任何一個操作數。
所以
add(
)
可以用結果和任意選定的一個參數判斷溢出,並以落選的參數判斷溢出的方向。
add(
)
無法以返回值舉報溢出,所以採用
strtol(
)
的舉報方法。
不同於
strtol(
)
的是,若沒有溢出,add(
)
會把
0
賦值給
errno。
multiply(
)
在這方面跟
add(
)
一樣。
#include<stdio.h>
#include<errno.h>
/*
errno,
ERANGE
*/
/*
*
Returns
the
sum
of
a
and
b,
with
overflow
and
underflow
check.
*
If
overflow
or
underflow
occurred,
sets
errno
to
ERANGE,
else
to
0.
*/
int
add(
int
a,
int
b
)
{
int
result
=
a
+
b;
if(
b
>
0
&&
result
>
a
||
b
<=
0
&&
result
<=
a
)
errno
=
0;
else
errno
=
ERANGE;
return
result;
}
/*
*
Returns
the
proct
of
a
and
b
obtained
through
repeated
call
of
add(
).
*
Affects
errno
exactly
as
add(
)
does.
*/
int
multiply(
int
a,
int
b
)
{
int
sign_of_a
=
1,
result
=
0,
i
=
0;
/*
Keep
the
sign
of
multiplier
off
the
loop
sentinel.
*/
if(
a
<
0
)
{
sign_of_a
=
-1;
a
*=
-1;
}
/*
Have
to
reset
errno
here
because
it
won't
be
updated
if
a
is
0.
*/
errno
=
0;
while(
i++
<
a
)
{
result
=
add(
result,
b
);
if(
errno
==
ERANGE
)
break;
}
return
result
*
sign_of_a;
}
int
main(
)
{
int
result;
/*
Operands
too
huge:
sure
overflow.
*/
result
=
multiply(
-5000000,
1374389539
);
if(
errno
==
ERANGE
)
perror(
"Uh
oh"
);
else
printf(
"%d\n",
result
);
/*
Small
operands:
safe.
*/
result
=
multiply(
49,
-972
);
if(
errno
==
ERANGE
)
perror(
"Uh
oh"
);
else
printf(
"%d\n",
result
);
}
當然,應付溢出的最佳方法還是防範:充分了解數據的范圍,選擇恰當的變數類型。
也許你正考慮改用不需要你擔心整數類型溢出的語言。考慮過
Python
嗎?
㈤ 如何判斷整數是否溢出
根據存儲的空間和有無符號位。
例如c或java當中的int型,使用32位,4個位元組存儲,有符號位。其能存儲2^32種不同數據。可存儲的數據在-2^31~2^31-1這個范圍內,超出則范圍則溢出。
若使用不帶符號位,則范圍為0~2^32-1。
用更加簡單的例子,如果使用4位來存儲,只能存儲2^4=16種不同數據。如果不帶符號位,則存儲范圍為0~15,超出則溢出。如果帶符號位,則范圍為-8~7,超出則溢出。
在實際編程中,某些編譯器會在特定情況下提示溢出問題,但更多情況需要自己處理溢出問題。
有什麼具體需求可以在追問中提出。