#はじめに
くだらない中で学んだことが多かったので共有
アイデアの先人
空気の成分30連ガチャ
空気を構成している要素、どこまで言えますか?
窒素、酸素、二酸化炭素、アルゴン...あとは知りませんでした。
こちらのサイトでガチャを回せます。
#空気ガチャ排出率
空気を構成している成分は空気 - Wikipediaによると
成分 | 化学式 | 体積比 割合(vol%) |
---|---|---|
窒素 | N2 | 78.084 |
酸素 | O2 | 20.9476 |
アルゴン | Ar | 0.934 |
二酸化炭素 | CO2 | 0.0390 |
ネオン | Ne | 0.001818 |
ヘリウム | He | 0.000524 |
メタン | CH4 | 0.000181 |
クリプトン | Kr | 0.000114 |
二酸化硫黄 | SO2 | 0.0001 |
水素 | H2 | 0.00005 |
一酸化二窒素 | N2O | 0.000032 |
キセノン | Xe | 0.0000087 |
オゾン | O3 | 0.000007 |
二酸化窒素 | NO2 | 0.000002 |
ヨウ素 | I2 | 0.000001 |
空気を構成している成分の体積比をガチャの排出率とします。
※Wikipedia内の「表2: 乾燥空気の微量成分」についてはあまりにも微量なので今回は無視します。
#ソースコード
"""
https://ja.wikipedia.org/wiki/%E7%A9%BA%E6%B0%97#%E6%88%90%E5%88%86
表1: 乾燥空気の主な組成(国際標準大気、1975年)
成分 化学式 体積比 割合(vol%) ppm ppb 備考
窒素 N2 78.084 780,840 - [12]
酸素 O2 20.9476 209,476 - [12]
アルゴン Ar 0.934 9,340 - [12]
二酸化炭素 CO2 0.0390 390 - +*2011年の値[13][12][注 2]
ネオン Ne 0.001818 18.18 - [12]
ヘリウム He 0.000524 5.24 - [12]
メタン CH4 0.000181 1.81 1813±2 +2011年の値[13][12][注 3]
クリプトン Kr 0.000114 1.14 - [12]
二酸化硫黄 SO2 0.0001> 1> - *[12]
水素 H2 0.00005 0.5 - [12]
一酸化二窒素 N2O 0.000032 0.32 324.2±0.1 +*2011年の値[13][12][注 4]
キセノン Xe 0.0000087 0.087 87 [12]
オゾン O3 0.000007> 0.07> 70> *[注 5][12]
二酸化窒素 NO2 0.000002> 0.02> 20> *[12]
ヨウ素 I2 0.000001> 0.01> 10> *[12]
"""
import random
import time
from decimal import Decimal
dic = {"窒素 N2":78.084, "酸素 O2":20.9476, "アルゴン Ar":0.934, "二酸化炭素 CO2":0.0390, "ネオン Ne":0.001818, "ヘリウム He":0.000524, "メタン CH4":0.000181, "クリプトン Kr":0.000114, "二酸化硫黄 SO2":0.0001, "水素 H2":0.00005, "一酸化二窒素 N2O":0.000032, "キセノン Xe":0.0000087, "オゾン O3":0.000007, "二酸化窒素 NO2":0.000002, "ヨウ素 I2":0.000001}
com = ["窒素", "酸素", "アルゴン", "二酸化炭素", "ネオン", "ヘリウム", "メタン", "クリプトン", "二酸化硫黄", "水素", "一酸化二窒素", "キセノン", "オゾン", "二酸化窒素", "ヨウ素"]
che = ["N2", "O2", "Ar", "CO2", "Ne", "He", "CH4", "Kr", "SO2", "H2", "N2O", "Xe", "O3", "NO2", "I2"]
keys = []
for i in dic.keys():
keys.append(i)
su = 0
for i in dic.keys():
su += int(Decimal(str(dic[i]))*(10**7))
dic[i] = int(Decimal(str(dic[i]))*(10**7))
out = [0 for i in range(len(keys))]
que = 10**6
for q in range(que): #10**6は10秒, 10**7は2分かかる
t = time.perf_counter()
random.seed(t)
ra = random.randint(0, su)
res = 0
if 0 <= ra < dic[keys[0]]:
out[0] += 1
else:
res += dic[keys[0]]
for i in range(1, len(keys)):
"""
if i >= 5:
print("!!!!!!!!!!!!")
print(out)
"""
if res <= ra < res + dic[keys[i]]:
out[i] += 1
break
res += dic[keys[i]]
#半角, 全角による文字の"揺らぎ"を整形するための関数
import unicodedata
def left(digit, msg):
for c in msg:
if unicodedata.east_asian_width(c) in ('F', 'W', 'A'):
digit -= 2
else:
digit -= 1
return msg + ' '*digit
print("空気ガチャ" + "{:.0e}".format(que) + "(" + str(que) + ")" + "連")
for i in range(len(keys)):
print(left(12, com[i]), left(3, che[i]), "{:>7}".format(out[i]))
#実行結果
que = 10**6
のとき
空気ガチャ1e+06(1000000)連
窒素 N2 780580
酸素 O2 209579
アルゴン Ar 9406
二酸化炭素 CO2 391
ネオン Ne 32
ヘリウム He 5
メタン CH4 3
クリプトン Kr 1
二酸化硫黄 SO2 2
水素 H2 1
一酸化二窒素 N2O 0
キセノン Xe 0
オゾン O3 0
二酸化窒素 NO2 0
ヨウ素 I2 0
que = 10**7
のとき
空気ガチャ1e+07(10000000)連
窒素 N2 7809540
酸素 O2 2092942
アルゴン Ar 93396
二酸化炭素 CO2 3808
ネオン Ne 214
ヘリウム He 54
メタン CH4 12
クリプトン Kr 11
二酸化硫黄 SO2 6
水素 H2 10
一酸化二窒素 N2O 6
キセノン Xe 1
オゾン O3 0
二酸化窒素 NO2 0
ヨウ素 I2 0
#注意ポイント
####浮動小数点数の誤差
float型の扱いには注意しましょう。
コンピュータの内の2進数の世界では小数を扱うとき、正確な値を扱うことができません。
print(0.1 + 0.2)
#実行結果: 0.30000000000000004
どこから現れた0.00000000000000004!!!!!!!!
そこでPythonで小数点以下を扱うときはDecimal()
を使うとよいでしょう。
15. 浮動小数点演算、その問題と制限 — Python 3.8.3 ドキュメント
from decimal import Decimal
print(Decimal("0.1") + Decimal("0.2"))
#実行結果: 0.3
コード内で
for i in dic.keys():
su += int(Decimal(str(dic[i]))*(10**7))
dic[i] = int(Decimal(str(dic[i]))*(10**7))
としている部分が誤差の回避に該当しています。
10**7を掛けて排出率を整数で扱おうとしているときに、計算が行われているので浮動小数点型だと誤差が発生してしまいますね。
####ランダムの作成
[time.time()は精度があまりよくない? - Qiita]
(https://qiita.com/takeopy/items/170d0e1ddbf02ef9fbb9)
for文が回るのが早すぎるのでtime.time()
では同じ時刻を生成してしまい、シード値が同じになる可能性が高いです(Windows環境では実際そうだった)。
そこで精度の高いtime.perf_counter()
を使います。
t = time.perf_counter()
random.seed(t)
ra = random.randint(0, su)
####半角, 全角による文字の"揺らぎ"を整形
Pythonのunicodedataライブラリを使って、全角文字も半角文字も揃えて表示する - Qiita
見やすい出力を心がけましょう。
for i in range(len(keys)):
print(left(12, com[i]), left(3, che[i]), "{:>7}".format(out[i]))
#感想
確率は偏る。