RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 891685
Accepted
Crux Commissa
Crux Commissa
Asked:2020-10-11 17:02:08 +0000 UTC2020-10-11 17:02:08 +0000 UTC 2020-10-11 17:02:08 +0000 UTC

什么可以比数学 sqrt 更快?

  • 772

我有一个任务:我需要尽快找到几万亿个整数的整数平方根个数,不超过100,000^2 。 简单地说:

100 = 10^2 - 适合

3 = 不适合

28 = 不适合

49 = 7^2 - 适合

...

等等

作为任务的一部分,我使用 openMP 指令在处理器内核之间平均分配线程,但即使在这种情况下,程序执行速度也不太适合我。我目前使用的结构是这样的:

int y = sqrt(x);
if (y==int(y))
  i++;

我尝试使用 SET 查找,知道我的数字永远不会超过100,000^2

set<int> mySet;

for (int j = 1; j <= 100001; j++) 
    mySet.insert(j*j);

if (mySet.find(x) != mySet.end()) 
  i++;

但事实证明,这种方法比通常的平方根计算要慢很多倍。告诉我,是否有可能使用语言工具以某种方式加速一次迭代的执行,或者用更快的方法替换根下的计算?我会很高兴任何提示!

c++
  • 5 5 个回答
  • 10 Views

5 个回答

  • Voted
  1. Best Answer
    KoVadim
    2020-10-11T17:33:46Z2020-10-11T17:33:46Z

    有一种非常有效的方法可以加快计算速度——丢弃明显的“非正方形”。如果你回想一下学校数学,你可以猜到一个数字平方的最后 n 位数字只取决于数字本身的最后 n 位数字。因此得出结论 - 如果数字以 0 1 4 5 6 9 结尾,那么这可能是某个数字的平方。如果 2 3 7 8 - 那么这绝对不是正方形。

    但对于最后一位数字,它提供了 40% 的筛选。这还不够。对于最后两位数(00 01 04 09 16 21 24 25 29 36 41 44 49 56 61 64 69 76 81 84 89 96),辍学率已经是 78%。这是非常好的。也就是说,在五分之四的情况下,您甚至不需要计算任何东西。继续前行。使用最后三位数字,您已经可以过滤掉 84.1%,4 位数字 89.56 - 这非常非常好 - 您可以将随机数据增加十倍。

    数据本身可以存储在一个小数组中,并在启动时计算。可以通过 检索最后 3 位数字% 1000。

    • 24
  2. Герман Борисов
    2020-10-11T17:18:40Z2020-10-11T17:18:40Z

    我会尝试在位掩码上设置我自己的实现。我们在一块中分配约 1.2 Gb 的内存,并在其中设置 100,000 个必要的位。

    由于 set 将非常稀疏,我们首先检查整个字节是否不为 0,如果是,我们检查所需的位。

    也许一次处理 4 或 8 个字节会比 1 个字节快。

    • 6
  3. MBo
    2020-10-11T17:31:57Z2020-10-11T17:31:57Z

    为了不浪费大量内存,创建一个布隆过滤器

    这是一种数据结构,可让您确定一个元素是否属于一个集合(在本例中为一组正方形1,4,9...10^10)。

    它有一个特性——算法可以报告集合中存在一个元素,尽管实际上它不是——一个误报。

    在这种情况下,您将不得不用手检查,移除根部。但是,对于大多数数字(误报的比例取决于分配的内存),不需要这样的检查,因为 没有假阴性。

    Delphi 中的示例

    var
      b: TSynBloomFilter;
      i, cnt: Integer;
      ii: Int64;
    begin
      //выбираем 5xразмер словаря, больший размер уже не особо влияет на количество коллизий
      b := TSynBloomFilter.Create(500000);
      try
        //загоняем квадраты до 10^10
        for i := 1 to 100000 do begin
          ii := int64(i) * i;
          b.Insert(@ii, sizeof(ii));
        end;
    
        //считаем, сколько обнаружений выпало на диапазоне 10^8
        //истинных совпадений 10000
        cnt := 0;
        for i := 1 to 100000000 do begin
          ii := i;
          if b.MayExist(@ii, sizeof(ii)) then
              Inc(cnt);
        end;
         //через две секунды видим - 
        //получается, что потребовалось проверить 11359 чисел
        Memo1.Lines.Add(cnt.ToString);
      finally
        b.Free;
      end;
    
    • 6
  4. ffk
    2020-10-11T17:27:16Z2020-10-11T17:27:16Z

    使用 std::set 的想法很好,但您需要使用由脚本生成的排序正方形数组而不是 std::set,您应该得到如下内容:

    const int64_t n2[] = { 1, 4, 9, 16, 25, ... 100000^2 };
    

    此外,使用二分搜索,std::lower_bound(n2, n2+size, testValue)您将很快找到所需的值(或找不到)。这样的阵列只需要 800kb 并且很容易放入处理器缓存中

    • 3
  5. AlexGlebe
    2020-10-11T18:28:54Z2020-10-11T18:28:54Z

    尝试整数根。也许它会更快,但我不相信。

    # include <stdbool.h>
    # include <stdio.h>
    
    long isqrt(long ) ;
    long isqrt(long num) {
        long res = 0;
        long bit = 1L << (sizeof(long)*8-2); // 2^62
        while (bit > num)        bit >>= 2;
        while (bit) {
            if (num >= res + bit) {
                num -= res + bit;
                res = (res >> 1) + bit;        }
            else            res >>= 1;
            bit >>= 2;    }
        return res; }
    
    bool isSquare(long x) ;
    bool isSquare(long x){
      long y = isqrt(x);
      //fprintf(stdout,"y = %ld\n",y);
      return y*y == x;}
    
    int main(){
      long x;
      fprintf(stdout,"print number ?");
      fscanf(stdin,"%ld",&x);
      bool res = isSquare(x);
      fprintf(stdout,"result = %s\n",(res?"true":"false"));
      return 0;}
    
    • 0

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    是否可以在 C++ 中继承类 <---> 结构?

    • 2 个回答
  • Marko Smith

    这种神经网络架构适合文本分类吗?

    • 1 个回答
  • Marko Smith

    为什么分配的工作方式不同?

    • 3 个回答
  • Marko Smith

    控制台中的光标坐标

    • 1 个回答
  • Marko Smith

    如何在 C++ 中删除类的实例?

    • 4 个回答
  • Marko Smith

    点是否属于线段的问题

    • 2 个回答
  • Marko Smith

    json结构错误

    • 1 个回答
  • Marko Smith

    ServiceWorker 中的“获取”事件

    • 1 个回答
  • Marko Smith

    c ++控制台应用程序exe文件[重复]

    • 1 个回答
  • Marko Smith

    按多列从sql表中选择

    • 1 个回答
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Suvitruf - Andrei Apanasik 什么是空? 2020-08-21 01:48:09 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5