免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 3914 | 回复: 18
打印 上一主题 下一主题

求助:求一个简单的小算法,经常被调用,希望高效点 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-02-09 21:43 |只看该作者 |倒序浏览
本帖最后由 okocha-jay 于 2010-02-10 10:08 编辑

大家都很热心,非常感谢。
才注册没几天,以后我回常来的。

  1. //这是等级0到9对应的最低分数线;比如,得分是2万,那么等级是1;因为超过了1万分(等级1,也就数组下标),没达到3万分(下标2)
  2. const unsigned int levels[10] = {0, 10000, 30000, 60000, 100000, 150000, 210000, 280000, 360000, 450000};

  3. 求一个函数,根据输入分数,得到对应等级

  4. int getLevel(unsigned int score);

  5. 我写了一个,谢谢大家的帮助
  6. unsigned short getLevel(unsigned int score )
  7. {
  8.         int low = 0, high = 9;
  9.         int mid;

  10.         while ( true )
  11.         {
  12.                 mid = (low + high ) / 2;

  13.                 if ( score >= levels[mid])
  14.                 {
  15.                         if ( mid==9 || score < levels[mid+1])
  16.                                 return mid;
  17.                         else
  18.                                 low = mid + 1;
  19.                 }
  20.                 else//不可能是mid等级
  21.                 {
  22.                         assert(mid>0);
  23.                         high = mid - 1;
  24.                 }
  25.         }
  26. }
复制代码

论坛徽章:
0
2 [报告]
发表于 2010-02-09 21:55 |只看该作者
写最原始的需求

论坛徽章:
0
3 [报告]
发表于 2010-02-09 21:57 |只看该作者
如果要被经常调用的话, 最好用汇编, 或者嵌入式汇编.

论坛徽章:
0
4 [报告]
发表于 2010-02-09 22:05 |只看该作者
如果要被经常调用的话, 最好用汇编, 或者嵌入式汇编.
yylogo 发表于 2010-02-09 21:57

这种优化是最最后才考虑的。

论坛徽章:
0
5 [报告]
发表于 2010-02-09 22:28 |只看该作者
看你的数据如果去掉四个0的话就是1,3,6,10,15,...,这个按照目前的规律是前n项自然数的和,也就是1+2+...+n=n*(n+1)/2,我们只要找到对应的n就可以了
假设你的输入是x,对于n*(n+1)/2=x化简后就是n^2 + n - 2*x = 0这个方程在x为正数的时候对应的n值唯一,且为正数,我们求解这个方程有
n=(sqrt(8*x+1)-1)/2,也就是我们根据x求出n后求整就可以了。
然后接下来就是求这个公式了,记得我们原先的x是在score/10000之后的,所以n=(sqrt(x/1250+1)-1)/2,函数内代码就一行:
  1. int getLevel(unsigned int score)
  2. {
  3.         return (int)((sqrt(score / 1250.0 + 1) - 1) / 2);
  4. }
复制代码
不知道有没有更快的,毕竟我用了sqrt,可能用牛顿叠代在你精度要求不大的时候计算次数少,会更快点儿,反正我的想法就是这样{:3_186:}

论坛徽章:
9
摩羯座
日期:2013-08-15 15:18:48狮子座
日期:2013-09-12 18:07:47金牛座
日期:2013-09-16 13:23:09辰龙
日期:2013-10-09 09:03:27白羊座
日期:2013-10-17 13:32:44子鼠
日期:2014-04-23 15:09:38戌狗
日期:2014-09-17 11:37:542015年亚洲杯之韩国
日期:2015-03-26 10:16:442015亚冠之武里南联
日期:2015-08-18 14:55:52
6 [报告]
发表于 2010-02-09 22:34 |只看该作者
本帖最后由 w_anthony 于 2010-02-09 22:37 编辑

回复 1# okocha-jay

通用方法是二分法,可以借助stl的std::lower_bound来完成,把内容存入vector,lower_bound得到iterator后跟begin减一下就行了。

不过也有更快的方法,你这组数字有一个规律:s = (n + 1) * n * 10000。
而对于给定一个s找出n的规则是满足s>=(n + 1) *n * 10000的最大正整数n,也就是满足n<=(sqrt(1 + 8 * s / 10000) - 1) / 2这个条件的最大正整数n,考虑浮点计算误差,那么C/C++代码大致如下:
int n = (int)((sqrt(1.0f + 8.0f * (s + 0.5f) / 10000.0f) - 1.0f) / 2.0f);
如果n有界限,可以最后判断一下截止也行。

论坛徽章:
0
7 [报告]
发表于 2010-02-09 22:36 |只看该作者
楼上,我们想一块儿去了,握个手吧

论坛徽章:
9
摩羯座
日期:2013-08-15 15:18:48狮子座
日期:2013-09-12 18:07:47金牛座
日期:2013-09-16 13:23:09辰龙
日期:2013-10-09 09:03:27白羊座
日期:2013-10-17 13:32:44子鼠
日期:2014-04-23 15:09:38戌狗
日期:2014-09-17 11:37:542015年亚洲杯之韩国
日期:2015-03-26 10:16:442015亚冠之武里南联
日期:2015-08-18 14:55:52
8 [报告]
发表于 2010-02-09 22:39 |只看该作者
回复 7# daybreakcx


   

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
9 [报告]
发表于 2010-02-09 22:58 |只看该作者
反正就那几个数,先生成一个46个值的表,然后查表,飞快。
int level[] =
{
    0, //0
    1, //10000
    1, //20000
    2, //30000
    2, //40000
    2, //50000
    3, //60000
    3, //70000
    ....
};

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:50:28
10 [报告]
发表于 2010-02-10 09:13 |只看该作者
查表不对吧,中间的数怎么办?

另外用sqrt和浮点数的方法,不见得比老老实实的一个个if else快,毕竟比较是整数,还可以用二分法优化一下。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP