深入理解大數(shù)與高精度數(shù)的處理問題
更新時(shí)間:2013年05月24日 16:56:27 作者:
本篇文章是對(duì)大數(shù)與高精度數(shù)的處理進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
float和double型數(shù)據(jù)分別是單精度和雙精度型數(shù),他們的取值分別是3.4E+10的負(fù)38次方到3.4E+10的38次方,和1.7E+10的負(fù)308次方到1.7E+10的308次方。
那么對(duì)于float而言,只有6-7位的有效數(shù)字,怎么能裝下可達(dá)3.4*10^(-38)這么大的數(shù)呢?同理,15-16位的double型,也無法裝下1.7*10^(-308)這么大的數(shù)???
回答: float 6-7位指的是有效數(shù)字的位數(shù)(精度),而不是數(shù)值大小。例如,3.14159267有9位有效數(shù)字,數(shù)值卻在3~4之間,而350有3位數(shù)字,數(shù)值卻在300~400之間。所以說float數(shù)能達(dá)到3.4E+10,但是它的有效數(shù)字位數(shù)只能達(dá)到6-7位,如果3.14159267賦值給一個(gè)float變量,那么精度將會(huì)丟失。例如
float a=3234567.1;
float b=3234567;
if( a==b )
printf("YES");
else
printf("NO");
將輸出YES,因?yàn)閍末尾的11超出了float 只能達(dá)到6-7位的精度。(如果a=1234567.1;b=3234567)輸入結(jié)果將是NO,為什么呢?這就要我們分析:超出精度的部分怎么處理?不是四舍五入,而是二進(jìn)制位的丟失。所以說有時(shí)候能達(dá)到6位的精度,有時(shí)候能達(dá)到7位的精度,取決于該數(shù)的二進(jìn)制表示。
那么我們就想怎么表示超長位數(shù),超大精度的數(shù)字呢?
比如123456789123456789123456789(超長30位的大整數(shù));
比如3.14159012345678901234567890123(超高精度30位的小數(shù)),這么長的數(shù)字,long float都存不下來,這就要借助于“字符串”或者“字符數(shù)組”了。
unsigned __int64 n;
無符號(hào)__int64類型的變量n,最大值超過了1234567892345678912(20位),可達(dá)到約1.8E+19,平常來說應(yīng)該夠用了。
但是__int64類型的數(shù)據(jù)不能用C++里面的cout來輸出,應(yīng)該是cout沒有重載這個(gè)類型,如果用printf來輸出,顯然%d, %f, %l都無法滿足20位的精度,網(wǎng)上查到VC6下可以用printf("%I64d\n", n);但是支持的位數(shù)不超過20,經(jīng)我測(cè)試,大概超過9.23E+18 輸出的結(jié)果就會(huì)出錯(cuò)了。那么最好的辦法是將“長位數(shù)”轉(zhuǎn)換成字符串,如下:
char buffer[65];
printf("%s", _ui64toa(n, buffer,10) );
函數(shù)_ui64toa就是負(fù)責(zé)將n轉(zhuǎn)換成字符串的,存入字符數(shù)組buffer[65]中,10代表轉(zhuǎn)換成10進(jìn)制。
數(shù)字轉(zhuǎn)換為字符串,參考程序如下:
#include <stdlib.h>
#include <stdio.h>
int main( void )
{
char buffer[65];
int r;
for( r=10; r>=2; --r )
{
_itoa( -1, buffer, r );
printf( "base %d: %s (%d chars)\n", r, buffer, strlen(buffer) );
}
printf( "\n" );
for( r=10; r>=2; --r )
{
_i64toa( -1L, buffer, r );
printf( "base %d: %s (%d chars)\n", r, buffer, strlen(buffer) );
}
printf( "\n" );
for( r=10; r>=2; --r )
{
_ui64toa( 0xffffffffffffffffL, buffer, r );
printf( "base %d: %s (%d chars)\n", r, buffer, strlen(buffer) );
}
}
Output
base 10: -1 (2 chars)
base 9: 12068657453 (11 chars)
base 8: 37777777777 (11 chars)
base 7: 211301422353 (12 chars)
base 6: 1550104015503 (13 chars)
base 5: 32244002423140 (14 chars)
base 4: 3333333333333333 (16 chars)
base 3: 102002022201221111210 (21 chars)
base 2: 11111111111111111111111111111111 (32 chars)
base 10: -1 (2 chars)
base 9: 145808576354216723756 (21 chars)
base 8: 1777777777777777777777 (22 chars)
base 7: 45012021522523134134601 (23 chars)
base 6: 3520522010102100444244423 (25 chars)
base 5: 2214220303114400424121122430 (28 chars)
base 4: 33333333333333333333333333333333 (32 chars)
base 3: 11112220022122120101211020120210210211220 (41 chars)
base 2: 1111111111111111111111111111111111111111111111111111111111111111 (64 chars)
base 10: 18446744073709551615 (20 chars)
base 9: 145808576354216723756 (21 chars)
base 8: 1777777777777777777777 (22 chars)
base 7: 45012021522523134134601 (23 chars)
base 6: 3520522010102100444244423 (25 chars)
base 5: 2214220303114400424121122430 (28 chars)
base 4: 33333333333333333333333333333333 (32 chars)
base 3: 11112220022122120101211020120210210211220 (41 chars)
base 2: 1111111111111111111111111111111111111111111111111111111111111111 (64 chars)
PS:可以用這個(gè)函數(shù)來將10進(jìn)制整數(shù)轉(zhuǎn)換成二進(jìn)制字符串;
int main( void )
{
char buffer[65];
_itoa( 12, buffer, 2 );
printf( "base %d: %s (%d chars)\n", r, buffer, strlen(buffer) );
}
還有一種方法是自己定義字符數(shù)組存放超長位數(shù)的數(shù),小數(shù)點(diǎn)也是可以解決的,然后自己定義這些字符串形式的超長數(shù)之間的運(yùn)算法則并重載運(yùn)算符,據(jù)說這樣做運(yùn)算效率還是蠻高的。
那么對(duì)于float而言,只有6-7位的有效數(shù)字,怎么能裝下可達(dá)3.4*10^(-38)這么大的數(shù)呢?同理,15-16位的double型,也無法裝下1.7*10^(-308)這么大的數(shù)???
回答: float 6-7位指的是有效數(shù)字的位數(shù)(精度),而不是數(shù)值大小。例如,3.14159267有9位有效數(shù)字,數(shù)值卻在3~4之間,而350有3位數(shù)字,數(shù)值卻在300~400之間。所以說float數(shù)能達(dá)到3.4E+10,但是它的有效數(shù)字位數(shù)只能達(dá)到6-7位,如果3.14159267賦值給一個(gè)float變量,那么精度將會(huì)丟失。例如
復(fù)制代碼 代碼如下:
float a=3234567.1;
float b=3234567;
if( a==b )
printf("YES");
else
printf("NO");
將輸出YES,因?yàn)閍末尾的11超出了float 只能達(dá)到6-7位的精度。(如果a=1234567.1;b=3234567)輸入結(jié)果將是NO,為什么呢?這就要我們分析:超出精度的部分怎么處理?不是四舍五入,而是二進(jìn)制位的丟失。所以說有時(shí)候能達(dá)到6位的精度,有時(shí)候能達(dá)到7位的精度,取決于該數(shù)的二進(jìn)制表示。
那么我們就想怎么表示超長位數(shù),超大精度的數(shù)字呢?
比如123456789123456789123456789(超長30位的大整數(shù));
比如3.14159012345678901234567890123(超高精度30位的小數(shù)),這么長的數(shù)字,long float都存不下來,這就要借助于“字符串”或者“字符數(shù)組”了。
unsigned __int64 n;
無符號(hào)__int64類型的變量n,最大值超過了1234567892345678912(20位),可達(dá)到約1.8E+19,平常來說應(yīng)該夠用了。
但是__int64類型的數(shù)據(jù)不能用C++里面的cout來輸出,應(yīng)該是cout沒有重載這個(gè)類型,如果用printf來輸出,顯然%d, %f, %l都無法滿足20位的精度,網(wǎng)上查到VC6下可以用printf("%I64d\n", n);但是支持的位數(shù)不超過20,經(jīng)我測(cè)試,大概超過9.23E+18 輸出的結(jié)果就會(huì)出錯(cuò)了。那么最好的辦法是將“長位數(shù)”轉(zhuǎn)換成字符串,如下:
復(fù)制代碼 代碼如下:
char buffer[65];
printf("%s", _ui64toa(n, buffer,10) );
函數(shù)_ui64toa就是負(fù)責(zé)將n轉(zhuǎn)換成字符串的,存入字符數(shù)組buffer[65]中,10代表轉(zhuǎn)換成10進(jìn)制。
數(shù)字轉(zhuǎn)換為字符串,參考程序如下:
復(fù)制代碼 代碼如下:
#include <stdlib.h>
#include <stdio.h>
int main( void )
{
char buffer[65];
int r;
for( r=10; r>=2; --r )
{
_itoa( -1, buffer, r );
printf( "base %d: %s (%d chars)\n", r, buffer, strlen(buffer) );
}
printf( "\n" );
for( r=10; r>=2; --r )
{
_i64toa( -1L, buffer, r );
printf( "base %d: %s (%d chars)\n", r, buffer, strlen(buffer) );
}
printf( "\n" );
for( r=10; r>=2; --r )
{
_ui64toa( 0xffffffffffffffffL, buffer, r );
printf( "base %d: %s (%d chars)\n", r, buffer, strlen(buffer) );
}
}
復(fù)制代碼 代碼如下:
Output
base 10: -1 (2 chars)
base 9: 12068657453 (11 chars)
base 8: 37777777777 (11 chars)
base 7: 211301422353 (12 chars)
base 6: 1550104015503 (13 chars)
base 5: 32244002423140 (14 chars)
base 4: 3333333333333333 (16 chars)
base 3: 102002022201221111210 (21 chars)
base 2: 11111111111111111111111111111111 (32 chars)
base 10: -1 (2 chars)
base 9: 145808576354216723756 (21 chars)
base 8: 1777777777777777777777 (22 chars)
base 7: 45012021522523134134601 (23 chars)
base 6: 3520522010102100444244423 (25 chars)
base 5: 2214220303114400424121122430 (28 chars)
base 4: 33333333333333333333333333333333 (32 chars)
base 3: 11112220022122120101211020120210210211220 (41 chars)
base 2: 1111111111111111111111111111111111111111111111111111111111111111 (64 chars)
base 10: 18446744073709551615 (20 chars)
base 9: 145808576354216723756 (21 chars)
base 8: 1777777777777777777777 (22 chars)
base 7: 45012021522523134134601 (23 chars)
base 6: 3520522010102100444244423 (25 chars)
base 5: 2214220303114400424121122430 (28 chars)
base 4: 33333333333333333333333333333333 (32 chars)
base 3: 11112220022122120101211020120210210211220 (41 chars)
base 2: 1111111111111111111111111111111111111111111111111111111111111111 (64 chars)
PS:可以用這個(gè)函數(shù)來將10進(jìn)制整數(shù)轉(zhuǎn)換成二進(jìn)制字符串;
復(fù)制代碼 代碼如下:
int main( void )
{
char buffer[65];
_itoa( 12, buffer, 2 );
printf( "base %d: %s (%d chars)\n", r, buffer, strlen(buffer) );
}
還有一種方法是自己定義字符數(shù)組存放超長位數(shù)的數(shù),小數(shù)點(diǎn)也是可以解決的,然后自己定義這些字符串形式的超長數(shù)之間的運(yùn)算法則并重載運(yùn)算符,據(jù)說這樣做運(yùn)算效率還是蠻高的。
相關(guān)文章
使用c++實(shí)現(xiàn)OpenCV繪制旋轉(zhuǎn)矩形圖形
這篇文章主要給大家介紹了使用c++實(shí)現(xiàn)OpenCV繪制圖形旋轉(zhuǎn)矩形的方法案例,通過圖文及代碼形式進(jìn)行了詳細(xì)的描述,有需要的朋友可以參考下,希望可以有所幫助2021-08-08利用QDir實(shí)現(xiàn)刪除選定文件目錄下的空文件夾
這篇文章主要為大家詳細(xì)介紹了如何利用QDir實(shí)現(xiàn)刪除選定文件目錄下的空文件夾功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以動(dòng)手嘗試一下2022-08-08Visual Studio 2019安裝、測(cè)試創(chuàng)建c語言項(xiàng)目(圖文教程)
這篇文章主要介紹了Visual Studio 2019安裝、測(cè)試創(chuàng)建c語言項(xiàng)目,Visual Studio 2019是完全免費(fèi)的,而且安裝比較簡單,現(xiàn)在把安裝步驟分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2020-03-03