首页 > 其他 > 详细

一个快速double转int的方法(利用magic number)

时间:2016-02-13 23:07:25      阅读:973      评论:0      收藏:0      [点我收藏+]

代码:

int i = *reinterpret_cast<int*>(&(d += 6755399441055744.0));

知识点:

1.reinterpret_cast<type_id> expression:type_id 必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)。

只是将bit表示进行了重新解读,不改变位表示

reinterpret_cast 只能在指针之间转换。

更多信息,参见msdn

2.magic number的原理:stackoverflow的页面

6755399441055744.0 = 1<<51 + 1<<52 = 2,251,799,813,685,248 + 4,503,599,627,370,496

 

技术分享

根据double类型的格式可知:尾数52位

从而double类型有一个性质:当数据大小处于2^52~2^53范围内时,可表示的数恰好为该范围内的整数(根据数据格式显然可知)

从而把一个(相对)非常小的double类型数强行规约到2^52~2^53范围内,截取它的后32位即为相应的int表示(因为加的数实际为11000...000,只影响第52和53位,都已经被舍去)

3.一些问题:

  1)为什么选择1<<51 + 1<<52?

  尝试1<<52作为参数,发现正数范围内舍入正常,但负数范围内出现奇怪的结果:

  [0~-0.25) --> 0

  [-0.25~-0.75) --> -1

  [-0.75~-1.25] --> -2

  (-1.25~1.75) --> -3

  行为类似于数据大小位于2^53~2^54范围的表现(只表示范围内的全部偶数,相当于上文范围*2)

  猜想:1<<51是为了让负数的表示也正常?如何实现?TODO1

  2)数据范围

  理论上来说double的大小不能大于2^51,但考虑到int的范围,足够用了

  (注意:此处的溢出行为与通常的转换例如static_cast<int>不同)

  3)存在的问题

  1.引用还是指针?

  更好的写法:int &i = reinterpret_cast<int &>(d += 6755399441055744.0);

  原因:TODO2

  2.舍入规则:round-to-even,2.5-->2,3.5-->4

  原因:TODO3

  3.会有static alias的问题,Undefined Behavior

  关于static alias:TODO4

 

螺蛳壳里做道场,一行代码有学问……

  

 

一个快速double转int的方法(利用magic number)

原文:http://www.cnblogs.com/giddens/p/5188393.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!