使用 MATLAB 的二项式精度误差?
Accuracy error in binomials using MATLAB?
该值是绝对整数,不是浮点数值得怀疑,而且,它不是溢出,因为双精度值可以保持到 2^1024。
fprintf('%f',realmax)
179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
我在 nchoosek
函数中遇到的问题是它不产生精确值
fprintf('%f\n',nchoosek(55,24));
2488589544741302.000000
虽然关于 binomian(n,m)=binomial(n-1,m)+binomial(n-1,m-1)
的百分比误差为 2,如下所示
fprintf('%f',nchoosek(55-1,24)+nchoosek(55-1,24-1))
2488589544741301.000000
Ps:准确值为2488589544741300
MATLAB 有什么问题?
看起来像整数 (55
) 的东西和实际上是整数的东西(在变量类型方面)是有区别的。
你计算它的方式,你的值被存储为浮点数(这就是 realmax
指向你的 - 最大的正浮点数 - 检查 intmax('int64')
最大可能的整数值),因此您可能会得到浮点错误。一个大值的绝对差 2 并不意外 - 实际百分比误差很小。
此外,您在格式字符串中使用了 %f
- 例如要求它显示为浮点数。
具体来说,对于 nchoosek
,从文档中,输出作为非负标量值返回,与输入 n 和 k 的类型相同,或者,如果它们是不同的类型,则 non-double 类型(如果一个是 double,你只能有不同的输入类型)。
在 Matlab 中,当您直接在函数输入中键入数字时,它通常默认为浮点数。你必须强制它是一个整数。
试试看:
fprintf('%d\n',nchoosek(int64(55),int64(24)));
注意:%d
而不是 %f
,将两个输入都转换为具体的整数。这里nchoosek
的输出应该是int64
.
类型
我无法访问 MATLAB,但由于您显然可以使用 Octave,我将 post 基于此进行观察。
如果您使用 edit nchoosek
或 here 查看 Octave 源代码,您会发现计算二项式系数的公式非常简单:
A = round (prod ((v-k+1:v)./(1:k)));
如您所见,有 k
个分区,每个分区都有可能引入一些小错误。下一行试图提供帮助并警告您可能会丢失精度:
if (A*2*k*eps >= 0.5)
warning ("nchoosek", "nchoosek: possible loss of precision");
所以,如果我可以稍微修改一下你的最后一个问题,Octave 有什么问题?我会说没有错。作者显然知道不精确的可能性,并包括一个检查以在这种可能性出现时警告用户。所以该功能按预期工作。如果您的应用程序需要比 built-in 函数提供的更高的精度,看起来您需要编写(或找到)一些东西来计算更精确的中间结果。
你对realmax
函数的理解是错误的。这是可以存储的最大值,但是对于如此大的数字,您的浮点精度误差远高于 1。第一个不能存储在 double 值中的整数是 2^53+1
,请尝试 2^53==2^53+1
举个简单的例子。
如果符号工具箱可用,最容易实施的解决方案是使用它:
>> nchoosek(sym(55),sym(24))
ans =
2488589544741300
该值是绝对整数,不是浮点数值得怀疑,而且,它不是溢出,因为双精度值可以保持到 2^1024。
fprintf('%f',realmax)
179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
我在 nchoosek
函数中遇到的问题是它不产生精确值
fprintf('%f\n',nchoosek(55,24));
2488589544741302.000000
虽然关于 binomian(n,m)=binomial(n-1,m)+binomial(n-1,m-1)
的百分比误差为 2,如下所示
fprintf('%f',nchoosek(55-1,24)+nchoosek(55-1,24-1))
2488589544741301.000000
Ps:准确值为2488589544741300
MATLAB 有什么问题?
看起来像整数 (55
) 的东西和实际上是整数的东西(在变量类型方面)是有区别的。
你计算它的方式,你的值被存储为浮点数(这就是 realmax
指向你的 - 最大的正浮点数 - 检查 intmax('int64')
最大可能的整数值),因此您可能会得到浮点错误。一个大值的绝对差 2 并不意外 - 实际百分比误差很小。
此外,您在格式字符串中使用了 %f
- 例如要求它显示为浮点数。
具体来说,对于 nchoosek
,从文档中,输出作为非负标量值返回,与输入 n 和 k 的类型相同,或者,如果它们是不同的类型,则 non-double 类型(如果一个是 double,你只能有不同的输入类型)。
在 Matlab 中,当您直接在函数输入中键入数字时,它通常默认为浮点数。你必须强制它是一个整数。
试试看:
fprintf('%d\n',nchoosek(int64(55),int64(24)));
注意:%d
而不是 %f
,将两个输入都转换为具体的整数。这里nchoosek
的输出应该是int64
.
我无法访问 MATLAB,但由于您显然可以使用 Octave,我将 post 基于此进行观察。
如果您使用 edit nchoosek
或 here 查看 Octave 源代码,您会发现计算二项式系数的公式非常简单:
A = round (prod ((v-k+1:v)./(1:k)));
如您所见,有 k
个分区,每个分区都有可能引入一些小错误。下一行试图提供帮助并警告您可能会丢失精度:
if (A*2*k*eps >= 0.5)
warning ("nchoosek", "nchoosek: possible loss of precision");
所以,如果我可以稍微修改一下你的最后一个问题,Octave 有什么问题?我会说没有错。作者显然知道不精确的可能性,并包括一个检查以在这种可能性出现时警告用户。所以该功能按预期工作。如果您的应用程序需要比 built-in 函数提供的更高的精度,看起来您需要编写(或找到)一些东西来计算更精确的中间结果。
你对realmax
函数的理解是错误的。这是可以存储的最大值,但是对于如此大的数字,您的浮点精度误差远高于 1。第一个不能存储在 double 值中的整数是 2^53+1
,请尝试 2^53==2^53+1
举个简单的例子。
如果符号工具箱可用,最容易实施的解决方案是使用它:
>> nchoosek(sym(55),sym(24))
ans =
2488589544741300