如何在Matlab中处理精度问题?

如何在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不会提供有用

我正试图用Matlab编写一个生日问题计算器,但有一个精度问题,其中(1-非常小的浮点数=1)

我目前的问题是,我想知道在一个网站上,如果有23000000个活动会话令牌,其中有128位可能的唯一值,那么在猜测UUID时需要尝试多少次,因此猜测有效令牌的几率超过50%

我首先通过以下方式模拟该过程:

  • 我将我的成功率设定为(23000000/(2^128))
  • 我将失败率设置为(1-成功率)
  • 但是我注意到这个值是1

    更糟糕的是,在中输入
    (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)))