HIT ICS ftoa函式的實現

2021-10-23 04:30:57 字數 3574 閱讀 2161

計算機系統基礎實驗要求實現乙個 ftoa 函式,將 float 型變數轉換為字串,轉換效果同 printf 函式

在這之前,寫了 itoa 的實現,int 到字串嘛,%%% 把數字取出來就好了嘛!

咋一看,ftoa 也簡單,float 嘛,只有七八位精度,**// 搞一搞應該沒啥問題。好做......

個屁float 用 ieee754編碼儲存的,每個規格化數/非規格化數都是準確對應了乙個十進位制小數的!所以不能搞近似!

特別是實驗了一下 printf ,居然也真的是全活不打折地輸出的!

比如編碼 0x7f7fffff 用 printf ,%f 輸出,整數部分39位是一點沒差;0x1 用 printf ,%f 輸出,最低位是小數點後149位;

我想了半天是怎麼實現的,最後猜測到:printf 裡面難道還內建了高精度計算?

後來查閱了一些資料,似乎真的是?是篇英文的,不想看,反正就是確認了得寫高精度!

但是不想寫,再後來問了老師,確實是要寫高精度!

那就寫高精度咯!

因為是純 c語言,沒有類,沒有成員函式這些概念,運算子過載沒試,不知道有沒有,估計是沒有。寫起來不習慣

先來 高精度加法、乘法

#include #include #include #include #define max_len 200

typedef struct bigint bigint;

int reg[max_len];

bigint plus(bigint x, bigint y)

k++; i--; j--;

}if(reg[k] == 1)len++;

for(i = 0, j = len-1; j >= 0; i++, j--)ans.val[i] = reg[j] + '0';

ans.val[len] = '\0';

return ans;

}bigint mul(bigint x, bigint y)

if(reg[len-1] == 0)len--;

for(i = 0, j = len-1; j >= 0; i++, j--)ans.val[i] = reg[j] + '0';

ans.val[len] = '\0';

return ans;

}

通過上面的實驗可以估計,位串長度不會超過200位,於是把乙個200位的字串宣告成了bigint的型別,來處理大整數計算

需要說明的是,這裡是用的乙個很樸素的方法來實現高精度計算的,只做實現,不談效率,大佬們盡可使用 fft 等等高階方法

加法、乘法都是右對齊計算的,字串天然下是左對齊的,所以需要進行一些處理

為了賦值的時候較為容易,還寫了乙個賦值函式,就是套了乙個strncpy;為了把 int值賦給bigint,又把 itoa 貼了進來

因為會用到 2的冪次和 5的冪次,有求冪運算,就又搞了乙個二分快速冪

void setval(bigint *x, char *ptr)

void cs_itoa(int num, char str)

char a[16];

int i,j,len,flag;

flag = (num < 0);

if(flag) num = -num;

for(i = 0; num ; i++)

if(flag)a[i++] = '-';

a[i] = '\0';

len = i;

for(i = len -1, j = 0; i >= 0 ; i--, j++)str[i] = a[j];

str[len] = '\0';

return;

}bigint montgemery(bigint a, int b)

return ans;

}

下面才開始正題,ftoa 函式,把float轉換為字串

void cs_ftoa(float num, char str, int digit )
先把符號碼,階碼,尾數碼取出來,完成這些需要位運算,我用到了乙個union

union int_float

;

union int_float m;

m.f = num;

int e,frac,s;

bigint a,b;

int pointsh = 0; //小數點需左移位數

char tmp[max_len]; //儲存純數字

s = (m.i & 0x80000000)>>31;

e = (m.i & 0x7f800000)>>23;

frac = (m.i & 0x7fffff);

然後,把特殊值先行處理掉,inf、-inf 以及 nan

if(e == 255)

先得出輸出的數字串,並且得到小數點需移動的位數

先看非規格化數

if(e == 0)

再看規格化數

else

else // e<0, (frac*5^(-e))/(10^(-e)) -e 就是 小數點移位位數

}

首先補充尾數碼的隱含位1,再把階碼 e -127 再 -23,這樣原數值絕對值部分就變成了 frac*(2^e) 的形式了,當 e >= 0 時,結果一定為整數。

接下來確定正負號

int pos = 0, i;

int len = strlen(tmp);

if(s)str[pos++] = '-';

然後來做移位和捨入工作

對於結果是整數的,這個工作很好做

if(pointsh == 0)

如果數串長度小於等於左移位數,這意味著需要補充前導零。在這之前,需要根據保留位數把捨入先做了來

if(len <= psh )

strncpy(str+pos,"0.", 2);

pos += 2;

if(psh - len > digit) // digit + 1 位為前導0,輸出全0

//去後導0

for(i = len-1;tmp[i] == '0';i--)

if(digit >= psh) //前補0,後補0

// 最麻煩的部分,定位,進製,去除後導0

int pt = digit + len - psh;

if(tmp[pt] < '5')//舍尾;

// 以下部分還沒整清楚

if(tmp[pt] >= '5' && ( (psh > pt) || (tmp[pt-1]) ) )

for(i = len-1;tmp[i] == '0';i--)tmp[i] = '\0';

for(i = psh - len; i > 0; i--)putchar('0');

printf("%s\n",tmp);

return;

}

好麻煩,不想寫了,睡覺!

函式實現 MySQL排名函式實現

現在有個需求對所有學生分數進行排名,並且列出名次。剛看到這個需求,我有點懵逼,完全沒有思路?為什麼難一點需求,我就不會做呢?去網上查詢資料,把所有實現都列出來,全部都要學會。建立乙個分數表s score create table s score id int not null auto increm...

memcpy函式的實現

前段時間去面試自己比較喜歡的乙個工作,面試的哥們讓我實現void memcpy void to,const void from,size t count 這個函式。沒做出來,掛了。感到非常不爽。回來研究了一下。找著了幾個不同版的實現,貼出來。首先對這個函式做一些說明。include void mem...

atoi函式的實現

atoi函式的實現 寫這個函式的實現的原因很簡單,而且也很容易,直接抄襲的庫中的原始碼。因為有朋友面試的時候遇到了,前幾天乙個哥們面intel的時候也被問到了,巧合的是今天看廣聯達的面試題再次遇到。一周之內看到三次,讓我不得不重視一下啊,畢竟自己也要開始面試題呀面試題了!其實這個函式比較容易實現,不...