P6033 [NOIP2004 提高組] 合併果子 加強版 題解
目錄
目錄1. question1
思路
由於是按補碼形式儲存,最高位為1
其他位全為0
,直接將1
左移31
位即可得到
程式碼
int tmin(void) {
return 1<<31;
}
測試截圖
./dlc -e bits.c
:
btest
:
2. question2
思路
Tmax
的補碼錶示為最高位為0
其他位全為1
即0x7fffffff
,可得Tmax+1=Tmin(0x80000000)
若 x= 0111 1111 1111 1111 1111 1111 1111 1111
x+1= 1000 0000 0000 0000 0000 0000 0000 0000
!(x^(x+1))=1
!(x+1)=0 !!(x+1)=1
所以當x
為0x7fffffff
時返回值為1,其餘返回值為0
程式碼
int isTmax(int x) {
return !((~(x+1)^x))&!!(x+1);
}
測試截圖
./dlc -e bits.c
:
btest
:
3. question3
思路
最重要的是構造一個32
位並且奇數位為1
的數,若有一個數為a
其奇數位全為1
如果存在x
使得x&a==a
那麼x
就滿足條件
先構造8
位奇數位為1
的數之後左移與原狀態取或運算即可得到滿足條件的16
位數,以此類推變可得到32
位奇數位為1
的數,之後用x&a
若返回結果為x
則說明x
滿足條件,隨後和自身異或得到0
取非得到返回值1
,執行成功。
程式碼
int allOddBits(int x) {
int a=0xAA;
int b=(a<<8)|a;
int c=(b<<16)|b;
return !((x&c)^(c));
}
測試截圖
./dlc -e bits.c
:
btest
:
4. question4
思路
函式理解為,當x!=0
時返回y
否則將返回z
x
的範圍限制住,可以採用!x
來判斷是否為零
當x
等於0
時,x1
最高位為1
,其餘位為0
即-0
,此時和y
與運算得0
按位取反之後最高位為0
其餘為為1
,和z
做與運算得到本來z
的值返回即可
當x
不等於0
時x1
全為1
,和y
與運算得到y
本身,按位取反之後為0
和z
相與之後為0
所以最後取和返回y
主要還是通過!x
來縮小x1
的範圍再進行判斷就方便很多
程式碼
int conditional(int x, int y, int z) {
int x1=!x+~0;
return (x1&y)+((~x1)&z);
}
測試截圖
./dlc -e bits.c
:
bteat
:
5. Nuaa_question5
思路
首先提取符號位sign
和階碼exp
,情況如下:
若為inf
或者Nan
即exp==0xff
直接返回自身
若為非規格化數,exp==0
時,直接將尾數左移一位,但是注意恢復原來的符號位
若為規格化數,exp>0&&exp<0xff
直接將階碼加一即可,階碼加一後如果為0xff
就代表浮點數乘二會溢位,返回inf
主以依然要保留原來的符號位,如果不溢位就講符號,階碼,尾數三部分按照格式組合起來即可。
程式碼
unsigned float_twice(unsigned uf) {
int exp = (uf>>23)&0xff;
int sign = uf&(1<<31);
if(exp==255) return uf;
if(exp==0) return sign|(uf<<1);
exp+=1;
if(exp==255) return sign|0x7f800000;
return(uf&0x807fffff)|(exp<<23) ;
}
測試截圖
./dlc -e bits.c
:
btest
:
6. Nuaa_question6
思路
首先和第五題類似通過移位和&
運算取得符號位sign
,階碼exp
和尾數frac
實際上的階碼等於exp-127
,關與於階碼:
exp<127
實際階碼小於零,浮點數的絕對值小於1,直接轉換為整數的零即可
exp>157
實際階碼大於30
,此時浮點數的絕對值最小為2^31
如果是正數就會發生溢位返回0x80000000u
,但是如果為負數,-2^31
轉為整數並不溢位,結果為0x80000000u
,其他負數全部溢位,所以綜上所述返回值全部為0x80000000u
exp>=127&&exp<=150
時實際階碼大於等於0
小於等於23
,單獨提取出來的尾數相當於階碼為23
,所以整數右移(127+23-exp)
位即可
exp>150&&exp<=157
時實際階碼大於等於23
小於等於30
相當於整體左移(exp-127-23)
即可
程式碼
int float_f2i(unsigned uf) {
int exp,sign,frac,ans;
exp=(uf>>23)&0xff;
sign=(uf>>31)&1;
frac=(uf&0x7fffff)|0x800000;
if(exp<127)
return 0;
if(exp>157)
return 0x80000000u;
if(exp<150)
ans=frac>>(150-exp);
else
ans=frac<<(exp-150);
if(!sign)
return ans;
else
return ((~ans)+1);
}
測試截圖
./dlc -e bits.c
:
btest
:
7. 最終結果
./driver.pl
截圖:
挑戰教授截圖(161920214)