Cで作った二項分布の計算プログラムをPerlで書き直しています。
ユーザ関数の使い方がよくわかりません。
どこが間違っているか教えていただけませんでしょうか?
余談ですが、ソースが左揃えになるのを防ぎたいのですが…。
#!/usr/bin/perl
$p = 0.5, $s = 0, $t = 0, $combination = 0, $binarydistribution = 0;
printf("n=");
$n = <STDIN>;
for ($r = 0; $r <= $n; $r++){
$combination = &factorial($n) / (&factorial($r) * &factorial($n - $r));
$s = 1;
for ($i = 1; $i <= $r; $i++){
$s = $s * $p;
}
$t = 1;
for ($i = 1; $i <= $n - $r; $i++){
$t *= (1 - $p);
}
$binarydistribution = $combination * $s * $t;
printf("%.15f\n", $binarydistribution);
}
sub factorial{
$j = @_;
$x = 1;
for ($i = 1; $i <= $j; $i++){
$x *= $i;
}
return $x;
}
No.2ベストアンサー
- 回答日時:
Perl の場合、サブルーチンの引数の受け渡しを、配列 @_ を使用して行います。
$j = @_;
の箇所を
( $j ) = @_;
括弧でくくってあげれば良いでしょう。
# あと、できれば my をつけたほうが良いです。
#
# my ( $j ) = @_;
#
# こうすることで、変数をサブルーチン内に局所化できます。
# いわゆるローカル変数というやつですね。
そうでなければ、No1 BLUEPIXYさんがご回答されているように
my $j = shift;
とします。
これは、以下と同様の意味で、引数リスト@_ から先頭要素を取り出すことを意味します。
$j = shift( @_ );
どうしてこのような面倒な話になるのかと言うと、Perl が、状況によって勝手にコンテキストを変換してしまうためです。
簡単に言えば、配列をスカラー変数に代入すると、その要素数が取り出せるんです。
この場合も
$j = @_;
としてしまった場合、$j (スカラー変数) には @_ (配列) の要素数 (この場合は 1 ですよね?) が代入されることになります。
括弧でスカラー変数をくくれば、それは配列として扱われます。
( $j ) = @_;
とすれば、( $j ) は要素 $j をもつ配列を意味しますので、この式で配列代入が行われることになり、$j には $_[0] が代入されます。
ちなみに、2つ以上の引数があった場合にも同様にします。
引数を2個とるサブルーチンの場合は、以下のようにします。
--------------------------------------------------------
&subrtn1( $h, $p );
……
sub subrtn1 {
# 引数の受け渡し
my( $hoge, $piyo ) = @_;
}
--------------------------------------------------------
$hoge には $_[0]、$piyo には $_[1] がそれぞれ代入されることになります。
なお、shift を使う場合は、以下のようにします。
--------------------------------------------------------
my $hoge = shift;
my $piyo = shift;
--------------------------------------------------------
こんな感じでいかがでしょうか。
解決した上にさらに勉強になりました。
そうなんです。コンテキストを変換してしまうので、$jに要素数が入っているのでおかしいと思っていたんです。
()をつければ0番目の要素が入るんですね。これはとても役立つ知識だと思います。
shiftで先頭を切ってまた()で代入することによって、順番に要素を取り出すこともできるのが便利です。
my( $hoge, $piyo ) = @_;とすることで、一度に複数の要素を別々の変数に入れることもできるんですね。
Perlはある動作をさせるのに表現方法が複数あるので覚えるのが大変です。
どれか一つ得意な構文のパターンを身につけると良さそうですね。
ありがとうございました。
No.3
- 回答日時:
>なぜそれで直ったのか理由が知りたいです。
ほとんど#2の方が丁寧に説明されている通りです。
サブルーチンへの引数は
@_ という配列に自動的に割り当てられます。
$j = @_;
のようにスカラー変数に配列を代入するという式は配列のサイズを代入することになります。
なので、
$j は いつも1になるというのが直接的な動作不良の原因です。
shift は、配列から先頭を切り出す関数で
切り出された内容は配列からなくなり以降の要素が順繰りに上がるような感じになります、それでシフトというのです。
shift は引数としての配列が省略されたとき @_ が引数に指定されたとして処理します。
shiftを使わずに
$j=@_[0];
としてもいいですね。
後、蛇足ですが、
sub factorial($){…
の様に指定すると引数の数が(スカラーで)1つであることをコンパイル時にチェックしてくれます。
my 演算子を使うと変数を局所変数にしてくれます。
Perlでは、Cでのようにサブルーチンでの変数を
自動的には局所変数にはしてくれません。
例えば $i など、ループの変数としてよく使いますが、
そういうメインのループから関数を呼び出した時など致命的になりがちです。
(そういえばsubで $i 使ってますね my $i; しておきましょう)
No.1
- 回答日時:
とりあえず
my $j = shift;
my $x = 1;
としてみたらどうでしょうか
この回答への補足
質問者です。
サブルーチンの中をおっしゃるとおりに変えてみたらうまくいきました。
なぜそれで直ったのか理由が知りたいです。
私の持っている本にはユーザ関数について書いてないので、Webを頼りに組んでみたのですが、参照したサイトはmyやshiftは使っていませんでした。
@_がどのような役割をしているのかもよくわかりません。
myやshiftがあるのとないのでは何が違うのでしょうか?
参考にしたサイト
http://www.kent-web.com/perl/chap8.html
http://flex.ee.uec.ac.jp/texi/perl/perl_53.html
ありがとうございます。解決しました。
$jにつけるmyは今回は特に必要ありませんでした。
実務におけるシステム開発では、変数のスコープを必要な範囲で狭くしたほうがよいようですので、参考になりました。
shiftというのは今回初めて知りました。
勉強になりました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# C言語 プログラミング 4 2022/05/22 11:53
- C言語・C++・C# C言語 3 2022/10/04 15:07
- C言語・C++・C# LU分解法のピボッティングについて(C言語/gcc-9) 3 2022/07/11 23:10
- C言語・C++・C# C 言語の Gauss Jordan 法について 2 2022/12/28 11:16
- C言語・C++・C# LU分解法のピボット選択機能実装について(C言語・gcc-9) 1 2022/07/22 15:20
- C言語・C++・C# C言語 3 2022/11/09 13:27
- CGI 古ーくからフリーのtree.cgi掲示板を利用させてもらって来ましたが、最新でなにか復活できないか? 2 2023/04/07 10:43
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Can't use string ("0") as an ...
-
画面を強制的に再描画させる方法
-
VBAで3秒だけ時間を止めたい
-
DoEventsが必要な理由について
-
VBAのautofilter、criteriaの配...
-
GIFアニメをループさせたくない
-
vba
-
アクティブセルから、A列最終行...
-
データベースから取得したデー...
-
VBA Dir関数でファイルをループ...
-
VBのReturnの使い方
-
流れ図(フローチャート)が分か...
-
二次元配列のインデックスについて
-
DOSコマンドのループ内のTIMEコ...
-
Application.OnTime の使い方
-
ループフリー
-
二次元配列における要素数のは...
-
Strawberry Perl for Windows ...
-
VBA for文が止まらない
-
vb.netからエクセル関数書き込み
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Can't use string ("0") as an ...
-
PerlでCSV形式のファイルの一部...
-
perlの引数が不安定になります。
-
perlの比較、ループの使い方に...
-
レキシカル変数について
-
画面を強制的に再描画させる方法
-
VBAでの一時停止と再開の方法
-
データベースでユーザーのパス...
-
VBのReturnの使い方
-
ループ7回目の悪役令嬢は、元敵...
-
UWSCの終了の仕方
-
Escキーを押すと、中断する時と...
-
エクセルの当番表を作っていま...
-
GIFアニメをループさせたくない
-
VBAで3秒だけ時間を止めたい
-
どなたかこのプログラミングを...
-
VBA for i=1 to lastrow
-
文字列を変数名として扱う方法
-
ハッシュ検索はなぜ速い
-
DOSコマンドのループ内のTIMEコ...
おすすめ情報