求浮點的小數部分函式

2021-08-10 00:20:15 字數 3704 閱讀 2021

突然想起浮點的一些東西,無聊寫個求浮點的小數部分函式

說到浮點又想到前陣一件鬱悶的事

前陣專案中用到分解浮點的小數和整數部分用於顯示

不知道為什麼ads中編譯的**在顯示 "."的時候居然是亂碼

很是鬱悶沒辦法使用庫函式只能自己寫

當時也沒當回事,覺得很簡單 

簡單的分析了一下流程也很簡單

1.判斷是否為負數,是則儲存標誌

2.化成正小數依次求整數部分和小數部分

3.將整數部分按1步驟中的正負轉成相應的正負數返回

於是粗粗的將函式設計成

void f(int* fi, int* ff);  將整數和小數部分分別返回

用了很長一段時間才發現這個函式居然有問題 

我當時匆忙沒有-0.***的格式是沒有辦法通過返回整數和小數用於顯示

如果返回變成0, -***顯示時就不對了,最後沒有辦法修改介面將符號也返回

**通通改變,設計的時候功能分解的不徹底,就導致這種問題.如果徹底返回顯示的字串

或者是符號 整數 小數三部分都沒有問題,就是想偷懶做半吊子事搞的自己鬱悶.

廢話說多了談談浮點

浮點根據ieee浮點格式標準

符號1位 指數8位 位數23位  ----單精度格式

符號 sign: 表示正負.負數為1正書為0

指數 exponent: 表示資料以二為底的冪,單精度的指數偏移基數為127.

有效數字 significand:表示資料的有效數字.

基本上可以使用當前這個公式來求解浮點資料的值:

(-1)^s ×(1+x) ×2^(e-127)

s是符號位 x有效數字 e指數

再看下實數轉化為浮點的過程這個有助我們推導獲得小數的過程

隨便抄了例子

比如100.75 = 0110 0100.11b = 1.10010011×2^6

保留1指數是按照小數點的當前位置左移到第乙個1後的位置偏移

符號為0

指數部分  6 = e-127 - > e=133=10000101b

有效數字 10010011 00000000 0000000 

所以組成值為  0 10000101 10010011 0000 0000 0000 000

這樣我們需要的小數0.75的計算過程需要 0.11->1*2^(-1)+1*2^(-2) = 0.5+0.25

這也是精度問題的原因浮點是計算出來的所以位數超過儲存位後就會產生誤差

求解小數部分我們從浮點結構入手就是要獲得到小數的二進位制表示式才能用於計算

1.獲得指數e

2.獲得有效數字

3.有效數字左移掉e-127得到小數字數

4.是計算的最重要部分

此刻得到的是分布在整型中的和小數部分位分布相同的值

我們觀察小數中計算從最高位開始以1/2為底的冪進行計算累加

而整型中計算是以最低位開始以2為底的冪進行累加

此刻只要對整型中的資料*10 ^ 需要小數字數 除以2^小數的總位數就得到了小數值

理論上分析是這樣的實際求解時抒寫函式驗證可以獲得

#define f_signed_num 1 //符號位

#define f_exponet_num 8 //指數字

#define f_significand_num 23 //有效數字位

#define f_e_size 127 //指數基數大小

unsigned int getff( float in_f, int n)

這樣演算法只是理論上驗證獲得小數部分

對於位數獲取很大的情況下導致fs*10 ^指數 造成溢位未做處理

以後我想找出一種更加簡單安全的轉化方法.不過此種方法實用64位的整型可以獲得相當的精度

在實際使用中不要求非常多的小數字的話夠用了.

可以考慮使用大陣列存放進行乘法運算防止溢位

#include "stdio.h"

#include "memory.h"

#include "stdlib.h"

#include "string.h"

#define f_signed_num 1 //符號位

#define f_exponet_num 8 //指數字

#define f_significand_num 23 //有效數字位

#define f_e_size 127 //指數基數大小

unsigned char bin2bcd(unsigned char bin)

unsigned char bcd2bin(unsigned char bcd)

void bins2bcds(unsigned char* src, unsigned char* des, unsigned int n)

void bcds2bins(unsigned char* src, unsigned char* des, unsigned int n)

void bcdsls4bins(char* src, int n )

void bcdsrs4bins( char* src, int n )

void binsmul10(unsigned char* src, int n)

;int i = 0, l = 0;

unsigned char tc = 0;

l = strlen((char*)src);

for( i = 0; i < l; i++ )

for( i = l-1; i >= 0; i-- )

for( i = l-1; i > 0; i-- )

if(src[i]&0xf0)

for( i = 0; i < l; i++ )

}int strtohex(unsigned char* src)

for( i = 0; i < l; i++)

return tr;

}unsigned int getff( float in_f, int n)

;unsigned int points = 0;

memcpy( (unsigned char*)&fi, (unsigned char*)&in_f, 4);

fe = fi<<1>>(1+23); //獲得指數移碼

//帶整數和純小數的小數部分

if(fe>=127)

fs = fi<<(fe-127+1+8)>>(fe-127+1+8);

else

fs = ((fi<<(1+8)>>(1+8))|0x00800000);

points = 150-fe;

//這個函式功能可由參考_itoa實現,不需要庫

sprintf((char*)ia, "%x", fs);

while(n--)

binsmul10((unsigned char*)ia, 10); //乘以需要位的10的指數

for( i = 0; i < points/4; i++ )

bcdsrs4bins(ia,10);

fs = strtohex((unsigned char*)ia);

return (fs>>points%4); //除以2^小數字數 得到小數值

}void main()

;fi = getff(tf, 6);

sprintf(test, "%f", tf);

tf = 0.7513458933;

fi = getff(tf, 9);

sprintf(test, "%0.10f", tf);

}這樣可以做到任意位抽取

C floor函式 截斷浮點數小數部分 轉

在論壇裡看到了乙個人的提問,關於如何截斷浮點數小數部分的問題。我的第一感覺是使用字串處理 呵呵,估計知道floor函式的人都會笑話我了 的確,用c 也算挺久了,竟然不知道c 庫中的floor函式,可以輕易實現這個功能,唉,感慨 就不多說別的了,下面說一下關於floor函式 1 函式原型 1 doub...

js中取小數整數部分函式 取小數部分

parseint 23.56 結果 23 2.向上取整,有小數就整數部分加1 math.ceil 23.56 結果 24 3,四捨五入.math.round 23.56 結果 24 4,向下取整 math.floor 23.56 結果 23 附 如何判斷輸入的數值型別 使用時不帶引號!d 非負整數 ...

FPGA浮點小數與定點小數的換算及應用

有些fpga中是不能直接對浮點數進行操作的,只能採用定點數進行數值運算。所謂定點小數就是把小數點的位置固定,我們要用整數來表示小數。先以10進製為例。如果我們能夠計算12 34 46的話,當然也就能夠計算1.2 3.4 或者 0.12 0.34了。所以定點小數的 加減法和整數的相同,並且和小數點的位...