2016-11-18 54 views
0

下面的代碼給出了錯誤的答案。它應該給出大約0.5,這是一個數組的平均值,其中有許多隨機數在0和1之間。我認爲問題是因爲N是「大」,或者是生成的隨機數的精度?該代碼適用於較小的N值(10^7,10^6等)。一些建議將會有所幫助。對於N大的錯誤結果代碼。Common Lisp

預先感謝您。

(defun randvec(n) 
    (let ((arr (make-array n))) 
     (dotimes (i n) 
      (setf (aref arr i) (random 1.0)) 
     ) 
     arr 
    ) 
) 

(defparameter N (expt 10 8)) 
(setf *random-state* (make-random-state t)) 
(defparameter vector1 (randvec N)) 
(format t "~a~%" (/ (reduce #'+ vector1) (length vector1))) 
+0

由錯誤錯誤的道歉我的意思是0和1; 「太大」 – Francisco

+1

您正在遇到數值分析中精度失效的典型例子 - 增加不同比例的數字。取而代之,將每個數字/分開/添加 - 然後您將添加相同比例的數字。 – BadZen

回答

4

浮點數

你用單精度浮點數運算的精度。將所有隨機數加起來就得到一個單浮點數。你添加的數字越多,浮點數就越大。這最終會導致你的結果不夠精確。

1.0d0這樣的雙浮體比單浮體如1.0s0具有更高的精度。默認情況下,1.0被讀取爲單個浮點數。 (RANDOM 1.0d0)將計算雙浮點數。

(defun randvec (n) 
    (let ((v (make-array n))) 
    (dotimes (i n v) 
     (setf (aref v i) (random 1.0d0))))) ; create a double float random number 

(defun test (&optional (n 10)) 
    (setf *random-state* (make-random-state t)) 
    (let ((v (randvec n))) 
    (/ (reduce #'+ v) (length v)))) 

例子:

CL-USER 58 > (test (expt 10 8)) 
0.4999874882753848D0 

風格

Common Lisp中編程時,請使用Common Lisp的編程風格:

  • 不使用全局變量,如果不是必要。改寫本地變量的函數。
  • 如果您使用defparameter定義全局變量,請不要將其命名爲n,而是*n*
  • 格式並正確縮進您的代碼。應該使用編輯器幫助進行縮進。
  • 不要在自己的行上使用括號。

看我上面的例子。

+0

非常感謝。另外,感謝您對lisp編程風格的建議。 關於對自己的行使用括號的,我使用它,因爲 它給我的清晰度,也是我看到的口齒不清一些圖書使用了它 (羅賓·瓊斯克萊夫·梅納德·伊恩·斯圖爾特的Lisp程序設計的藝術, 爲例)。雖然有點老。 – Francisco

+0

@Francisco:不要使用懸掛括號。學習使用縮進代碼並顯示相應括號的編輯器。代碼將更加緊湊和可讀。無論如何,當你的眼睛和你的大腦之間有一定的距離時,你的眼睛和你的大腦將無法看到哪個括號是對齊的。編輯可以很容易地顯示它。 –