前回の投稿の続き。
やりたいこと
・照明の12V電源を朝7時にON、夜19時にOFFする
・温室内の4点の温度をAmbient.ioに毎分送信する
やり方
<Arduino Nano>
・LM61 * 4点のAnalog INを温度[℃]に変換し、1秒ごとにシリアルでPiに送る
・シリアルを監視し、「t or T」が来たらGPIOをON、「f or F」が来たらGPIOをOFFする
<Raspberry Pi>
・各点の温度を60秒間貯めて平均値を計算し、Ambientに送信する
・1分に1回時刻を見て、tもしくはfをシリアルで送信する
上記のような機能分担とした。
それぞれのソースコードは前回の投稿の後半を参照。近いうちに解説を書くかも。
H/Wは非常にシンプルで、次のような構成とした。
Fritzingだと綺麗に書けて気持ちよい!
青線部分は、実際にはmicroUSB-B otg + miniUSBケーブルで接続する。
実物の写真はこんな感じ。
時刻に応じて照明を消す機能はD3に割り当ててあるけど、H/Wの実装はまだ。
今はLEDでテスト中。
ブレッドボードの下側部分がLM61への配線。
D3部分は、後ほどLEDの代わりに照明への12VをON/OFFするためリレー回路を追加予定。
2020年2月27日木曜日
2020年2月25日火曜日
温室の温度をAmbientに投稿しつつ、時刻でLED照明を制御する(Ras Pi Zero⇔Arduino連動)
以前に温室の温度制御を追加したが、その温度データをリアルタイムでモニタリングしたくなった。
また、温度だけでなく日照不足も補うため、LED照明を追加した。
24時間点灯は植物の負担になるらしいので朝夕に手動でON/OFFしているが、
このON/OFFを自動化したい。(ときどき付け忘れるので…)
(↑こんな感じ 見た目はめちゃくちゃ怪しいけど、健全な草花なのでご安心を)
温度モニタリングと時間での照明ON/OFFを実現するため、
Raspberry Pi Zero WとArduino Nanoを連携させてシステムを構築した。
仕様は以下2つ。
・照明の12V電源を朝7時にON、夜19時にOFFする
・温室内の4点の温度をAmbient.ioに毎分送信する
先にAmbientの表示結果を載せる。
こんな風に4点がグラフ化できる。何か月分もさかのぼって見ることもできる優れもの。
安いArduino Nano互換機を大量に持っているので2ボード構成を選択した。
わざわざ2つを繋ぐのは少しダサいけど、いくつかメリットもある。
ArduinoはAnalog INで直接読めるからLM35やLM61のような安い温度計測ICを使えるが、
Piから直接読めるセンサはお値段が高め。
ESP32はADCの誤差が大きい。また、ESP32自体がPi Zero Wより高い。
対して、Pi+Arduinoなら、Internet部分をPythonで簡単に書けるうえに安く作れる。
その代わり、PiとArduinoのSerial通信を書く必要がある。
簡単に表にまとめるとこんな感じ。
(Nanoが互換品前提なので少しずるい気もする)
中身の説明とハードウェアは後日掲載します。
・Raspberry Pi
・Arduino
以上。続きは後編へ。
また、温度だけでなく日照不足も補うため、LED照明を追加した。
24時間点灯は植物の負担になるらしいので朝夕に手動でON/OFFしているが、
このON/OFFを自動化したい。(ときどき付け忘れるので…)
(↑こんな感じ 見た目はめちゃくちゃ怪しいけど、健全な草花なのでご安心を)
温度モニタリングと時間での照明ON/OFFを実現するため、
Raspberry Pi Zero WとArduino Nanoを連携させてシステムを構築した。
仕様は以下2つ。
・照明の12V電源を朝7時にON、夜19時にOFFする
・温室内の4点の温度をAmbient.ioに毎分送信する
先にAmbientの表示結果を載せる。
こんな風に4点がグラフ化できる。何か月分もさかのぼって見ることもできる優れもの。
環境検討
ESP32とかPi Zeroなら単独でもできないこともないが、安いArduino Nano互換機を大量に持っているので2ボード構成を選択した。
わざわざ2つを繋ぐのは少しダサいけど、いくつかメリットもある。
ArduinoはAnalog INで直接読めるからLM35やLM61のような安い温度計測ICを使えるが、
Piから直接読めるセンサはお値段が高め。
ESP32はADCの誤差が大きい。また、ESP32自体がPi Zero Wより高い。
対して、Pi+Arduinoなら、Internet部分をPythonで簡単に書けるうえに安く作れる。
その代わり、PiとArduinoのSerial通信を書く必要がある。
簡単に表にまとめるとこんな感じ。
Arduino + Pi | Piのみ | ESP32 | |
主要部品 | Arduino Nano Pi Zero W LM61 *4 | Pi Zero W DS18B20 *4 | ESP32 LM61 * 4 |
概算費用 | 400円 1,320円 60円*4 (1,960円) | 1,320円 320円*4 (2,540円) | 2,200円 60円*4 (2,240円) |
開発言語 | C/C++ Python ※ボード間通信有 | Python | C/C++ |
ソース
本日はソースの掲示のみ。中身の説明とハードウェアは後日掲載します。
・Raspberry Pi
#! /usr/bin/python3 import serial as sl import ambient from datetime import datetime as dt am = ambient.Ambient(<AmbientのID>, "<AmbientのKey>") tim = dt.now() count = 0 acc = [0.0, 0.0, 0.0, 0.0] s = sl.Serial("/dev/ttyUSB0", 9600) while True: try: txt = s.readline() ary = txt.decode().strip().split(" ") if len(ary) != 11: continue else: t = [float(x) for x in [ary[1], ary[4], ary[7], ary[10]]] count += 1 for idx in range(4): acc[idx] += t[idx] if (dt.now() - tim).total_seconds() >= 60: t = [x / count for x in acc] count = 0 acc = [0.0, 0.0, 0.0, 0.0] tim = dt.now() tmp = {'d1':t[0], 'd2':t[1], 'd3':t[2], 'd4':t[3]} am.send(tmp) ## Ambientへ送信 # DC12VのON/OFF if 7 <= tim.hour and tim.hour <= 19: s.write(b"t") else: s.write(b"f") except Exception as e: print(e) s.close()
・Arduino
void sendTemp(); bool serialFlag = false; unsigned long tim = 0; const unsigned char PWR = 3; // D3 void setup(){ Serial.begin(9600); delay(20); pinMode(LED_BUILTIN, OUTPUT); pinMode(PWR, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); digitalWrite(PWR, HIGH); } void loop(){ if(millis() - tim > 1000){ sendTemp(); tim = millis(); } } void serialEvent(){ while(Serial.available()){ char c = Serial.read(); switch(c){ case 'T': case 't': // AC12V ON digitalWrite(LED_BUILTIN, HIGH); digitalWrite(PWR, HIGH); break; case 'F': case 'f': // AC12V OFF digitalWrite(LED_BUILTIN, LOW); digitalWrite(PWR, LOW); break; default: break; } } } void sendTemp(){ float t[4]; t[0] = analogRead(A7) * 500.0/1024 - 60; t[1] = analogRead(A6) * 500.0/1024 - 60; t[2] = analogRead(A5) * 500.0/1024 - 60; t[3] = analogRead(A4) * 500.0/1024 - 60; Serial.write("S0: "); Serial.print(t[0]); Serial.write(" / S1: "); Serial.print(t[1]); Serial.write(" / S2: "); Serial.print(t[2]); Serial.write(" / S3: "); Serial.println(t[3]); }
以上。続きは後編へ。
2020年2月16日日曜日
美咲フォント(misaki font)をPythonで扱う<実装>
直前の記事で美咲フォントのpng画像の扱い方を検討したが、
今度はPythonで実装を行う。
美咲フォントの詳細は直前の記事か、作成者様のサイトを参照してください。
2Byte文字1文字を入力して、美咲フォントの画像から必要な部分を切り出す。
画像を扱うのでOpenCVでやってみる。
ここで、
「松」の画像部分を切り出して表示できる。
(8x8 pixelだからタイトルバーに比べて松の字は豆粒くらい・・・。)
簡単にコードの動作は以下の通り。
まず文字をShift-JISに変換し、s[0]=1Byte目 で s[1]=2Byte目に格納する。
そこからpng画像内の文字の位置を計算する。
(x, y)はpngファイル内の各文字の場所を指す。0始まりで、xが列、yが行。
文字コードからx,yを求める部分は、前回検討した内容が重要になる。
図の分断された4つの領域からpngの連続空間にマップするため、
x,yそれぞれに1つずつ条件分岐が必要になる。
加えて、列数を半分にする条件が1つ入る。
ここが上位1Byte:0x81~0x9F、 0xE0~0xEFの条件。
前半部分は、0始まりにするため0x81を引く。
後半部分は、0xE0を引いたうえで、前半部分の行数を足している。
最後に2倍にしているのは、列が半分になる=行が2倍になる部分を反映している。
奇数行の部分は後で。
0x9F未満の部分は条件そのままで、その先は次の行になる部分のため、
0x41ではなく0x9Fを引いて0列目からとし、行数も1加算して奇数行にする。
文字を抜き出す部分は以上。
これで、8x8のndarrayを抜き出せる。
モノクロビットマップなので、全要素は0 or 255になっている。
両方とも、実行効率改善や文字数を減らす余地がありそう。
こんな感じで遊べる。
今度はPythonで実装を行う。
美咲フォントの詳細は直前の記事か、作成者様のサイトを参照してください。
2Byte文字1文字を入力して、美咲フォントの画像から必要な部分を切り出す。
画像を扱うのでOpenCVでやってみる。
import cv2 misaki_png_path = "[path]/misaki_mincho.png" misaki_img = cv2.imread(misaki_png_path, 0) def imshow(im): cv2.imshow("image", im) cv2.waitKey(0) cv2.destroyAllWindows() def letter2glyph(chara): s = chara.encode("Shift-JIS") if s[0] < 0xA0: y = (s[0] - 0x81) * 2 else: y = (s[0] - 0xE0 + (0x9F - 0x81 + 1)) * 2 if s[1] < 0x7f: x = s[1] - 0x40 elif s[1] < 0x9f: x = s[1] - 0x41 else: x = s[1] - 0x9f y += 1 return misaki_img[y*8:y*8+8, x*8:x*8+8]
ここで、
imshow(letter2glyph("松"))と書くと、
「松」の画像部分を切り出して表示できる。
(8x8 pixelだからタイトルバーに比べて松の字は豆粒くらい・・・。)
簡単にコードの動作は以下の通り。
まず文字をShift-JISに変換し、s[0]=1Byte目 で s[1]=2Byte目に格納する。
そこからpng画像内の文字の位置を計算する。
(x, y)はpngファイル内の各文字の場所を指す。0始まりで、xが列、yが行。
文字コードからx,yを求める部分は、前回検討した内容が重要になる。
図の分断された4つの領域からpngの連続空間にマップするため、
x,yそれぞれに1つずつ条件分岐が必要になる。
加えて、列数を半分にする条件が1つ入る。
ここが上位1Byte:0x81~0x9F、 0xE0~0xEFの条件。
前半部分は、0始まりにするため0x81を引く。
後半部分は、0xE0を引いたうえで、前半部分の行数を足している。
最後に2倍にしているのは、列が半分になる=行が2倍になる部分を反映している。
奇数行の部分は後で。
if s[0] < 0xA0: y = (s[0] - 0x81) * 2 else: y = (s[0] - 0xE0 + (0x9F - 0x81 + 1)) * 2こちらは下位1Byte:0x40~0x7E、 0x80~0xFCの条件。
0x9F未満の部分は条件そのままで、その先は次の行になる部分のため、
0x41ではなく0x9Fを引いて0列目からとし、行数も1加算して奇数行にする。
if s[1] < 0x7F: x = s[1] - 0x40 elif s[1] < 0x9F: x = s[1] - 0x41 else: x = s[1] - 0x9F y += 1
文字を抜き出す部分は以上。
これで、8x8のndarrayを抜き出せる。
モノクロビットマップなので、全要素は0 or 255になっている。
おまけ
char[8]への変換と、「■」と「 」での表示。def mat2char8(mat): m = (1 - mat / 255) * 2 ** np.arange(7, -1, -1) return np.add.reduce(m, axis=1).astype(np.uint8)
def mat2Dprint(mat): print("\n".join(["".join(["■" if y==0 else " " for y in x]) for x in mat]))
両方とも、実行効率改善や文字数を減らす余地がありそう。
こんな感じで遊べる。
txt = "松―ログ" matList = [letter2glyph(c) for c in txt] mats = np.concatenate(matList, axis=1) mat2Dprint(mats) charList = np.array([mat2char8(m) for m in matList]) print(charList)表示結果↓
■ ■ ■ ■ ■ ■■ ■ ■ ■■ ■■■ ■■■■ ■■ ■ ■■■ ■ ■ ■ ■■ ■ ■■■■■■■■ ■ ■ ■■ ■ ■■ ■ ■ ■ ■ ■ ■ ■ ■■■■■■ ■ ■■■■ ■ ■ ■■ [[ 84 212 98 200 200 84 122 0] # 松 [ 0 0 0 255 0 0 0 0] # - [ 0 206 114 68 68 126 64 0] # ロ [ 20 30 18 98 4 8 48 0]] # グchar[8]の結果は全角ハイフンがわかりやすい。
「グ」も、下4桁が4→8→16+32→0となっていて直感的に計算できる。
次回は、この結果をマトリクスLEDに表示して遊んでみる予定。
新幹線のインジケータを作るってわけです。
ラベル:
8bit,
misaki font,
OpenCV,
Python,
美咲フォント
美咲フォント(misaki font)をPythonで扱う<事前検討>
(実装だけが必要の場合、こちらのページへGo!)
8x8ドットの日本語ビットマップフォント、美咲フォントをPythonで取り扱ってみる。
JIS第一、第二水準をサポートで、ゴシック/明朝のTTF形式とPNG形式がある。
8x8なら、char[8]で格納でき、ダイナミック制御でセレクタを3bitにすることもでき、
データや信号線の取り回しも非常にやりやすい。
こんな素晴らしいものがフリーで公開されているとは!
(公開元のウェブサイト)
TTF形式も公開されているのでfonttoolsを使えば汎用的に扱えるが、
今回使うのは8x8だけなのでコンパクトなPNG形式を対象にした。
misaki_mincho.png ・・・ 54kB
misaki_mincho.ttf ・・・ 1,092kB
約20倍の差がある
このため、png画像から必要な部分を抜き出すことにする。
美咲フォントのpng画像はこんな感じの並び。
この並びはShift-JISの2Byte文字部分のよう。
(参考:文字コード表 シフトJIS(Shift_JIS)より)
上位1Byte:0x81~0x9F、 0xE0~0xEF
下位1Byte:0x40~0x7E、 0x80~0xFC
字面だけではイメージしづらいので、0xFF×0xFFのドットマトリクスで示す。
何故隙間だらけかというと、ASCIIや他のコードと識別しやすくするためらしい。
特に上位1ByteがASCIIの0x20(半角スペース)や0x41(A), 0x61(a)と同じだと、
日本語なのかASCIIなのか1Byte目だけでは判別できなくなってしまうからだ。
これに対し、PNG画像の並びでいくつか注意が必要な部分がある。
(※画像はhttp://charset.7jp.net/様より一部借用)
実際の文字コードは0x8140からスタートする。
それに対し、png画像は最初の8x8が対応するので、このオフセットを考慮しないといけない。
図の通り、Shift-JISの中にはドデカい空白部分がある。
対して、美咲フォントのpng画像は空白部分を詰めている。
2つの行頭を見比べると、pngのほうは「ぁァАА・・・亜院押」なのに対し、
Shift-JISの表は「ァА・・・院魁」となっている。
これは、pngのほうが区/点を基準とした表示なのに対し、
Shift-JISの表は16進数基準の表示になっているためである。
つまり、図で示すとおり元々の1行がpng画像では2行分になっている。
これら①②③を考慮すれば、あとは文字コード変換と簡単な画像処理でうまく扱えるはず。
続きは次回。
8x8ドットの日本語ビットマップフォント、美咲フォントをPythonで取り扱ってみる。
JIS第一、第二水準をサポートで、ゴシック/明朝のTTF形式とPNG形式がある。
8x8なら、char[8]で格納でき、ダイナミック制御でセレクタを3bitにすることもでき、
データや信号線の取り回しも非常にやりやすい。
こんな素晴らしいものがフリーで公開されているとは!
(公開元のウェブサイト)
TTF形式も公開されているのでfonttoolsを使えば汎用的に扱えるが、
今回使うのは8x8だけなのでコンパクトなPNG形式を対象にした。
misaki_mincho.png ・・・ 54kB
misaki_mincho.ttf ・・・ 1,092kB
約20倍の差がある
このため、png画像から必要な部分を抜き出すことにする。
美咲フォントのpng画像はこんな感じの並び。
(↑PNG版の美咲フォント明朝から一部抜粋)
この並びはShift-JISの2Byte文字部分のよう。
(参考:文字コード表 シフトJIS(Shift_JIS)より)
■Shift-JIS
Shift-JISを構成する範囲は以下の通り。上位1Byte:0x81~0x9F、 0xE0~0xEF
下位1Byte:0x40~0x7E、 0x80~0xFC
字面だけではイメージしづらいので、0xFF×0xFFのドットマトリクスで示す。
何故隙間だらけかというと、ASCIIや他のコードと識別しやすくするためらしい。
特に上位1ByteがASCIIの0x20(半角スペース)や0x41(A), 0x61(a)と同じだと、
日本語なのかASCIIなのか1Byte目だけでは判別できなくなってしまうからだ。
これに対し、PNG画像の並びでいくつか注意が必要な部分がある。
➀開始点のオフセット
(※画像はhttp://charset.7jp.net/様より一部借用)
実際の文字コードは0x8140からスタートする。
それに対し、png画像は最初の8x8が対応するので、このオフセットを考慮しないといけない。
②1Byte目0xA0~0xDFと、2Byte目0x7Fの空白部分
図の通り、Shift-JISの中にはドデカい空白部分がある。
対して、美咲フォントのpng画像は空白部分を詰めている。
③png画像は行数2倍、列数1/2
2つの行頭を見比べると、pngのほうは「ぁァАА・・・亜院押」なのに対し、
Shift-JISの表は「ァА・・・院魁」となっている。
これは、pngのほうが区/点を基準とした表示なのに対し、
Shift-JISの表は16進数基準の表示になっているためである。
つまり、図で示すとおり元々の1行がpng画像では2行分になっている。
これら①②③を考慮すれば、あとは文字コード変換と簡単な画像処理でうまく扱えるはず。
続きは次回。
ラベル:
8bit,
misaki font,
OpenCV,
Python,
美咲フォント
2020年2月15日土曜日
Project Euler(21 - 27) ※27で断念
21
重複するので2で割っておく
22
あとは文字をforで切り出してordでASCIIコードに変えると簡潔に記述できる
23
28123 - 12以下のすべてのnに対して、過剰数リストを作る
ついで、1から28123までで、過剰数の和で表せるものをユニークなリストにする
ここで、i = j となる12+12=24のような数も含まれるのでrangeの条件式に注意(見事にハマりました)
最後に、総数から過剰数の和で表せる数の合計を引けばOK
24
先に問題を整理する
1th 0123456789 ←下1桁の入れ替えは1!=1パターン(実質入れ替えなし)
2nd 0123456798 ←下2桁の入れ替えは1th, 2ndの2!=2パターン
3rd 0123456879
4th 0123456897
5th 0123456978
6th 0123456987 ←下3桁の入れ替えは1st-6thの3!=6パターン
つまり、n! < 1000 < (n+1)!のところを探せばかなり範囲が絞れる
このとき、n!thの数字は、下n桁が逆転した数値になる
2ndなら8,9が逆転で、3!=6thなら7,8,9が987になっている
362,880thは9桁逆転なので、0987654321となる
362,881thは1023456789で、そこから8!=40,320進むとここから下8桁が逆転になる
つまり403,300thは1098765432
362,880thから9!進んだときも、同様に362,880thのうち下9桁が逆転するので、
9!*2thは1987654320となるはず
上記より、1Mthが階乗の和で表して、各桁の状態を推定する
まず、9!x2thは1987654320, 9!x2+1th = 2013456789
ここから8!x6なので2798654310, 9!x2+8!x6+1th = 2
こうしてみると、各i!の係数aがi+1桁目の数に対応しているとわかる
n番目の数を求めるとき、n!=sigma i! x A(i)と表すと、i=10桁から順番に、i桁目には残った0-9の数字の中でA(i-1)+1番目に小さい数を当てはめていく
26
うまく動いたので、あとは11 - 1000で最長を求める
27
毎回素数判定で割り算するのはもったいないので
これで愚直に解こうとしたけど、計算が遅すぎて断念
また練り直します
In [179]: def divisors(n): ...: ret = [] ...: for i in range(1, int(n**0.5+2), 1): ...: if n%i == 0: ...: if int(n/i) == i: ...: ret += [i] ...: else: ...: ret += [i, int(n/i)] ...: return list(set(ret))まずは約数のユニークなリストを出す
In [180]: lst = [] ...: for i in range(2, 10000, 1): ...: ami = sum(divisors(i)) - i ...: if i != ami and i == sum(divisors(ami)) - ami: ...: lst += [i, ami] ...: int(sum(lst)/2) Out[180]: 31626友愛数のリストを作って合計する
重複するので2で割っておく
22
In [192]: score = 0 ...: with open("p022_names.txt") as f: ...: lst = sorted(f.readlines()[0].strip().replace('"', '').split(",")) ...: i = 1 ...: for name in lst: ...: score += i * sum([ord(x)-64 for x in name]) ...: i+=1 ...: score Out[192]: 871198282Pythonのsortedはアルファベット順に並び替えてくれるのでそのまま使える
あとは文字をforで切り出してordでASCIIコードに変えると簡潔に記述できる
23
In [197]: def isAbundant(n): ...: if n < sum(divisors(n)) - n: ...: return True ...: else: ...: return False上記の関数でabundant number=過剰数というのを判定させる
28123 - 12以下のすべてのnに対して、過剰数リストを作る
In [236]: abundantList = [] ...: for i in range(12, 28124, 1): ...: if isAbundant(i): ...: abundantList.append(i)
ついで、1から28123までで、過剰数の和で表せるものをユニークなリストにする
ここで、i = j となる12+12=24のような数も含まれるのでrangeの条件式に注意(見事にハマりました)
In [282]: lst = [] ...: for i in range(len(abundantList)): ...: for j in range(i, len(abundantList), 1): ...: n = abundantList[i]+abundantList[j] ...: if n < 28123: ...: lst.append(n) ...: lst = sorted(list(set(lst)))
最後に、総数から過剰数の和で表せる数の合計を引けばOK
In [283]: sum([x for x in range(28123)]) - sum(list(set(lst))) Out[283]: 4179871
24
先に問題を整理する
1th 0123456789 ←下1桁の入れ替えは1!=1パターン(実質入れ替えなし)
2nd 0123456798 ←下2桁の入れ替えは1th, 2ndの2!=2パターン
3rd 0123456879
4th 0123456897
5th 0123456978
6th 0123456987 ←下3桁の入れ替えは1st-6thの3!=6パターン
つまり、n! < 1000 < (n+1)!のところを探せばかなり範囲が絞れる
このとき、n!thの数字は、下n桁が逆転した数値になる
2ndなら8,9が逆転で、3!=6thなら7,8,9が987になっている
In [291]: [factorial(x) for x in range(2,13,1)] Out[291]: [2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600]これより、9! - 10!の間を探せばよい
362,880thは9桁逆転なので、0987654321となる
362,881thは1023456789で、そこから8!=40,320進むとここから下8桁が逆転になる
つまり403,300thは1098765432
362,880thから9!進んだときも、同様に362,880thのうち下9桁が逆転するので、
9!*2thは1987654320となるはず
上記より、1Mthが階乗の和で表して、各桁の状態を推定する
In [313]: factorial(9)*2+factorial(8)*6+factorial(7)*6+factorial(6)*2+factorial(5)*5+factorial(4)+factorial(3)*2+factorial(2)*2 Out[313]: 1000000つまり、9!x2+8!x6+7!x6+6!x2+5!x5+4!+3!x2+2!+1!=999,999
まず、9!x2thは1987654320, 9!x2+1th = 2013456789
ここから8!x6なので2798654310, 9!x2+8!x6+1th = 2
こうしてみると、各i!の係数aがi+1桁目の数に対応しているとわかる
n番目の数を求めるとき、n!=sigma i! x A(i)と表すと、i=10桁から順番に、i桁目には残った0-9の数字の中でA(i-1)+1番目に小さい数を当てはめていく
In [338]: n="" ...: nums = [0,1,2,3,4,5,6,7,8,9] ...: for i in [2,6,6,2,5,1,2,1,1,0]: ...: n+=str(nums[i]) ...: nums.remove(nums[i]) ...: int(n) Out[338]: 278391546025
In [341]: a, b = 1, 1 ...: i = 2 ...: while len(str(b)) < 1000: ...: a, b = b, a+b ...: i+=1 ...: i Out[341]: 4782関数を作らなくても、Whileで回すだけで十分
26
In [398]: def countDivLoop(n): ...: ans = "0.0" ...: lst = [10] ...: divided = 100 ...: while True: ...: a = int(divided / n) ...: ans += str(a) ...: divided = divided % n ...: if divided == 0 or lst.count(divided) > 0: ...: break ...: lst.append(divided) ...: divided *= 10 ...: return ans, lst普通の割り算ではだめなので、割り算のループが発生するまでのリスト長さを図る関数を作成
In [403]: countDivLoop(12) Out[403]: ('0.083', [10, 4]) In [404]: 1/12 Out[404]: 0.08333333333333333 In [405]: countDivLoop(13) Out[405]: ('0.0769230', [10, 9, 12, 3, 4, 1]) In [406]: 1/13 Out[406]: 0.07692307692307693 In [407]: countDivLoop(14) Out[407]: ('0.0714285', [10, 2, 6, 4, 12, 8]) In [408]: 1/14 Out[408]: 0.07142857142857142
うまく動いたので、あとは11 - 1000で最長を求める
In [412]: maxNum = 0 ...: maxLst = [] ...: for i in range(11, 1000, 1): ...: n, lst = countDivLoop(i) ...: if len(lst) > len(maxLst): ...: maxNum, maxLst = i, lst ...: maxNum, len(maxLst) Out[412]: (983 982)
27
In [416]: 999**2+999*999+1000 Out[416]: 1997002この2次関数の最大値は1997002なので、それ以下の素数の列を作っておく
毎回素数判定で割り算するのはもったいないので
In [420]: def PrimeNumList(n): ...: primeNumList = [2] ...: i = 3 ...: while primeNumList[-1] < n: ...: for d in primeNumList: ...: if i%d == 0: ...: i+=2 ...: break ...: if i**0.5<d: ...: primeNumList.append(i) ...: i+=2 ...: break ...: return primeNumListこれに最大値を入れてリスト化しておく
これで愚直に解こうとしたけど、計算が遅すぎて断念
また練り直します
登録:
投稿 (Atom)