やりたいこと
1を何かで割ったときの循環節の長さを調べてます。
(ex)1÷7=0.14285714285714285...で、長さが六の142857が繰り返されるので循環節は6です。
また、便宜上割り切れる場合と循環小数にならない場合は循環節は0としてます。
pythonで作りましたが、わる数を増やしていった時に速度が足らず、対応出来なかったので高速で動くc言語で書き換えようとしました
pythonでは問題なく動作しましたがCでおかしな挙動を見せました。アルゴリズムはほぼ同じなので自分の知識不足により変な結果になっているものと思われます。
pythonも大概ですが、Cはかなりの初心者なのでお手柔らかにお願いします
##入出力
入力はinput()やscanf()などを介すことなくend_numという変数に直接入力する形をとってます
出力はpythonでは配列、cでは配列をそのまま出力できないのでpythonの配列っぽく出力させてます
わかりづらいことは実際のコードをみていただければわかると思います
##pythonでのコード
python
1import numpy as np 2count = 0 # 今何回割り算したかを記録します 3end_num = 100 # 入力です。わる数の上限です。自分の環境では100000から速度不足が深刻で計算できませんでした。 4num_list = list(np.zeros(end_num, dtype=int)) # 余りを記録するリスト。同じ余りが出てきたときが循環が一区切りついたときなので(実際に筆算をするとわかりやすいです) 5output_list = list(np.zeros(end_num+1, dtype=int)) # 出力用のリストです。 6 7 8for i in range(2, end_num + 1): 9 if i % 2 == 0 or i % 5 == 0: 10 output_list[i] = 0 # 2や5の倍数でわると必ず循環しないので0を出力のリストに入れます 11 else: 12 left = 1 % i # 余りです 13 while True: # 同じ余りが出るまでループを続けます 14 if left in num_list: 15 output_list[i] = count - num_list.index(left) 16 # 割り算した回数-今出た余りは過去に何回目で出たかで循環節が求まります。実際に筆算するとわかりやすいです 17 break 18 else: 19 num_list[count] = left 20 left *= 10 21 left %= i # でた余りを十倍してもとの数で再度割る。実際の筆算の操作と同じです 22 count += 1 23 24 count = 0 # 循環節が求まったので次の数に進むために再度初期化しておきます 25 num_list = list(np.zeros(end_num, dtype=int)) 26 27print(output_list)
出力
[0, 0, 0, 1, 0, 0, 0, 6, 0, 1, 0, 2, 0, 6, 0, 0, 0, 16, 0, 18, 0, 6, 0, 22, 0, 0, 0, 3, 0, 28, 0, 15, 0, 2, 0, 0, 0, 3, 0, 6, 0, 5, 0, 21, 0, 0, 0, 46, 0, 42, 0, 16, 0, 13, 0, 0, 0, 18, 0, 58, 0, 60, 0, 6, 0, 0, 0, 33, 0, 22, 0, 35, 0, 8, 0, 0, 0, 6, 0, 13, 0, 9, 0, 41, 0, 0, 0, 28, 0, 44, 0, 6, 0, 15, 0, 0, 0, 96, 0, 2, 0]
いくつかの数を調べてみた所実際の計算結果と一致したのでおそらく欠陥はないです。
##Cでのコード
C
1#include <stdio.h> 2 3int existinArray(int array[], int size, int element); 4/* 5 要素が存在するかを判定 6 引数: 7 int array[] 調べたい配列 8 int size 調べたい配列の要素数 9 int element 要素 10戻り値: 11 int 0か1。実質Bool型 12*/ 13int indexArray(int array[], int size, int element); 14/* 15 要素がどこに存在するかを判定 16 引数: 17 int array[] 調べたい配列 18 int size 調べたい配列の要素数 19 int element 要素 20戻り値: 21 int 要素のインデックスを表示 22*/ 23 24int main(void){ 25 size_t count = 0; //今何回割り算したかを記録します 26 int end_num = 100; //入力です。割る数の上限です。 27 int numArray[end_num]; //余りを記録する配列。同じ余りが出てきたときが循環が一区切りついたときなので(実際に筆算をするとわかりやすいです) 28 for (int i = 0; i < end_num; i++){ 29 numArray[i] = 0; 30 } 31 int outputArray[end_num+1]; //出力用の配列です。 32 for (int i = 0; i < end_num+1; i++){ 33 outputArray[i] = 0; 34 } 35 int left; //余りです 36 37 for (int i = 2; i < end_num + 1; i++){ 38 if (i % 2 == 0 || i % 5 == 0){ 39 outputArray[i] = 0; // 2や5の倍数でわると必ず循環しないので0を出力の配列に入れます 40 }else{ 41 left = 1 % i; // 余りです 42 while (1){ // 同じ余りが出るまでループを続けます 43 if (existinArray(numArray, end_num, left) == 1){ //余りが過去にでた余りと一致するかを判定 44 outputArray[i] = count - indexArray(numArray, end_num+1, left); 45 // 割り算した回数-今出た余りは過去に何回目で出たかで循環節が求まります。実際に筆算するとわかりやすいです 46 break; 47 }else{ 48 numArray[count] = left; 49 left *= 10; 50 left %= i;// でた余りを十倍してもとの数で再度割る。実際の筆算の操作と同じです 51 count ++; 52 } 53 } 54 count = 0; 55 } 56 } 57 58 // 出力部 59 printf("["); 60 for (int i = 0; i < (sizeof(outputArray)/sizeof(outputArray[0])); i++){ 61 printf("%d,", outputArray[i]); 62 } 63 printf("]"); 64} 65 66int existinArray(int array[], int size, int element){ 67 size_t output = 0; 68 for (int i = 0; i < size; i++){ 69 if (array[i] == element){ 70 output = 1; 71 break; 72 } 73 } 74 return output; 75} 76 77int indexArray(int array[], int size, int element){ 78 size_t output = 0; 79 for (int i = 0; i < size; i++){ 80 if (array[i] == element){ 81 break; 82 }else{ 83 output ++; 84 } 85 } 86 return output; 87} 88
出力
[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,]
※最後のコンマは特に気にしなくて大丈夫です。
Ubuntu 20.04.1 LTS x86_64のターミナルでgccコマンド打ってコンパイルしてます。
回答2件
あなたの回答
tips
プレビュー