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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

java long double精度丢失_long long类型转double类型部分精度丢失问题

發布時間:2023/12/10 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java long double精度丢失_long long类型转double类型部分精度丢失问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

我最近做了一道題,一個64位(unsigned __int64)范圍內的數輸出其除以1000的值,并按四舍五入保留小數點后三位。

我剛開始直接寫WA,結果發現當數比較大的時候,結果后幾位精度總會丟失,只好手動模擬了一個,水過。。。。

后來我在網上找到了某位大牛的博客,這篇文章讓我對數據類型有了更好的認識。。

謝謝,轉載自http://blog.csdn.net/cai870808/article/details/24907853

看了一篇關于C/C++浮點數的博文,在Win32下,把int, 指針地址,long等4字節整數賦給一個double后,再用該double數賦給原始類型的數,得到的結果于最初的數值一致,即不存在任何精度丟失。例如下面的結果將總是true:

long a=123456; //assign any long number here

double db=a;long b=db;

printf("%s\n",a==b?"true":"false");

但是對于long long或win64下的指針地址等8字節整數將存在精度丟失,于是對這方面做了一個簡單的測試:

#include#include

void showEncodeOfDouble(unsigned char*db){const int ByteLength=8;for(int i=ByteLength-1;i>=0;i--)

printf("%.2x",db[i]);

printf("\n");

}intmain(){

unsignedlong long maxULL=0xffffffffffffffff; //2^64-1=18446744073709551615,//max unsigned long long

printf("%llu\n",maxULL);double d1=maxULL; //20bit Significant,Precision Loss

printf("%f\n",d1);

maxULL=d1;

printf("%llu\n",maxULL);

showEncodeOfDouble((unsignedchar*)&d1);

system("pause");return 0;

}

輸出的結果如下(visual studio,win32):

18446744073709551615

18446744073709552000.000000

9223372036854775808

43 f0 00 00 00 00 00 00

至此,有兩點疑問(暫時不理會代碼中showEncodeOfDouble的結果):

1)為什么丟失精度后得到的double數是18446744073709552000.000000?

2)為什么將double數重新轉化為unsigned long long后得到的數又和double不一致呢?對于這兩個問題,需要對C++浮點數的規格有一定的了解。

1??IEEE浮點標準

C/C++采用的是IEEE浮點標準,它以“二進制的科學表示法”表示一個小數:

其中M是一個整數部分僅有一位的二進制小數,例如1.011,表示十進制下的1.375。E表示該小數以2為底時的階數。基于以上的表示方式,小數需要對三部分進行編碼:表示符號的s,及階碼E、尾數碼M。C++中的double類型三種編碼所占的位數如圖所示。

53位尾數碼所能達到的精度為53二進制位,約為16 個十進制位( 53 log10(2) ≈ 15.955)[1],尾數碼的編碼中還有一個隱含的開頭整數位1(或0,當11位階碼全0時)因此實際中可得15-17位十進制的精度。當有效位數最多15位的十進制數轉換成double然后重新轉換為原來的十進制類型時,數值保持一致;另一方面,將一個double數轉化為可以容納17位以上有效數字的十進制數再重新轉化為double,結果數值也保持一致。

這就解釋了為什么4字節的整數轉化為double重新轉化能保持一致(2^32=4294967296僅10個有效位),而8字節的整數卻可能丟失精度(2^64-1=18446744073709551615共20個有效位)。但第一個問題中整數丟失精度后轉化成的double數值是怎么來的呢,這需要了解C++階碼和尾數對于double數值的意義。

2 階碼編碼和尾數編碼

在階碼編碼中,有一個常數偏置量Bias=1023,假設11位階碼所代表的無符號整數值為e,

1)若e不為0(11位全為1時用于表示特殊數字,此處不討論),則double數值為

2)若e=0,則小數值為

那么,可以看函數showEncodeOfDouble了,它的作用是將一個double數的編碼按字節打印出來(左邊是高字節),按其打印結果按照上面計算,可知double編碼值表示的數值是2^64,這是合理的,當把精度較高的整數轉化為double時,C++采用向偶數舍入的方式得到最接近的值[2]。至于打印出的結果,屬于C++浮點數打印中的細節問題。

3 C++浮點數打印

許多C/C++的庫中在輸出double時,通常有意使得輸出結果簡短些(即使設置了足夠多的可見位數),以避免較大位數的輸出。直接使用C中的printf或cout打印double數時,打印顯示的結果也有可能是帶有精度丟失的結果,可使用16進制的方式打印出更精確的double:

printf("%a\n",d1);

得到的輸出結果為:

0x1.000000p+64

至此問題1實際上只是C++中,將高精度整數轉double時的偶數舍入問題。

對于問題2,從float或double轉換成int,值將會被向零舍入.例如1.999將被轉換成1而-1.999將會被轉換成-1。進一步來說,值有可能會溢出。C語言標準沒有對這種情況指出固定的結果,這種轉換行為是無定義的。

[2]深入理解計算機系統,Randal E. Bryant, 機械工業出版社

總結

以上是生活随笔為你收集整理的java long double精度丢失_long long类型转double类型部分精度丢失问题的全部內容,希望文章能夠幫你解決所遇到的問題。

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