大家好好我是沐曦希??
??float 變量
??浮點數(shù)在內(nèi)存中的存儲原理
根據(jù)國際標(biāo)準(zhǔn)IEEE(電氣和電子工程協(xié)會) 754,任意一個二進(jìn)制浮點數(shù)V可以表示成下面的形式:
(-1)^S * M * 2^E
(-1)^S表示符號位,當(dāng)S=0,V為正數(shù);當(dāng)S=1,V為負(fù)數(shù)。
M表示有效數(shù)字,大于等于1,小于2。
2^E表示指數(shù)位。
例如:
十進(jìn)制中的5.0轉(zhuǎn)換成二進(jìn)制是101.0,相當(dāng)于1.01*2^2
(二進(jìn)制中0.1表示1*2^(-1); 0.11表示1*2^(-1)+1*2^(-2))
那么,按照上面V的格式,可以得出S=0,M=1.01,E=2。
十進(jìn)制的-5.0,寫成二進(jìn)制是 -101.0 ,相當(dāng)于 -1.01×2^2 。那么,S=1,M=1.01,E=2。
V=9.5f=1001.1=(-1)^0*1.0011*2^3
相當(dāng)于S=0;M=1.0011;E=3。
??IEEE 754規(guī)定
對于32位的浮點數(shù),最高的1位是符號位s,接著的8位是指數(shù)E,剩下的23位為有效數(shù)字M。
單精度浮點數(shù)存儲模型:
對于64位的浮點數(shù),最高的1位是符號位S,接著的11位是指數(shù)E,剩下的52位為有效數(shù)字M。
雙精度浮點數(shù)存儲模型:
IEEE 754對有效數(shù)字M和指數(shù)E,還有一些特別規(guī)定。
??有效數(shù)字M的規(guī)定
前面說過, 1≤M<2 ,即M可以寫成 1.xxxxxx 的形式,其中xxxxxx表示小數(shù)部分。
IEEE 754規(guī)定,在計算機內(nèi)部保存M時,默認(rèn)這個數(shù)的第一位總是1,因此可以被舍去,只保存后面的xxxxxx部分。比如保存1.01的時候,只保存01,等到讀取的時候,再把第一位的1加上去。這樣做的目的,是節(jié)省1位有效數(shù)字。以32位浮點數(shù)為例,留給M只有23位,將第一位的1舍去以后,等于可以保存24位有效數(shù)字。
??指數(shù)E的規(guī)定
??指數(shù)E為一個無符號整數(shù)
這意味著,如果E為8位,它的取值范圍為0~255;如果E為11位,它的取值范圍為0~2047。存入內(nèi)存時E的真實值必須再加上一個中間數(shù),對于8位的E,這個中間數(shù)是127;對于11位的E,這個中間數(shù)是1023。
例如: V=0.5f;
(-1)^0*1.0*2^(-1) 保存成32位浮點數(shù)時,必須保存成E+127–>126
保存成64位浮點數(shù)時,必須保存成E+1023–>1022 即float–>E(真實值)+127(中間值)–>存儲值
即double–>E(真實值)+1023(中間值)–>存儲值
然后,指數(shù)E從內(nèi)存中取出還可以再分成三種情況:
??E不全為0或不全為1
浮點數(shù)就采用下面的規(guī)則表示,即指數(shù)E的計算值減去127(或1023),得到真實值,再將有效數(shù)字M前加上第一位的1。
??E全為0
當(dāng)浮點數(shù)的指數(shù)E等于1-127(或者1-1023)即為真實值,
有效數(shù)字M不再加上第一位的1,而是還原為0.xxxxxx的小數(shù)。這樣做是為了表示±0,以及接近于0的很小的數(shù)字。
??E全為1
當(dāng)有效數(shù)字M全為0,表示±無窮大(正負(fù)取決于符號位s);
??float 變量與"零值"進(jìn)行比較
浮點數(shù)在內(nèi)存中存儲,并不想我們想的,是完整存儲的,在十進(jìn)制轉(zhuǎn)化成為二進(jìn)制,是有可能有精度損失的。
注意這里的損失,不是一味的減少了,還有可能增多。浮點數(shù)本身存儲的時候,在計算不盡的時候,會“四舍五入”或者其他策略
//code1
#include <stdio.h>
int main()
{
double x = 3.6;
printf("%.50f\n", x);
return 0;
}
//code2
#include <stdio.h>
int main()
{
double x = 1.0;
double y = 0.1;
printf("%.50f\n", x - 0.9);
printf("%.50f\n", y);
if ((x - 0.9) == y)
{
printf("you can see me!\n");
}
else
{
printf("oops\n");
}
return 0;
}
結(jié)論:因為精度損失問題,兩個浮點數(shù),絕對不能使用==進(jìn)行相等比較.
浮點數(shù)本身有精度損失,進(jìn)而導(dǎo)致各種結(jié)果可能有細(xì)微差別。
浮點數(shù)比較應(yīng)該進(jìn)行范圍精度比較
偽代碼一:
if((x-y) > -精度 && (x-y) < 精度){
//TODO
}
偽代碼-簡潔版
if(fabs(x-y) < 精度){ //fabs是浮點數(shù)求絕對值
//TODO
}
精度可以直接定義一個(宏定義)或者使用系統(tǒng)精度。
??宏定義精度
#define EPS 0.0000000000000001
#include<stdio.h>
#include<math.h>
int main()
{
double x = 1.0;
double y = 0.1;
if (fabs((x - 0.9) - y) < EPS)
{
printf("x==y");
}
else
{
printf("x!=y");
}
return 0;
}
輸出結(jié)果:
??系統(tǒng)精度
#include<float.h> //使用下面兩個精度,需要包含該頭文件
DBL_EPSILON //double 最小精度
FLT_EPSILON //float 最小精度
#include <stdio.h>
#include <math.h> //必須包含math.h,要不然無法使用fabs
#include <float.h> //必須包含,要不然無法使用系統(tǒng)精度
int main()
{
double x = 1.0;
double y = 0.1;
printf("%.50f\n", x - 0.9);
printf("%.50f\n", y);
if (fabs((x - 0.9) - y) < DBL_EPSILON)
{ //原始數(shù)據(jù)是浮點數(shù),我們就用DBL_EPSILON
printf("x==y\n");
}
else
{
printf("x!=y\n");
}
return 0;
}
兩個精度定義
#define DBL_EPSILON 2.2204460492503131e-016 /* smallest such that 1.0+DBL_EPSILON !=1.0 */
#define FLT_EPSILON 1.192092896e-07F /* smallest such that 1.0+FLT_EPSILON !=1.0 */
XXX_EPSILON是最小誤差,是:XXX_EPSILON+n不等于n的最小的正數(shù)。
EPSILON這個單詞翻譯過來是’ε’的意思,數(shù)學(xué)上,就是極小的正數(shù)。
??x與"零值"比較
#include <stdio.h>
#include <math.h>
#include <float.h>
int main()
{
double x = 0.00000000000000000000001;
//if (fabs(x-0.0) < DBL_EPSILON){ //寫法1
//if (fabs(x) < DBL_EPSILON){ //寫法2
if (x > -DBL_EPSILON && x < DBL_EPSILON)
{
printf("x==y\n");
}
else
{
printf("x!=y\n");
}
return 0;
}
x > -DBL_EPSILON && x < DBL_EPSILON: 為何不是>= && <= 呢?
XXX_EPSILON是最小誤差,是:
XXX_EPSILON+n不等于n的最小的正數(shù)。
XXX_EPSILON+n不等于n的最小的正數(shù): 有很多數(shù)字+n都可以不等于n,但是XXX_EPSILON是最小的,但是XXX_EPSILON依舊是引起不等的一員。
換句話說:fabs(x) <= DBL_EPSILON(確認(rèn)x是否是0的邏輯),如果=,就說明x本身,已經(jīng)能夠引起其他和他±的數(shù)據(jù)本身的變化了,這個不符合0的概念。
??fabs庫函數(shù)
fabs是用來計算浮點參數(shù)的絕對值的庫函數(shù),頭文件是math.h。
Example
/* ABS.C: This program computes and displays
* the absolute values of several numbers.
*/
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
void main( void )
{
int ix = -4, iy;
long lx = -41567L, ly;
double dx = -3.141593, dy;
iy = abs( ix );
printf( "The absolute value of %d is %d\n", ix, iy);
ly = labs( lx );
printf( "The absolute value of %ld is %ld\n", lx, ly);
dy = fabs( dx );
printf( "The absolute value of %f is %f\n", dx, dy );
}
Output
The absolute value of -4 is 4
The absolute value of -41567 is 41567
The absolute value of -3.141593 is 3.141593
??指針變量與“零值”進(jìn)行比較
#include<stdio.h>
int main()
{
printf("%d\n", 0);//0
printf("%d\n", '0');//字符0,ASCII碼值48
printf("%d\n", '\0');//字符串結(jié)束標(biāo)'\0',ASCII碼值0
printf("%d\n", NULL);//0
//#define NULL ((void *)0)
return 0;
}
真實轉(zhuǎn)化:
字符串A為“123456”轉(zhuǎn)換成int類型,此時字符串A的字節(jié)數(shù)為7,而int類型為4個字節(jié),要進(jìn)行真實轉(zhuǎn)化,需要我們編寫算法,使用相關(guān)庫函數(shù)來進(jìn)行轉(zhuǎn)化。
強制類型轉(zhuǎn)化:
不改變內(nèi)存中的數(shù)據(jù),只改變對應(yīng)的類型。
例如:
float a = 3.14;//3.14類型為double,存儲在float類型中需要經(jīng)過強制類型轉(zhuǎn)化
//float a =(float)3.14;
int* p = NULL;//定義指針一定要同時初始化,否則為野指針
//if(p==0); if(p!=0);//不推薦
//if(p); if(!p);//不推薦
if(NULL==p); if(NULL!=p);//推薦
??else 到底與哪個if配對呢?
//code1
#include<stdio.h>
int main()
{
int x = 0;
int y = 1;
if (10 == x)
if (11 == y)
printf("hello\n");
else
printf("world!\n");
return 0;
}
無打印結(jié)果。
//code2
#include<stdio.h>
int main()
{
int x = 0;
int y = 1;
if (10 == x)
{
if (11 == y)
{
printf("hello\n");
}
}
else
{
printf("world!\n");
}
return 0;
}
打印結(jié)果:world!
結(jié)論:else 匹配if采取就近原則
??寫在最后
友友們覺得不錯的可以給個關(guān)注,點贊或者收藏哦!??感謝各位友友們的支持。文章來源:http://www.zghlxwxcb.cn/news/detail-620961.html
你的??點贊是我創(chuàng)作的動力的源泉
你的?收藏是我奮斗的方向
你的??關(guān)注是對我最大的支持
你的??評論是我前進(jìn)的明燈
創(chuàng)作不易,希望大佬你支持一下小沐吧??文章來源地址http://www.zghlxwxcb.cn/news/detail-620961.html
到了這里,關(guān)于【C語言深度解剖】float變量在內(nèi)存中存儲原理&&指針變量與“零值”比較的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!