【问题标题】:Factorization of an integer整数的因式分解
【发布时间】:2014-01-28 12:01:42
【问题描述】:

在回答另一个问题时,我偶然发现了一个问题:没有符号数学工具箱,我实际上是如何找到整数的所有因数的。

例如:

factor(60)

返回:

 2     2     3     5

unique(factor(60))

因此将返回所有素数因子,“1” 缺失。

 2     3     5

我正在寻找一个可以返回所有因子的函数(1数字本身 并不重要,但它们会很好)

x = 60 的预期输出:

 1     2     3     4     5     6    10    12    15    20    30    60     

我想出了那个相当庞大的解决方案,除了它可能可以向量化之外,没有任何优雅的解决方案吗?

x = 60;

P = perms(factor(x));
[n,m] = size(P);
Q = zeros(n,m);
for ii = 1:n
    for jj = 1:m
        Q(ii,jj) = prod(P(ii,1:jj));
    end
end

factors = unique(Q(:))'

我还认为,对于某些大数字,此解决方案将失败,因为 perms 需要向量长度

【问题讨论】:

  • 你的代码不会生成12和20,只是说。
  • @Mahm00d:你是对的,甚至更糟。我更正了。

标签: matlab math factorization number-theory


【解决方案1】:

你可以找到一个数n的所有因数,方法是将它除以一个包含整数1到n的向量,然后找到除以1后的余数正好为零(即整数结果):

>> n = 60;
>> find(rem(n./(1:n), 1) == 0)

ans =

     1     2     3     4     5     6    10    12    15    20    30    60

【讨论】:

  • 我想过这样的事情,但以前从未听说过rem。太优雅了!
  • 不需要除法。 rem 一个人就够了(看我的回答)
  • 这种暴力破解方法对于较大的整数来说很慢,更不用说它很容易抛出内存不足的错误(例如n=1e9 需要大约 8GB 的​​内存)。
  • @Amro:内存肯定是较大整数的一个问题,但可以通过一些技巧来缓解(您在回答中提到了其中一些技巧)。我只是给出了可能适用于大多数情况的快速而肮脏的答案,而这正在躲避 OP。 :)
  • 真的很难决定哪个是“最佳”答案,因为您/Luis 的方法对于少数人来说非常有建设性,但对于相当大的人数来说 amro 是无与伦比的,这是经过深思熟虑的。跨度>
【解决方案2】:

@gnovice's answer的改进是跳过除法操作:单独rem就足够了:

n = 60;
find(rem(n, 1:n)==0)

【讨论】:

  • 好收获!我完全错过了。
  • 我认为让 gnovices 的答案被选为接受是公平的,因为他有这个想法;)但无论如何 +1!
【解决方案3】:

以下是查找整数因数的六种不同实现的比较:

function [t,v] = testFactors()
    % integer to factor
    %{45, 60, 2059, 3135, 223092870, 3491888400};
    n = 2*2*2*2*3*3*3*5*5*7*11*13*17*19;

    % functions to compare
    fcns = {
        @() factors1(n);
        @() factors2(n);
        @() factors3(n);
        @() factors4(n);
        %@() factors5(n);
        @() factors6(n);
    };

    % timeit
    t = cellfun(@timeit, fcns);

    % check results
    v = cellfun(@feval, fcns, 'UniformOutput',false);
    assert(isequal(v{:}));
end

function f = factors1(n)
    % vectorized implementation of factors2()
    f = find(rem(n, 1:floor(sqrt(n))) == 0);
    f = unique([1, n, f, fix(n./f)]);
end

function f = factors2(n)
    % factors come in pairs, the smaller of which is no bigger than sqrt(n)
    f = [1, n];
    for k=2:floor(sqrt(n))
        if rem(n,k) == 0
            f(end+1) = k;
            f(end+1) = fix(n/k);
        end
    end
    f = unique(f);
end

function f = factors3(n)
    % Get prime factors, and compute products of all possible subsets of size>1
    pf = factor(n);
    f = arrayfun(@(k) prod(nchoosek(pf,k),2), 2:numel(pf), ...
        'UniformOutput',false);
    f = unique([1; pf(:); vertcat(f{:})])'; %'
end

function f = factors4(n)
    % http://rosettacode.org/wiki/Factors_of_an_integer#MATLAB_.2F_Octave
    pf = factor(n);                    % prime decomposition
    K = dec2bin(0:2^length(pf)-1)-'0'; % all possible permutations
    f = ones(1,2^length(pf));
    for k=1:size(K)
      f(k) = prod(pf(~K(k,:)));        % compute products 
    end; 
    f = unique(f);                     % eliminate duplicates
end

function f = factors5(n)
    % @LuisMendo: brute-force implementation
    f = find(rem(n, 1:n) == 0);
end

function f = factors6(n)
    % Symbolic Math Toolbox
    f = double(evalin(symengine, sprintf('numlib::divisors(%d)',n)));
end

结果:

>> [t,v] = testFactors();
>> t
t =
    0.0019        % factors1()
    0.0055        % factors2()
    0.0102        % factors3()
    0.0756        % factors4()
    0.1314        % factors6()

>> numel(v{1})
ans =
        1920

虽然第一个矢量化版本最快,但基于循环的等效实现 (factors2) 也紧随其后,这要归功于自动 JIT 优化。

请注意,我必须禁用蛮力实现 (factors5()),因为它会引发内存不足错误(以双精度存储向量 1:3491888400 需要超过 26GB 的内存!)。这种方法显然不适用于大整数,无论​​是空间还是时间。

结论:使用以下矢量化实现:)

n = 3491888400;
f = find(rem(n, 1:floor(sqrt(n))) == 0);
f = unique([1, n, f, fix(n./f)]);

【讨论】:

  • 好主意!您是否知道使用mod 而不是rem 可以将时间减半? (这就是为什么我从来没有听说过rem,我一直用mod,在大多数情况下实际上是一样的) - PS:我宁愿把你的结论放在首位,我不知道有多少人关心关于其他 5 种方法;)
  • @thewaywewalk:我实际上没有看到 remmod 之间的时间差异,正如您所说,除了列出的特殊情况外,它们实际上是相同的。我正在运行最新的 MATLAB 版本的 Windows 64 位。
  • 我用你的计时功能再次测试了它,我要么得到相同的时间,要么(在大多数情况下)其中一个速度快 5 倍。但是,这并不重要。
猜你喜欢
  • 1970-01-01
  • 2015-06-10
  • 2014-03-03
  • 2011-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多