アプリ版:「スタンプのみでお礼する」機能のリリースについて

条件文において、配列の中身を変数で取り出すとエラーが起きます。
また、配列の中身を変数で取り出し、別の変数に移してから条件文で使ってもエラーが起きます。
また、エラーメッセージは条件文において0で割っているというものですが、そのようなことはありません。
以下コード内容
$a = 10000;
$b = 3;
$d = 1;
my @primenumbers;
$primenumbers[0] = 2;
while($a <= 11000){
while($b <= sqrt $a) {
$c = 0;
$flaga = 0;
while($c <= $b){
$f = $primenumbers[$c];
print $f;
if($b % $f == 0){
$flaga = 1;
$c = $b
}
$c = $c + 1;
}
if($flaga == 0){
$primenumbers[$d] = $b;
$d = $d + 1;
}
$b = $b + 1;
}
$e = 0;
$flagb = 0;
while($e <= $d){
$g = $primenumbers[$e];
if($a % $g == 0){
$flagb =1;
$e = $d;
}
$e = $e + 1;
}
if($flagb == 0){
print "\n";
print $a;
print "Prime!";
}
$a = $a + 1;
}

以下出力&エラーメッセージ
Illegal modulus zero at 100.pl line 13.
2

エラーの理由がわかる方がいたら原因を教えてくださると非常にありがたいです。

A 回答 (4件)

print $f;      ・・・・①


if($b % $f == 0){ ・・・・②
の個所ですが
①を
printf("\$f=<%s> \$c=<%s>\n",$f,$c);
にして、$fと$cの内容を表示します。
すると
$f=<2> $c=<0>
$f=<> $c=<1>
Illegal modulus zero at goo1a.pl line 13.
のようになります。
$cが1のとき、$fは空です。これは、数値としては0の扱いになります。
従って②の個所で $bを$fで割った余りが0かどうか判断しているので、ここでエラーになります。
(余りを求める演算子%で割り算が発生します)
    • good
    • 0
この回答へのお礼

おっしゃる通りでした。
原因はcの値を増やすタイミングを間違えていたことにあったようです。
現在、問題が解決し期待通りの挙動を示しています。
回答ありがとうございました。
ほかの方の回答も非常に参考になり、優劣つけがたいのですが、最も適切な回答を一番早く提示してくれたtatsu99さんにベストアンサーを差し上げたいと思います。

お礼日時:2019/10/04 17:40

1. Perlのリスト(配列)は、今ある長さの外を指定しても「未定義値」を返すだけで、エラーになったりしない。


 @x=(0,1) ; # 長さ2 なので、 $x[0],$x[1] だけが「範囲内」 ## 負の値で後から、というのもあるけど。
 $y = $x[5] ; # だけど、5とか指定してもエラーにはならないで、「未定義値」になる

2. Perlでの多くの演算は「数値」に変換して行われる。
 「未定義値」は 0 として扱われる。

3. % (余りを求める演算) は「割り算した余り」なので、 0 で割ってはいけない。


で、ざっと眺めたんですが、どういう考えでやろうとしているのか、よくわかりません。
ですから、どうするのかが正解かがよくわかりません。

・$a,$b, 等と1文字だけの変数がたくさんでてきますが、それぞれの役割がよくわかりません。
 もうちょっと名前を工夫しましょう。
 「配列の長さ」でないものを「配列の長さ」に使おうとしているように見受けられます。

・配列の全要素について処理を繰り返したいのなら、 foreach が便利です。
 また、配列の長さを調べる方法がありますし、
 配列に追加するのに push を使うと、自動で最後に加えてくれるので、
わざわざ別の変数を用意して管理する必要はありません。
    • good
    • 0
この回答へのお礼

学校の授業の一環でやっているのでforeach,pushというものは習っておりません。
教えてくれてありがとうございます。
変数名を工夫すれば分かりやすいプログラムが作れるのですね。
次からはそうしようと思います。
やりたいことは$aが動く整数の範囲の素数を求めようというものです。
コピーしたときにインデントが抜けてしまったようで読みにくくてすみません。
問題は一応解決しました。
最初から考え直してコメントを使って見やすくしてみました。
原因はcを増やすタイミングを間違えていたことだったようです。
そのせいで配列の要素の入っていない部分から取り出そうとしてしまい、perlの仕様上0が出力され、「0で割れないよ」というエラーがでたようです。
現在、目的通りの挙動は示しましたが改良点があるかもしれません。
また、aの範囲が狭い場合は、2以上aの平方根以下の整数で工夫してaを割っていった方が素数判定はより速くなり、コードも短くなるので、今回は挑戦という形で授業の範囲から逸脱して作ってみたものです。
これを改良したコードの前半部分だけを使えば、2から指定した範囲までの素数を列挙することが可能です。
今回作ったコードの方法では、せいぜい12桁程度の素数判定が限界です。
それに比べ、上記の方法であれば、16桁程度の素数を5秒足らずで判定することができます。
そういった意味でも試験的なコードであることは確かですが、これからプログラミングの世界に深く踏み込んでいく可能性のある中で、いい経験になったかと思います。
回答ありがとうございました。

お礼日時:2019/10/04 17:32

存在しない添え字で配列から undef を取り出し、


undef は数値 0 として評価されるため、
$b % $f が零除算しています。

存在しない添え字を使うこと自体がバグである気がしますが、
もしこれが仕様通りであるならば、以下のいずれかの対策が必要です
* 配列の全要素を事前に全て 0 以外の値で初期化する
* 配列ではなくハッシュを使い、取得時に添え字の存在確認をし、存在しないなら 0 以外の値で代用する
    • good
    • 0
この回答へのお礼

問題は解決しました。
原因はおっしゃる通りのものでした。
ご指摘ありがとうございます。
undef、ハッシュについて調べてみます。
回答ありがとうございました。

お礼日時:2019/10/04 17:34

私はPerlはど素人ですけど、それでもちょっと気になった点が。


コンパイルするとあちこち修正があった点はバージョンによるのかもですが・・・・

my @primenumbers;
$primenumbers[0] = 2;


while($c <= $b){
$f = $primenumbers[$c];
print $f;
if($b % $f == 0){
$flaga = 1;
$c = $b
}
$c = $c + 1;
}

この中で配列:$primenumbers[$c]って最初の要素数:0の時の値しか格納されてなく、$cを増やしていっても配列の中身は存在してないんじゃない?
$primenumbers[1] とかは。
Perlそのものの経験がないので全く何をしようとしているコードかはわかりませんけど、配列に追加代入もせず要素数だけ増やしてもって思えました。
けど、結局は対処方法はわかりませんけどね。(配列に値を追加していけば良いのかもですが、何を追加したいのかが????です。)
    • good
    • 0
この回答へのお礼

プログラミングの知識を生かして回答してくれたことに感謝しています。
めぐみん_さんのおっしゃることは大まかには正しく、解決の一助となりました。
インデントもなく、工夫、コメントも何もないプログラムから問題を読み取ろうとしてくれてありがとうございます。
一応、
$primenumbers[$d] = $b;
の部分で、配列に数値を追加するポイントはありましたが、$cの値を追加するタイミングを間違えており、perlの仕様上存在しない要素を取り出そうとすると0が出力されるため、結果として「0で割ることはできない」という内容のエラーがでたようです。
prime numberというのは素数という意味で、aの動く範囲の素数を判定するプログラムを作ろうとしていました。
範囲指定の場合は、もっと効率のいい方法があるのですが、素数の定義に則って小さいものから順に素数を列挙するならばこのプログラムの前半部分で、配列に素数を要素として追加すると同時に、その素数を出力すれば、最も速く素数を列挙することができるのではないかと考えて作った次第であります。
素早い回答ありがとうございました。

お礼日時:2019/10/04 17:54

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!