【问题标题】:Prime Factorisation Loop in SASSAS中的质因数分解循环
【发布时间】:2018-07-11 07:14:15
【问题描述】:

我正在做一些小任务来提高我的编码和效率,我今天正在处理的问题来自 Euler 项目,问题 3:

“找出 600851475143 中最大的素数”

我写的代码是:

data test;

a = 600851475143;
/*The subsequent a's are the next parts of the loop I'm trying to incorporate*/
/*a = 8462696833;*/
/*a = 10086647;*/
/*a = 6857;*/

if mod(a,2) = 0 then do;

a = a / 2;

end;

else do;

    do i = 3 to a until(flag);

        if mod(a,i) = 0 and i < a then do;

            b = i ;
            a = a / b ;
            flag = 1;
            output;

        end;
    end;

end;

run;

如何使变量 a 循环并变小,然后在没有 a 时终止,即最后一次迭代不会产生数据集,因为没有分解。

我也很高兴收到有关如何使这段代码更高效的任何提示,因为我正在努力学习

【问题讨论】:

标签: loops if-statement sas do-loops sas-studio


【解决方案1】:

您将需要一些内部循环来消除每个因素的所有权力。

因素检查的一些问题

  • 去除 2 的幂只会去除分解中可能存在的许多 2 的幂中的第一个。
  • do i 循环也是如此(实际上是factor)。
  • do i 迭代 1,这意味着您正在检查偶数。去除这两个因素后不需要这样做——do i=3 to a by 2 … 会更好
    • 数字素数的上限是 sqrt(number)
    • 如果不想计算 sqrt,可以使用 number/2
    • 不管to 是多少,当数字减少到1 时,您都将退出分解循环,因此to a 是可以的。
    • 更智能的“求解器”将动态跟踪已知素数并仅测试这些素数。如果在检查最后一个已知素数后未实现完全分解,则必须提前 2

使用与其在解决方案中的角色相对应的变量名是有意义的——因此请考虑使用factor 而不是i。当然,对于个人代码,您可以使用您想要的名称,但对于将由您或其他人在未来维护的代码,最佳实践是好的变量名称。

在 SAS 中,不是在 DTA 步骤的顶部硬编码单个测试值,而是考虑处理(质因数分解)数据集中包含的任意数量的数字。

SAS 中的循环是通过各种do 代码结构完成的

  • do … while(condition); …iterated-statements… end;
    • 0 或更多循环 - 条件测试在执行任何迭代语句之前完成
  • do … until(condition); … end;
    • 1 个或多个循环 - 在执行迭代语句后完成条件测试
  • do index=from-value to to-value by by-value; … end;
    • 索引以相等的步长变化,可用作迭代语句的一部分
    • to-value 只计算一次,不能被迭代语句更改
    • whileuntil 可以附加到 do index= 声明中
    • to-value 是可选的,但除非存在whileuntil,或者至少有一个迭代语句执行leave 语句,否则将无限循环

你选择哪一个取决于问题。

制作要处理的数字数据集

data numbers; input number; format number 16.; datalines;
64
720
30
600851475143
8462696833
10086647
6857
run;

示例代码

内循环用于去除多次出现的因素。

更改:内部循环 (= -1, 1) 用于应用 6n+/-1 很可能是选择可能因素的素数定理。

data prime_factorizations(keep=number factor power);

  set numbers;
  objective = floor(abs(number));

  factor = 2;
  do power = 0 by 1 while (mod(objective,factor) = 0);
    objective = objective / factor;
  end;
  if power then output;

  factor = 3;
  do power = 0 by 1 while (mod(objective,factor) = 0);
    objective = objective / factor;
  end;
  if power then output;

  * after 2 and 3 all primes are of form 6n +/- 1;
  * however, not all 6n +/- 1 are prime;

  * in essence operate a sieve to check for factors;
  * of course the best sieve is a list of primes,
  * but 6n +/- 1 knocks out a lot of unnecessary checks; 

  do n = 1 to objective while (objective > 1);
    do offset = -1, 1;
      factor = 6*n + offset;
      do power = 0 by 1 while (mod(objective,factor) = 0);
        objective = objective / factor;
      end;
      if power then OUTPUT;
      if objective = 1 then leave;
    end;
  end;
run;

title "Prime factorization of some numbers";
proc print noobs data=prime_factorizations;
run;

proc sql;
  title "Max prime factor of various numbers";
  select number, max(factor) as max_prime_factor
  from prime_factorizations group by number;
quit;

title;

当然,这不是实际的大素数搜索器的操作方式,而是对任何给定语言的编程的一个很好的介绍。回到 CS“语言调查”中,我会尝试用正在学习的新语言编写上述代码。

【讨论】:

  • 我对我的代码最大的问题是关于变量 a 的自我实现,如上所述,您已经定义了一个数据集“数字”,其中包含大量因素,但在循环中,我正在寻找这些数字并希望用 a 的新值重新开始循环,是否可以突出显示此修改?
  • 我打算合并的另一个小功能是 3 之后的所有素数都遵循 6n+-1,将创建数据集以在 3 之后创建这些数字并将它们合并到循环中以节省时间跨度>
  • 您不需要包含 6n +/- 1 个主要候选者的单独数据集。它们可以在因子循环级别动态计算。查看更改
  • 当到达 DATA 步的底部时是 SAS,控件隐式(静默)返回到步的顶部。因此,再次到达 SET 语句,此时从numbers 数据集中读取下一条记录。
  • 数字数据集只是您想要分解的任何数字的列表。数据步输出prime_factorizations 每个数字素因子有一行,因此素数在输出中只有一行,而合数将有多行——proc 打印应该很明显。尝试将数字更改为因式以查看它们是如何因式分解的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多