如何在Matlab中处理精度问题?
我正试图用Matlab编写一个生日问题计算器,但有一个精度问题,其中(1-非常小的浮点数=1) 我目前的问题是,我想知道在一个网站上,如果有23000000个活动会话令牌,其中有128位可能的唯一值,那么在猜测UUID时需要尝试多少次,因此猜测有效令牌的几率超过50% 我首先通过以下方式模拟该过程:如何在Matlab中处理精度问题?,matlab,floating-point,precision,Matlab,Floating Point,Precision,我正试图用Matlab编写一个生日问题计算器,但有一个精度问题,其中(1-非常小的浮点数=1) 我目前的问题是,我想知道在一个网站上,如果有23000000个活动会话令牌,其中有128位可能的唯一值,那么在猜测UUID时需要尝试多少次,因此猜测有效令牌的几率超过50% 我首先通过以下方式模拟该过程: 我将我的成功率设定为(23000000/(2^128)) 我将失败率设置为(1-成功率) 但是我注意到这个值是1 更糟糕的是,在中输入(1-23000000/(2^128))^n>0.5不会提供有用
(1-23000000/(2^128))^n>0.5
不会提供有用的答案
我的第一个想法是完全抛弃Matlab,用Java创建我自己的库,它根本不使用浮点值,而是将比率存储为一对BigDecimal对象,这将通过只在最后一点进行计算消除所有精度问题,并将此计算存储为一对最小-最大值,以将结果显示为解决方案所在的范围(如果精确解不存在,因为浮点除法会导致错误和值,而这些错误和值无法使用指定精度的浮点来表示,但可以通过仅指定实际比率来表示精确答案,因为除法从未应用于实际比率,所以会显示该比率)
有没有一种不用发明这样一个系统就可以解决这类问题的方法,或者这些问题本质上不可能用浮点系统来解决
…这些问题是否天生就不可能用浮点系统解决
简短解释:
在MATLAB中默认为是,如果使用MATLAB中的符号工具箱,则为否
在MATLAB中,你可以用双精度浮点数来表示非常非常小的数字。但是,你遇到的问题与操作彼此相差太多数量级的双精度浮点数有关-在执行计算时,你会受到MA精度的限制TLAB计算
谢天谢地,有一个工具箱以符号工具箱的形式来缓解这个问题。如果您想在执行1-(小值)
时得到除1以外的其他值,请查看该工具箱
详细解释:
MATLAB中的双精度浮点数具有令人印象深刻的最大精度,分别为-1.79769e+308到-2.22507e-308和2.22507e-308到1.79769e+308
。然而,MATLAB计算的最大精度仅为53位:精度为9.007199255×10%⁵.
以下是我对如何产生您遇到的结果的解释(1-小值=1):
数字1.234e12
的精度约为1e16
,这意味着MATLAB可以对该数字进行操作,误差约为1e-4
。同样,2.345e-7
的计算误差约为1e-23
。因此,将两个数字相加将产生1e-4
,因此较小的数值在MATLAB执行的计算误差中丢失
如果您不介意等待更长的计算时间(与在远大于53位的数字上执行操作相关),那么我强烈建议您使用MATLAB中的符号工具箱(即vpa
函数)
如果我的答案不适合你,也许你可以在MATLAB论坛上查看。我从这个答案中提取了部分样本数
快乐的编码,我希望这有帮助!很容易解释:
使用:
eps(double(1))
在Matlab中,您将发现1(其最大精度=双精度)与执行数学运算时可以区分的下一个浮点数之间的最小间隙。在这种情况下,间隙等于2.2204e-016
自:
success_rate = (23,000,000 / (2^128))
将返回
6.7591e-032
,当执行1时,它远小于上面介绍的差距-6.7591e-032 Matlab理解从1中减去0,因此您总是得到1作为答案。希望它能有所帮助。其他答案解释了为什么您不能使用ma中的差异执行所需的计算您正在使用的数字的大小。但是,正如我在评论中提到的,您可以尝试使用较小的数字来显示趋势。让我们将“投影”值size\u of_key\u space/(2*number\u of_key)
。对于获得50%的成功概率来说,这是一个天真的期望值。为了证明这一点,我对许多不同的键集和键空间进行了模拟。所有这些都很大,稀疏程度不同:
function sparse_probability()
num_keys = logspace(2, 5, 15); % number of keys varies from 1e2 to 1e5
key_spaces = logspace(6, 12, 15); % size of key space varies from 1e6 to 1e12
% so p_sucess varies from 1e-4 to 1e-7
num_experiments = length(num_keys);
results = zeros(1,num_experiments);
proportions = zeros(1,num_experiments);
for i = 1:num_experiments
num_objs = num_keys(i);
size_of_key_space = key_spaces(i);
p_success = num_objs/size_of_key_space;
p_fail = 1 - p_success;
total_fail = 1;
num_trials = 0;
while (total_fail > 0.5)
total_fail = total_fail * p_fail;
num_trials = num_trials + 1;
end
results(i) = num_trials;
proportions(i) = num_trials/(size_of_key_space/(2*num_objs));
fprintf('p_success = %f, num_trials = %d, ratio = %f, num_keys = %e; size key_space = %e\n', 1 - total_fail, num_trials, proportions(i), num_objs, size_of_key_space);
end
由于密钥集和密钥空间的大小差异很大,我计算了上述“预测”值的比率,以及达到50%概率所需的实际试验次数。上述函数的输出为:
p_success = 0.500044, num_trials = 6932, ratio = 1.386400, num_keys = 1.000000e+02; size key_space = 1.000000e+06
p_success = 0.500010, num_trials = 11353, ratio = 1.386293, num_keys = 1.637894e+02; size key_space = 2.682696e+06
p_success = 0.500006, num_trials = 18595, ratio = 1.386292, num_keys = 2.682696e+02; size key_space = 7.196857e+06
p_success = 0.500008, num_trials = 30457, ratio = 1.386309, num_keys = 4.393971e+02; size key_space = 1.930698e+07
p_success = 0.500004, num_trials = 49885, ratio = 1.386300, num_keys = 7.196857e+02; size key_space = 5.179475e+07
p_success = 0.500001, num_trials = 81706, ratio = 1.386294, num_keys = 1.178769e+03; size key_space = 1.389495e+08
p_success = 0.500001, num_trials = 133826, ratio = 1.386297, num_keys = 1.930698e+03; size key_space = 3.727594e+08
p_success = 0.500002, num_trials = 219193, ratio = 1.386298, num_keys = 3.162278e+03; size key_space = 1.000000e+09
p_success = 0.500001, num_trials = 359014, ratio = 1.386295, num_keys = 5.179475e+03; size key_space = 2.682696e+09
p_success = 0.500001, num_trials = 588027, ratio = 1.386296, num_keys = 8.483429e+03; size key_space = 7.196857e+09
p_success = 0.500000, num_trials = 963125, ratio = 1.386295, num_keys = 1.389495e+04; size key_space = 1.930698e+10
p_success = 0.500000, num_trials = 1577496, ratio = 1.386294, num_keys = 2.275846e+04; size key_space = 5.179475e+10
p_success = 0.500000, num_trials = 2583771, ratio = 1.386294, num_keys = 3.727594e+04; size key_space = 1.389495e+11
p_success = 0.500000, num_trials = 4231943, ratio = 1.386295, num_keys = 6.105402e+04; size key_space = 3.727594e+11
p_success = 0.500000, num_trials = 6931472, ratio = 1.386294, num_keys = 1.000000e+05; size key_space = 1.000000e+12
如果要绘制比率列与键空间大小的关系图,则会得到一条直线。如中所示,只要键集和键空间相距数个数量级,比率基本上是恒定的。请注意,稀疏度会发生变化,但这不会影响比率。这是此类稀疏概率的典型特征问题。从这个简单的实验中,你可以非常有把握地说,在2^128=3.4e38
的键空间中,使用2.3e7
键所需的猜测次数是1.386294
以上的比率限制与总共
1.386294 * (2^128 / (2 * 2.3e7)) = 1.02550305123542e+31
猜测有效UUID的50%几率需要猜测
以每秒1万亿次的猜测速度,需要3250亿年才能做出如此多的猜测。换句话说,你是安全的。
(a + b)^n = a^n + C(1,n)a^(n-1)b + C(2,n)a^(n-2)b^2 + ...
(1 - b)^n = 1 - n b + O(b^2)
(1 - 23000000/(2^128))^n = exp(n*log(1- 23000000/(2^128))
exp(n*log1p(-23000000/(2^128)))