48628


Rubyを最近使い始めまして，勉強中の身です．  
熱雑音生成のプログラムを書いているのですが，UnitTestをしたところ，乱数で降ってるはずなのに値が更新されず，同一のままになってしまいます．  
デバッグをしていますが，原因がわかりません．  
ご教授お願い致します．  
詳細は以下のコードになります．

長文失礼しました.

* * *
[code]

    def BoxMullerNoise
        rnd = Random.new
        return BoxMuller.new_create(rnd)
    end
    
    class BoxMuller
       attr_accessor :_urng
       attr_accessor :_x
       attr_accessor :_y
       attr_accessor :_saveIns
    
       def self.new_create(urng)
           obj = self.new
           obj._urng = urng
           obj._x = urng.rand(1.0)
           obj._y = urng.rand(1.0)
    
           obj._saveInst = obj  # インスタンスの保存
    
           return obj
       end
    
       def value    # この中身の_x, _yが，popfrontをUnitTestでしているのに更新されない
           p _x
           p _y
           return Math.sqrt((-2.0) * Math.log(_x)) * Complex(Math.cos(2*Math::PI*_y), Math.sin(2*Math::PI*_y))
       end
    
       @@empty = false
    
       def popfront
           p "BoxMullerクラス内です"
           _x = _urng.rand(1.0)
           _y = _urng.rand(1.0)
       end
    
       def seed(seed)
           srand(seed)
       end
    
       def save
           _keepInst = _saveInst
    
           _keepInst._urng = _urng
    
           return _keepInst
       end
    end
    
    
    def noisePower(bandwidth, tempK)
        return bandwidth * tempK * BoltzmannConst
    end
    
    
    class ThermalNoise
       attr_accessor :_rnd
       attr_accessor :_gain
       attr_accessor :_saveInst
    
       def self.new_create(sampFreq, tempK, seed = Random.new.seed)
           obj = self.new
           obj._rnd = BoxMullerNoise()
           obj._gain = Math.sqrt(noisePower(sampFreq, tempK) / 2)
           obj._rnd.seed(seed)
    
           obj._saveInst = obj  # インスタンスの保存
    
           return obj
       end
    
    
       def value
           return _rnd.value * _gain
       end
    
       @@empty = false
    
       def popfront
           p "ThermalNoiseクラス内です"
           _rnd.popfront
       end
    
       def save
           _keepInst = _saveInst
    
           _keepInst._rnd = _saveInst._rnd.save
    
           p _keepInst
           return _keepInst
       end
    end
    
    
    # UnitTest
    class UnitTest < Test::Unit::TestCase
       def test_ThermalNoise
           buf = Array.new(64*1024)
           rndSeed = 114514
           thermalNoise = ThermalNoise.new_create((20*10**6)*4, 300, rndSeed + 123321)
    
           (0 ... 4).each{ |i|
               thermalNoise.popfront # BoxMullerクラスの_x, _yを変えているはずなのに
               thermalNoise.value    # ここで同じ値が表示されてしまう
           }
       end
    end
    
[/code]


CC BY-SA 4.0
2018-09-20T09:21:01.770
48592
2018-09-21T15:29:28.150
30173
question
ruby
乱数で変化させているはずが値が同一となってしまう

[code]

       def popfront
           p "BoxMullerクラス内です"
           _x = _urng.rand(1.0)
           _y = _urng.rand(1.0)
       end
    
[/code]

を

[code]

       def popfront
           p "BoxMullerクラス内です"
           self._x = _urng.rand(1.0)
           self._y = _urng.rand(1.0)
       end
    
[/code]

のようにしてください。

Rubyでは`a =
b`と言う表現は常にローカル変数`a`へ`b`を代入するとみなされます。ローカル変数`a`が未定義であれば、同時にローカル変数`a`が定義されることになります。`_x
=
_urng.rand(1.0)`という表現もローカル変数`_x`の定義と代入になり、インタンスメソッドの呼び出しにはなりません。インスタンスメソッドとして扱いたい場合は`self._x
= _urng.rand(1.0)`というようにレシーバーを明記する必要があります。

さて、全体的に言えることはRubyっぽくないことです。何か別の言語で作られた物を無理矢理移植したように思えます。たぶん、どこかで無理が出て、破綻します。

  * 初期化には`initialize`を使いましょう。特殊なことをしない限り、クラスメソッドを新しい`new`もどきを作る必要はありません。
  * クラス内の処理はインスタンス変数を使いましょう。`attre_accessor`等は外部にインスタンス変数を見せるための手段です。外部に見せる必要が無いのであれば、使うべきではありません。
  * Rubyのクラスは構造体ではありません。C++/D/Javaのように構造体の拡張と考えてはいけません。
  * 郷には入れば郷に従えです。Rubyでは2スペースのインデント、ローカル変数やメソッドはスネークケースが推奨されています。その他は[Ruby Style Guide](https://github.com/rubocop-hq/ruby-style-guide)を参考にしてください。


CC BY-SA 4.0
2018-09-21T15:29:28.150
48628
2018-09-21T15:29:28.150
7347
48592
answer