天天看點

matlab error函數_深度對比Python(Numpy,Scipy)與Matlab的數值精度

CSDN原文:https://blog.csdn.net/cauchy7203/article/details/107785295

Matlab一度被認為是最專業的數值計算工具之一,相信許多同學都或多或少用過這個工具。相比而言,Python作為一種膠水式的語言,其設計之初就不是為科學計算服務的。之前也看到許多人在吐槽說用Python去複現一些計算過程時經常失敗,是以(包括本人)也懷疑過是Python本身數值精度不夠導緻的。那麼Python的精度究竟如何,本文就來一探究竟。為了友善,我們就用線性方程組的求解來對比這一事實。

1、實驗設計

  • 基本思路:

本文考慮的線性方程組:

matlab error函數_深度對比Python(Numpy,Scipy)與Matlab的數值精度
matlab error函數_深度對比Python(Numpy,Scipy)與Matlab的數值精度
  • 關鍵問題一:保證兩種語言處理的資料完全一緻

這裡第二步其實很重要,由于Matlab預設資料類型為

double

,而Python的預設類型為

float

,如果直接粘貼或者導入就有可能在Python中被截斷,進而導緻在一開始使用的資料就存在誤差,使得實驗結果不可信。

  • 關鍵問題二:選取合适的名額來進行對比

第四步主要是計算兩種程式跑完後誤差的平方和: $$ |Ax-b|^2 $$ 這種驗證方式比較簡單。之是以這麼做是因為數值計算過程中不一定能夠得到100%的精度,這個問題的主要原因是在數值計算時數字不會一直保持為真實值。尤其在除法時由于數值長度的限制會被強行截斷一部分,是以用這個名額來驗證方法是否正确是很有必要的。當然,根據它的定義不難看出,這個值最小精度就越高。

2、資料生成和處理

首先由Matlab随機生成一個矩陣和一個向量:

A = rand(5,5)
b = rand(1,0)
           

然後在Matlab中将資料粘至txt檔案,再整理成Python的格式粘生成Numpy數組,同時也将資料重新粘回Matlab代碼。這裡原始資料是這個樣子:

A的值

0.814723686393179   0.0975404049994095  0.157613081677548   0.141886338627215   0.655740699156587
0.905791937075619   0.278498218867048   0.970592781760616   0.421761282626275   0.0357116785741896
0.126986816293506   0.546881519204984   0.957166948242946   0.915735525189067   0.849129305868777
0.913375856139019   0.957506835434298   0.485375648722841   0.792207329559554   0.933993247757551
0.632359246225410   0.964888535199277   0.800280468888800   0.959492426392903   0.678735154857774
           

b的值

0.757700000000000
0.743100000000000
0.392200000000000
0.655500000000000
0.171200000000000
           

當然也可以采用round函數一類的方式進行處理。

注意 這種操作雖然看似簡單并且有點笨拙,但能很好地保證二者在初始化時得到的結果是一樣的。

Matlab的操作相對簡單,直接将txt中的内容首尾加上

[]

,再粘回代碼即可。對于Python要稍加處理,最終的代碼是:

import numpy as np
A = np.array([0.814723686393179,0.905791937075619,0.126986816293506,0.913375856139019,0.632359246225410,0.0975404049994095,0.278498218867048,0.546881519204984,0.957506835434298,0.964888535199277,0.157613081677548,0.970592781760616,0.957166948242946,0.485375648722841,0.800280468888800,0.141886338627215,0.421761282626275,0.915735525189067,0.792207329559554,0.959492426392903,0.655740699156587,0.0357116785741896,0.849129305868777,0.933993247757551,0.678735154857774]).reshape([5,5]).T

b = np.array([0.757700000000000,0.743100000000000,0.392200000000000,0.655500000000000,0.171200000000000])
           
注意這裡Python的代碼最後要進行一下轉置,否則與Matlab的資料就就不一緻。

整理完成看看資料和txt中的形狀就完全一緻了:

A

array([[0.81472369, 0.0975404 , 0.15761308, 0.14188634, 0.6557407 ],
       [0.90579194, 0.27849822, 0.97059278, 0.42176128, 0.03571168],
       [0.12698682, 0.54688152, 0.95716695, 0.91573553, 0.84912931],
       [0.91337586, 0.95750684, 0.48537565, 0.79220733, 0.93399325],
       [0.63235925, 0.96488854, 0.80028047, 0.95949243, 0.67873515]])

b

array([0.7577, 0.7431, 0.3922, 0.6555, 0.1712])
           

這裡

b

變成了一維數組但不影響計算。

3、求解方程組

  • Matlab部分

用Matlab求解線性方程組十分簡單,直接一個反除号就可以搞定:

>> x = A  b

x =

   -0.8409
    3.7701
    3.8572
   -8.0050
    2.4445
           

注意這裡

x

跑出來的值隻是顯示值,實際值的位數是遠大于這個值的:

-0.840928749143009  3.77006972003583    3.85716025378275    -8.00495386938441   2.44448015270832
           
  • Python部分

用Python求解線性方程組的方式其實也很多,最簡單的辦法就是直接用

scipy

庫的

linalg

子產品中的

solve

方法:

from scipy.linalg import solve

x = solve(A,b)

x

array([-0.84092875,  3.77006972,  3.85716025, -8.00495387,  2.44448015])
           

為了更準确地對比數值的精度,我們将

x

的值用

np.savetxt

函數儲存至檔案再看具體數字:

-8.409287491430091910e-01
3.770069720035832184e+00
3.857160253782746739e+00
-8.004953869384410226e+00
2.444480152708315313e+00
           

仔細觀察發現,Python輸出的數值位數要稍多一些,這是因為我們用Matlab粘貼的時候它預設顯示的位數不太一樣。

注:這也是為什麼我們一定要在最開始進行資料統一規範的原因。Matlab在存儲變量時資料是儲存了完整的位數的,但即便從變量檢視視窗粘出來的數值也不一定是完整的數字。

4、精度驗證

  • Matlab部分
error = norm(A*x-b)

error =

   1.5801e-15

% 檢視15位
% 1.580118849929844e-15
           
  • Python部分
np.sqrt(np.sum((A.dot(x)-b)**2))

1.580118849929844e-15
           

注意,由于兩個數的量級都是

1e-15

,是以這裡隻需要看它們各自前16位即可。仔細觀察不難發現,兩個程式得到的結果完全一緻。

這裡我們把有效數字從第一位到最後一位排列直接放出來對比

# python
1580118849929843973242195223453751011511480618378089335607228349545039236545562744140625
# matlab
1580118849929843973242195223453751011511480618378089335607228349545039236545562744140625
           

肉眼觀察信不過,全部放入Python字元串試試對不對:

#第一行數字(python結果):
s1 = '1580118849929843973242195223453751011511480618378089335607228349545039236545562744140625'

#第二行數字(matlab結果):
s2 = '1580118849929843973242195223453751011511480618378089335607228349545039236545562744140625'
           

判斷一下是否相等:

s1 == s2

True
           

搞定!

5、結論

Python(Numpy, Scipy)的數值精度與Matlab是完全一緻的。