繁体   English   中英

Matlab nchoosek使用int64和sym获得了不同答案

[英]Matlab nchoosek got difference answer using int64 and sym

这是关于Matlab中的nchoosek函数的问题。

我想找到nchoosek(54,25) ,它与54C25相同。 由于答案约为10 ^ 15,因此我最初使用int64 但是,关于象征性答案,答案是错误的。

输入:

nchoosek(int64(54),int64(25))
nchoosek(sym(54),sym(25))

输出:

1683191473897753
1683191473897752

您会看到它们相差一个。 由于我现在使用sym所以这并不是真正的紧急问题。 但是有人可以告诉我为什么会这样吗?


编辑:

我正在使用R2013a。

我看一下nchoosek.m ,发现如果输入在int64 ,则代码可以简化为

function c = nchoosek2(v,k)

    n = v;  % rename v to be n. the algorithm is more readable this way.

    classOut = 'int64';
    nd = double(n);
    kd = double(k);
    nums = (nd-kd+1):nd;
    dens = 1:kd;
    nums = nums./dens;      %%
    c = round(prod(nums));
    c = cast(c,classOut);
end

但是,对我来说, int64(prod(nums./dens))的结果不同于prod(sym(nums)./sym(dens)) int64(prod(nums./dens)) prod(sym(nums)./sym(dens)) 每个人都一样吗?

我在R2014a上没有这个问题:

数字

>> n = int64(54);
>> k = int64(25);
>> nchoosek(n,k)
ans =
     1683191473897752    % class(ans) == int64

象征

>> nn = sym(n);
>> kk = sym(k);
>> nchoosek(nn,kk)
ans =
1683191473897752         % class(ans) == sym

% N!/((N-K)! K!)
>> factorial(nn) / (factorial(nn-kk) * factorial(kk))
ans =
1683191473897752         % class(ans) == sym

如果检查函数edit nchoosek.m的源代码,您会看到它专门使用单独的算法处理64位整数的情况。 我不会在这里重现代码,但是这里是重点:

function c = nchoosek(v,k)
    ...

    if int64type
        % For 64-bit integers, use an algorithm that avoids
        % converting to doubles
        c = binCoef(n,k,classOut);
    else
        % Do the computation in doubles.
        ...
    end

    ....
end

function c = binCoef(n,k,classOut)
    % For integers, compute N!/((N-K)! K!) using prime factor cancellations
    ...
end

在2013a中可以复制...

@Amro在nchoosek中显示int64或unit64的classOut的特殊情况,
但是在2013a中,仅当答案介于

  • flintmax (不带参数)和
  • double(intmax(classOut)) + 2*eps(double(intmax(classOut)))

对于int64 ,它给出了9007199254740992和922337203685477575808,而解决方案并不位于...


如果解决方案落在这些值之间,则将使用子函数binCoef重新计算其帮助状态: 对于整数,请使用质因子抵消来计算N!/(((NK)!M!)

对于给定的int64输入, binCoef函数将产生正确的答案

在2013年中,使用这些输入的binCoef不被调用

而是使用“默认”帕斯卡三角形方法,其中:

  • 输入转换为双精度
  • 向量((n-k+1):n)./(1:k)的乘积
  • 此向量包含分数的k双精度表示。

因此,我们几乎可以肯定是浮点错误


该怎么办?

我可以看到两个选择;

  1. 根据binCoef中的代码创建自己的函数,
  2. 修改nchoosek并从第81行中删除&& c >= flintmax

删除该表达式将迫使Matlab对int64和uint64的输入中精度范围内的任何值使用更精确的基于整数的计算。 这会稍慢一些,但会避免浮点错误,这在使用整数类型时理应是意外的。

选项一- 应该相当简单...

选项二-我建议保留原始功能的不变备份,或使用修改内容复制该功能,然后改用该功能。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM