計算機系統基礎實驗要求實現乙個 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的時候也被問到了,巧合的是今天看廣聯達的面試題再次遇到。一周之內看到三次,讓我不得不重視一下啊,畢竟自己也要開始面試題呀面試題了!其實這個函式比較容易實現,不...