最近尝试用Cocoa做一个四则运算计算器来练手,类似于Windows cmd: calc的那种。
毕竟这个东西算是我们项目组的入门练习,当年很多新人刚进来,老组长都会教他们用MFC/QT做个计算器来看看水平。由于各种原因,我当年倒是没有受到这种“礼遇”,等我真正开始做软件的时候,还是服务器端这样的纯C++代码做得比较多。但是不做不知道,一做才发现UI的逻辑还是挺复杂的,比如说,按“1”是追加到当前显示还是覆盖现有的显示呢,最后把逻辑弄清楚倒不是很麻烦,但要写出好看的代码还是有比较大的差距的。
以上都是前言,好像比较长……
要说的是,在这个过程中发现的问题,计算结果是浮点数,要怎么判断其是否能无损地转换成整数,从而消除小数点后的一段无用的“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 };
我的方法是通过浮点型的结构来进行判断。
浮点类型一般结构如下:
|+/-| exponent | tail |
对于float,指数部分为8字节,尾数部分为23字节。
对于double,指数部分为11字节,尾数部分为52字节。
其中指数部分是采用偏移方式的,比如float的指数部分为130,偏移值为127,即实际指数为130-127。
更详细的请参考
这里。
判断方法是,计算指数的值,根据偏移判断小数点后的尾数,想得比较简单,汗!
引入参数精度是为了判断值小于1时达到某个阈值的时候可以将后面的小数略去。
Honestly,其实这个应该可以用sprintf,然后判断小数点后的“0”来实现的,似乎更加简单方便。
但是我觉得,作为一个“码农”,重造轮子也是一种趣味嘛!