#include?stdio.h
專注于為中小企業(yè)提供成都網(wǎng)站建設(shè)、網(wǎng)站制作服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)云霄免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上1000+企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
#include?stdlib.h
struct?fraction
{
int?numerator;?//?分子
int?denominator;?//?分母
int?symbol;?//?符號(hào),分子為負(fù)時(shí)取值為-1,為正時(shí)取值為1,其它取值無(wú)意義
};
int?scan_frac(struct?fraction?*f,?struct?fraction?*g);//?按題目格式輸入兩個(gè)分?jǐn)?shù),存入f和g所指的內(nèi)存中。
struct?fraction?multiply_frac(struct?fraction?f,?struct?fraction?g);?//返回分?jǐn)?shù)f和g的乘積。
int?main()
{
struct?fraction?f1,?f2,?product;
while(scan_frac(f1,?f2)?!=?EOF)
{
product?=?multiply_frac(f1,?f2);
if(product.numerator?==?0)
{
printf("0\n");
continue;
}
if(product.symbol?==?-1)
printf("-");
printf("%d/%d\n",?product.numerator,?product.denominator);
}
return?0;
}
//讀取
int?scan_frac(struct?fraction?*f,?struct?fraction?*g)
{
char?c=0;
int?*tmpnum=f-numerator;
*tmpnum=0;
f-symbol=1;
while((c=getchar())!='\n')
{
???
if(c='9'c='0')
?*tmpnum=*tmpnum*10+c-'0';
else?if(c=='/')
{
tmpnum=f-denominator;
*tmpnum=0;
}
else?if(c=='-')
f-symbol=-1;
}
tmpnum=g-numerator;
*tmpnum=0;
g-symbol=1;
while((c=getchar())!='\n')
{
???
if(c='9'c='0')
?*tmpnum=*tmpnum*10+c-'0';
else?if(c=='/')
{
tmpnum=g-denominator;
??? *tmpnum=0;
}
else?if(c=='-')
g-symbol=-1;
}
fflush(stdin);
return?c;
}
//乘積
struct?fraction?multiply_frac(struct?fraction?f,?struct?fraction?g)
{
int?i=0;
int?tmp1,tmp2;
struct?fraction?*result=(struct?fraction?*)malloc(sizeof(?struct?fraction));
??//約分
tmp1=f.denominator*g.denominator;
??tmp2=f.numerator*g.numerator;
i=tmp1tmp2?tmp2:tmp1;
while(i=2)
{
??
if(tmp1%i==0
tmp2%i==0)
{
??tmp1/=i;
??tmp2/=i;
}
???i--;
}
?result-denominator=tmp1;
?result-numerator=tmp2;
result-symbol=f.numerator*g.numerator;
return?*result;
}
#include stdio.h typedef struct node{ long numerator,denominator; void frac_add(struct node,struct node); }fraction; void fraction::frac_add(fraction f1,fraction f2){ long i=2; this-denominator=f1.denominator*f2.denominator; this-numerator=f1.denominator*f2.numerator+f1.numerator*f2.denominator; while(i=this-denominatori=this-numerator){ while(!(this-denominator%i||this-numerator%i)){ this-denominator/=i; this-numerator/=i; } i++; } } void main(){ fraction f1,f2,f3; f1.numerator=3; f1.denominator=5; f2.numerator=4; f2.denominator=35; f3.frac_add(f1,f2); printf("%ld/%ld+%ld/%ld=%ld",f1.numerator,f1.denominator,f2.numerator,f2.denominator,f3.numerator); if(f3.numerator!=1){ printf("/%ld",f3.denominator); }putchar('\n'); }
IEEE浮點(diǎn)表示
IEEE浮點(diǎn)標(biāo)準(zhǔn)用
df5100123a813f9090d121b75ced0031.png
的形式近似表示一個(gè)數(shù)。并且將浮點(diǎn)數(shù)的位表示劃分為三個(gè)字段:
符號(hào)(sign)s決定這個(gè)數(shù)是負(fù)數(shù)(s=1)還是正數(shù)(s=0)。可以用一個(gè)單獨(dú)的符號(hào)s直接編碼符號(hào)s。
尾數(shù)(signficand)M是一個(gè)二進(jìn)制小數(shù),它的范圍是1~2-ξ或者是0~1-ξ。
n位小數(shù)字段87a21568c1ae9de8730727ed0bd6b560.png編碼尾數(shù)M。
階碼(exponent)E的作用是對(duì)浮點(diǎn)數(shù)加權(quán),這個(gè)權(quán)重是2的E次冪(可能是負(fù)數(shù))。k位的階碼字段 721b2fea992881e3b5d58079b970ae49.png編碼階碼E。
在單精度浮點(diǎn)格式(c語(yǔ)言的float)中,s,exp和frac字段分別為1位,8位和23位,而雙精度浮點(diǎn)格式(c語(yǔ)言中的double)中,s,exp和frac字段分別為1位,11位和52位。
一個(gè)浮點(diǎn)數(shù)的常見(jiàn)比特位表示如下:
單精度
雙精度
而根據(jù)exp的值,被編碼的值可以分為三大類不同的情況。下面進(jìn)行一一解釋。
情況1:規(guī)格化的值
即最普遍的情況,當(dāng)exp,即階碼域既不為全0,也不為全1的情況。在這種情況下,階碼字段解釋為以偏置(biased)形式表示有符號(hào)整數(shù),即E=exp-Bias,exp是無(wú)符號(hào)數(shù)(1~254)。Bias是一個(gè)等于534c19b7245290e31ebf91380d5f76cc.png的偏置值,對(duì)于單精度來(lái)說(shuō),k=23,Bias=127,因此E的范圍是-126~+127。
frac被描述為小數(shù)值,且0≤frac1,其二進(jìn)制表示為0.frac。尾數(shù)定義為 M=1+frac ,則M=1.frac。那么就有1≤M2,由于總是能夠調(diào)整階碼E,使得M在范圍1≤M2,所以不需要顯示的表示它,這樣還能獲得一個(gè)額外的精度位。也就是說(shuō),在計(jì)算機(jī)內(nèi)部保存M時(shí),默認(rèn)這個(gè)數(shù)的第一位總是1,因此可以被舍去,只保存后面的frac部分,等到讀取的時(shí)候,再把第一位的1加上去。
情況2:非規(guī)格化的值
當(dāng)exp,即階碼域?yàn)槿?時(shí),所表示的數(shù)便為非規(guī)格化的值,該情況下的階碼值E=1-Bias(注:為從非格式化值轉(zhuǎn)換到格式化值提供了一種方法)。尾數(shù)M=frac
非規(guī)格化的數(shù)有兩個(gè)作用。
表示數(shù)值0。格式化數(shù)中,我們總使得M≥1,因此就無(wú)法表示0。而階碼全0時(shí),且尾數(shù)也全0時(shí),就可以表示0了。
表示接近0.0的數(shù)。它所表示的值分布地接近于0.0,該屬性成為逐漸溢出。
情況3:特殊值
有兩種
階碼全為1,小數(shù)域全為0。它得到值為 +∞(s=0)或-∞(s=1),它在計(jì)算機(jī)中可以表示溢出的結(jié)果,例如兩個(gè)非常大的數(shù)相乘。
階碼全為1,小數(shù)域不全為0。它得到值為NaN(Note a Number)。它在計(jì)算機(jī)中可以表示非法的數(shù),例如計(jì)算根號(hào)-1時(shí)的值。
有了前面了基礎(chǔ),我們就可以來(lái)計(jì)算浮點(diǎn)數(shù)的數(shù)值范圍了。以單精度(float)為例,我們知道它的指數(shù)范圍(即E)為-126~+127,而M的范圍為1≤M2,實(shí)際上,對(duì)于單精度,1≤M≤2-2^(-23)(注:23為frac字段所占的比特位)。那么我們就可以得到單精度的最大值為:
e20b1b498c9971264f71d21d95b4fd55.png
同理,我們可以得到單精度的最小值為:
473794d6f5217c3819363802d1afd92c.png
我們僅僅以單精度為例,用同樣的方法可以計(jì)算其他精度的浮點(diǎn)數(shù)數(shù)值范圍,在此不再贅述。
浮點(diǎn)數(shù)的有效位
有效位也可以理解為我們常說(shuō)的精度。浮點(diǎn)數(shù)的精度是由尾數(shù)的位數(shù)來(lái)決定的。
對(duì)于單精度(float),它的尾數(shù)為23位,而2^23=8388608,共7位,也就是說(shuō)最多能有7位有效數(shù)字,但至少能保證6位,因此其有效位為6~7位。當(dāng)然我們可以通過(guò)下面的內(nèi)容進(jìn)一步理解。以下計(jì)算結(jié)果保留10位小數(shù)。
2946a6b34bb505a6dbcb919b2135f385.png5b3381a272e552309bd42b8f41d28d21.pnge10632444e7356476404af36db2c1bff.png
觀察a和b的結(jié)果可以發(fā)現(xiàn),0.0000001和0.0000002之間的其他數(shù)是沒(méi)有辦法通過(guò)單精度浮點(diǎn)數(shù)來(lái)精確表示的,也就是說(shuō),只有到小數(shù)點(diǎn)后面7位的值才是精確的,同理,觀察b和c的結(jié)果,0.0000002到0.0000004之間的其他數(shù)也是不能通過(guò)單精度浮點(diǎn)數(shù)精確表示的,更不幸地是,這之間的數(shù),甚至只能精確到第6位。
這也就有了單精度浮點(diǎn)數(shù)的有效位為6~7位的結(jié)論。根據(jù)相似的方法,我們同樣可以得到雙精度浮點(diǎn)數(shù)的有效位為15~16位的結(jié)論,這里不再贅述。
浮點(diǎn)數(shù)在內(nèi)存中的存儲(chǔ)
了解了這么多,我們來(lái)看一下一個(gè)小數(shù)究竟是如何在內(nèi)存中存儲(chǔ)的。以float f = 8.5f為例。其二進(jìn)制表示為94e38714fa97873bae95878e37c505e7.png,可見(jiàn)指數(shù)實(shí)際值為3,則根據(jù)E=exp-Bias,可知exp=E+Bias=3+127=130,根據(jù)M=1+frac,可知,frac=M-1=0.0001(二進(jìn)制)而45db4687f18f997dac6756f04478fe85.png