2016-11-18 12 views
0

以下のコードは間違った答えです。これは、0と1の間の多くの乱数を持つ配列の平均である約0.5を与えるはずです。問題は、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つの浮動小数点数が得られます。追加する数値が多いほど、浮動小数点数は大きくなります。結果的に精度が足りなくなります。

1.0d0のようなダブルフロートは、1.0s0のようなシングルフロートよりも高い精度を持っています。デフォルトでは、1.0はシングルフロートとして読み込まれます。 (RANDOM 1.0d0)はdouble floatを計算します。

(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でプログラミングする際の一般的なLispのプログラミングスタイルを使用してください:

  • 、グローバル変数をそうでない場合は使用しないでください必要。代わりにローカル変数で関数を記述してください。
  • defparameterでグローバル変数を定義する場合は、nではなく、*n*という名前を付けます。
  • 形式でコードを正しくインデントしてください。インデントはエディタのヘルプで行う必要があります。
  • 括弧を使用しないでください。

上記の私の例を参照してください。

+0

ありがとうございました。また、lispプログラミングスタイルのアドバイスをありがとう。 括弧の使用については、 私に明快さを与えてくれるので、私はそれを使用しています。 (Robin JonesのClive Maynard Ian Stewartのプログラミングの芸術、 例)。少し古いですが。 – Francisco

+0

@Francisco:括弧を使用しないでください。コードをインデントし、対応するかっこを表示するエディタを使用する方法を学びます。コードははるかにコンパクトで読みやすいでしょう。あなたの目とあなたの脳は、それらの間にある程度の距離があっても、どの括弧が並んでいるかを見ることができません。エディタで簡単に表示できます。 –

関連する問題