ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

c – (n * 2-1)%p:当n和p为32位时,避免使用64位

2019-08-30 00:05:03  阅读:215  来源: 互联网

标签:modulus c c11 algorithm math


考虑以下功能:

inline unsigned int f(unsigned int n, unsigned int p) 
{
    return (n*2-1)%p;
}

现在假设n(和p)大于std :: numeric_limits< int> :: max().

例如f(4294967295U,4294967291U).

数学结果为7,但函数将返回2,因为n * 2将溢出.

然后解决方案很简单:我们只需要使用64位整数.假设函数的声明必须保持不变:

inline unsigned int f(unsigned int n, unsigned int p) 
{
    return (static_cast<unsigned long long int>(n)*2-1)%p;
}

一切都好.至少在原则上.问题是这个函数在我的代码中会被调用数百万次(我的意思是溢出版本),64位模数比32位版本慢(例如参见here).

问题如下:是否存在任何技巧(数学或算法)以避免执行64位版本的模数运算.什么是使用这个技巧的新版本的f? (保持相同的声明).

>注1:n> 0
>注2:p> 2
>注3:n可以低于p:n = 4294967289U,p = 4294967291U
>注4:使用的模数运算次数越少越好(3 32位模数太大,2很有意思,1肯定会超越)
>注5:当然结果将取决于处理器.假设在最后的至强可用的超级计算机上使用.

解决方法:

即使我不喜欢处理AT& T语法和GCC的“扩展asm约束”,我认为这是有效的(它在我的工作中,无可否认有限,测试)

uint32_t f(uint32_t n, uint32_t p)
{
    uint32_t res;
    asm (
      "xorl %%edx, %%edx\n\t"
      "addl %%eax, %%eax\n\t"
      "adcl %%edx, %%edx\n\t"
      "subl $1, %%eax\n\t"
      "sbbl $0, %%edx\n\t"
      "divl %1"
      : "=d"(res)
      : "S"(p), "a"(n)
      : 
      );
  return res;
}

我不知道,这些限制可能是不必要的严格或错误.它似乎工作.

这里的想法是进行常规的32位分割,实际上需要64位的分红.它仅在商符合32位(否则发出溢出信号)时有效,在这种情况下总是如此(p至少为2,n不为零).除法之前的东西处理时间2(溢出到edx,“高半”),然后“减1”处理潜在的借位. “= d”输出的东西使得剩余的结果. “a”(n)将n放入eax(让它选择另一个寄存器没有帮助,除法将在edx:eax中输入). “S”(p)可能是“r”(p)(似乎有效),但我不确定是否相信它.

标签:modulus,c,c11,algorithm,math
来源: https://codeday.me/bug/20190829/1764446.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有