最近嘗試用Cocoa做一個(gè)四則運(yùn)算計(jì)算器來練手,類似于Windows cmd: calc的那種。
畢竟這個(gè)東西算是我們項(xiàng)目組的入門練習(xí),當(dāng)年很多新人剛進(jìn)來,老組長(zhǎng)都會(huì)教他們用MFC/QT做個(gè)計(jì)算器來看看水平。由于各種原因,我當(dāng)年倒是沒有受到這種“禮遇”,等我真正開始做軟件的時(shí)候,還是服務(wù)器端這樣的純C++代碼做得比較多。但是不做不知道,一做才發(fā)現(xiàn)UI的邏輯還是挺復(fù)雜的,比如說,按“1”是追加到當(dāng)前顯示還是覆蓋現(xiàn)有的顯示呢,最后把邏輯弄清楚倒不是很麻煩,但要寫出好看的代碼還是有比較大的差距的。
以上都是前言,好像比較長(zhǎng)……
要說的是,在這個(gè)過程中發(fā)現(xiàn)的問題,計(jì)算結(jié)果是浮點(diǎn)數(shù),要怎么判斷其是否能無損地轉(zhuǎn)換成整數(shù),從而消除小數(shù)點(diǎn)后的一段無用的“0”,以更好地顯示。直接上代碼:
1 template <typename FloatType>
2 struct _floattype_meta
3 {
4 };
5
6 template<>
7 struct _floattype_meta<float>
8 {
9 enum {
10 EXPO_OFFSET = 23,
11 EXPO_LEN = 8
12 };
13
14 typedef uint32_t match_uint_type;
15 };
16
17 template<>
18 struct _floattype_meta<double>
19 {
20 enum {
21 EXPO_OFFSET = 52,
22 EXPO_LEN = 11
23 };
24
25 typedef uint64_t match_uint_type;
26 };
27
28 template <typename FloatType>
29 struct float_to_int
30 {
31 typedef struct _floattype_meta<FloatType> _meta;
32
33 bool operator() ( FloatType f, FloatType precision )
34 {
35 static const _meta::match_uint_type EXPO_MASK =
36 (~((~(_meta::match_uint_type)0) << _meta::EXPO_LEN )) << _meta::EXPO_OFFSET;
37 _meta::match_uint_type* pf = (_meta::match_uint_type*)&f;
38 uint32_t expo = ((*pf) & EXPO_MASK) >> _meta::EXPO_OFFSET;
39
40 static const uint32_t EXPO_FIRSTBIT_MASK = 1<< (_meta::EXPO_LEN-1);
41 static const uint32_t EXPO_BOUND = EXPO_FIRSTBIT_MASK - 1;
42 if ( expo >= EXPO_BOUND )
43 {
44 uint32_t to_right_move = expo - EXPO_BOUND;
45 if ( to_right_move >= _meta::EXPO_OFFSET )
46 {
47 return true;
48 }
49 uint32_t cmp_len = _meta::EXPO_OFFSET - to_right_move;
50 _meta::match_uint_type mask = ~(~((_meta::match_uint_type)0) << cmp_len);
51 return (*pf&mask) ? false : true;
52 }
53 else
54 {
55 return ( f < precision && f > -precision ) ? true : false;
56 }
57 }
58 };
我的方法是通過浮點(diǎn)型的結(jié)構(gòu)來進(jìn)行判斷。
浮點(diǎn)類型一般結(jié)構(gòu)如下:
|+/-| exponent | tail |
對(duì)于float,指數(shù)部分為8字節(jié),尾數(shù)部分為23字節(jié)。
對(duì)于double,指數(shù)部分為11字節(jié),尾數(shù)部分為52字節(jié)。
其中指數(shù)部分是采用偏移方式的,比如float的指數(shù)部分為130,偏移值為127,即實(shí)際指數(shù)為130-127。
更詳細(xì)的請(qǐng)參考
這里。
判斷方法是,計(jì)算指數(shù)的值,根據(jù)偏移判斷小數(shù)點(diǎn)后的尾數(shù),想得比較簡(jiǎn)單,汗!
引入?yún)?shù)精度是為了判斷值小于1時(shí)達(dá)到某個(gè)閾值的時(shí)候可以將后面的小數(shù)略去。
Honestly,其實(shí)這個(gè)應(yīng)該可以用sprintf,然后判斷小數(shù)點(diǎn)后的“0”來實(shí)現(xiàn)的,似乎更加簡(jiǎn)單方便。
但是我覺得,作為一個(gè)“碼農(nóng)”,重造輪子也是一種趣味嘛!