あらきけいすけのメモ帳

あらきけいすけの雑記帳2

Microsoft Excel について

業務用の覚書。書きかけ。

Excelの利点

  • (多分、職場の)誰もが Excel を持っている。Excel ファイルとちょっとましなマシン(Core i7 + 8GB RAM とか)があればどこでも作業できる。(業務遂行に関して自由度が上がる)
  • (多分、実用的には、項目数が50以下、レコード数が10,000以下程度なら) WYSIWYG のデータベースとして使える。つまりクエリを投げずに直に検索, 置換, 編集ができる。とくに「フィルター*1」と「ウィンドウ枠の固定*2」は操作が直感的でいい。
  • オンプレミス*3で運用できる。(これはGoogleドライブにはできない)
  • プログラム(VBAマクロ)を書いてデータ操作ができる。(ただし Visual Basic for Application は動作がもっさりとしている。特にスレッディングができない*4。)
  • Excel ファイルにデータを書き出せる(データファイルとアプリケーション実行環境の「閉じた(複数にまたがらない)」エコシステムである。)
  • VBA には「連想配列( Scripting.Dictionary オブジェクト)」があるので Key-Value 的なコードが書けなくもない
  • Excel VBA 使いがいれば、外注するよりコミュニケーションの時間コストを下げることができる

ラグランジュ補間(2点を通る直線の公式)、単位の換算、そのプログラミングについての覚え

授業のための覚書

2点(x_0,y_0), (x_1,y_1)を通る直線の公式:\displaystyle y=\frac{x-x_1}{x_0-x_1}y_0+\frac{x-x_0}{x_1-x_0}y_1
これは Lagrange 補間(Lagrangian interpolation*1)と呼ばれる計算技法である。この式は次のようにも書ける:
2点(x_0,y_0), (x_1,y_1)を通る直線の公式:\displaystyle y=\frac{x-x_0}{x_1-x_0}(y_1-y_0)+y_0
「直線の式」だからって、この計算式の応用範囲が「直線を描画する」といったグラフィックスだけに限られるわけではない。例えば、摂氏温度*2から華氏温度*3への換算にも使える。水の氷点が(0度C,32度F), 沸点が(100度C,212度F)なので摂氏温度がc度のときの華氏温度の値は\displaystyle f=\frac{c-100}{0-100}32+\frac{c-0}{100-0}212になる。
ここで受験数学の答案のような「筆算にしばられた発想」だと、係数を整理してf=1.8c+32とまとめるところだが、プログラミングの世界では整理すべきでない。この換算をC言語コードで書くときは、次のように書くのがベター;

// マクロ, 関数形式マクロ
#define Cfleeze   (0.0)
#define Cboil   (100.0)
#define Ffleeze  (32.0)
#define Fboil   (212.0)
#define tempC2tempF(tempC) (tempC - Cfleeze)/(Cboil - Cfleeze)*(Fboil - Ffleeze) + Ffleeze
// 定数, 関数
float tempC2tempF (float tempC) {
  const float Cfleeze =  0.0, Cboil = 100.0;
  const float Ffleeze = 32.0, Fboil = 212.0;
  tempF = (tempC - Cfleeze)/(Cboil - Cfleeze)*(Fboil - Ffleeze)
          + Ffleeze;
  return tempF;
}

このコードならば「tempC=CfleezeのときにFfleeze」「tempC=CboilのときにFboil」の値を返す tempC の1次関数を計算していると分かる。ややこしい計算はコンピュータにやらせればよい。むしろ「何の計算をコンピュータにやらせているのかはっきり分かる」コードの方がベターである*4

演算数から考えると const を使って計算の定数を予め作っておいて*5、define で「インラインで計算」するのが早いかも:

// マクロ, 関数形式マクロ
// tempC2tempF(tempC) = (tempC - Cfleeze)/(Cboil - Cfleeze)
//                      *(Fboil - Ffleeze) + Ffleeze
#define Cfleeze   (0.0)
#define Cboil   (100.0)
#define Ffleeze  (32.0)
#define Fboil   (212.0)
const float
  tempC2tempFCoeff  = (Fboil - Ffleeze)/(Cboil - Cfleeze),
  tempC2tempFOffset = -(Cfleeze)*(Fboil - Ffleeze)/(Cboil - Cfleeze)
                      + Ffleeze;
#define tempC2tempF(tempC) ((tempC)*tempC2tempFCoeff + tempC2tempFOffset)

*1:ラグランジュ補間 - Wikipedia

*2:セルシウス度 - Wikipedia

*3:華氏 - Wikipedia

*4:プログラミングの世界では、いきなり数値をソースコードに書くことは「マジックナンバー」と呼ばれ、プログラムの可読性が悪くなるので避けるべきとされている。;マジックナンバー (プログラム) - Wikipedia可読性 - Wikipedia

*5:変数名は長くなってもよいから、計算で使うデータの内容を表示した方がよい。変数名の長さは、実際のCPU上で動くマシン語には影響しない。

python のリスト/辞書/タプルに特定の値を持つ要素が存在するかどうかの確認方法

で、躓いたのでメモをする。

if 〔探索値〕 in 〔リスト名/辞書名/タプル名〕:
        〔探索値がリスト/辞書のキー/タプル中にあったときの処理〕

ここで 〔探索値〕の添字を返すメソッド

〔リスト名〕.index(探索値)

を用いると存在しない場合に ValueError を返して、例外処理を書かないとコードの進行が止まる。辞書の〔キー〕・〔値〕のペアの〔値〕の中から探索するには

if 〔探索値〕 in 〔辞書名〕.values():
        〔探索値が辞書の値の中にあったときの処理〕

pigpio ライブラリの spi_xfer() 関数を用いて Raspberry Pi 3B から SPI 接続のA/Dコンバータ MCP3208 を利用する

自分用の覚書。ようやく pigpio の spi_open() と spi_xfer() のパラメータの与え方が分かったので、Python と C のミニマルコードをメモしておく。

Python

参考にしたサイト
tomosoft.jp

#! /usr/bin/env python
# -*- coding: utf-8 -*-
#
# Raspberry Pi 3B から MCP3208 を利用するコード (終了は Ctrl-C)
#
# ピンの接続
#   Raspberry Pi 3B           MCP3208
#   [19] GPIO_10 SPI_MOSI  -> [11] D_IN
#   [21] GPIO_09 SPI_MISO  <- [12] D_OUT
#   [23] GPIO_11 SPI_CLK   -> [13] CLK
#   [24] GPIO_08 SPI_CE0_N -> [10] ~CS/SHDN
#
# MCP3208 の [1]CH0 のA/D変換値(0~4095)を表示する
#
# 参考にしたサイト (2018年10月27日アクセス)
#   http://abyz.me.uk/rpi/pigpio/python.html
#     pigpio library: Python Interface
#   https://tomosoft.jp/design/?p=10477
#     TomoSoft: pigpioによるI2CとSPIインタフェースの実装
#     注: MCP3208 は12bitのA/Dコンバータだが testspi.py では
#         そのうちの上位10bitのデータ(0~1023)を利用していた。
#

import time
import pigpio

slct = 0 # +1 +1 # SPI接続機器の番号 chip select
baud = 50000     # 通信速度
flag = 0 # +256  # bin(256) = 0b100000000 は Aux SPI の利用フラグ
adch = 0         # MCP3208のCH0の番号

pi = pigpio.pi()
hndl = pi.spi_open(slct, baud, flag) # デバイスオープン

try:
  while True:
    cmnd = ( 0b00011000 + adch ) << 2
    c, raw = pi.spi_xfer(hndl,[cmnd,0,0]) # 最初の要素が命令の入力
    #
    #    [0][1][1][D2][D1][D0][0][0]
    #        |  |   |   |   |
    #        |  |  読み出しチャネルの指定
    #        | 1: シングルエンド
    #       [スタートビット]
    #
    data = ((raw[1] & 0b11111111) <<  4) + \
           ((raw[2] & 0b11110000) >>  4)
    print(c,raw,bin(data),data)
    time.sleep(1)

except KeyboardInterrupt:
    pi.spi_close(hndl)
    pi.stop()

C言語

参考にしたサイト
Raspberry Pi 3とADS7843を使ってタッチスクリーンの情報を受け取る(Cでpigpioを使ってSPI通信→Nodejs) - Qiita
gpio - pigpio spiXfer in C++ - Raspberry Pi Stack Exchange

/*
  pigpio の spiOpen(), spiXfer() を利用する最小限コード
  Raspberry Pi 3B と MCP3208 の接続は上の Python コードと同じ
  動作: A/Dコンバータを1秒間隔で10回読んで、表示する(終了は自動)

  参考にしたサイト
    https://qiita.com/yuji_miyano/items/e86150759818c3c12fa4
    https://raspberrypi.stackexchange.com/questions/79127/pigpio-spixfer-in-c/79128#79128
*/
#include <stdio.h>
#include <unistd.h>
#include <pigpio.h>

int main (void) {
  if ( gpioInitialise() < 0 ) {
    printf("gpioInitialise() failed\n");
  } else {
    printf("gpioInitialise() succeeded\n");
    int slct = 0;//+2   // SPI接続機器の番号 chip select
    int baud = 50000;   // 通信速度
    int flag = 0;//+256 // 256: Aux SPI の利用フラグ
    int hndl = spiOpen(slct, baud, flag);
    if ( hndl < 0 ) {
      printf("spiOpen() failed\n");
    } else {
      printf("spiOpen() succeeded\n");
      int count = 0;
      while ( count < 10 ) {
        int adch = 0;  // MCP3208のCHの番号(0-7)
        char txBuf[3]; // 読み出し命令, AD変換データの入れ物
        txBuf[0]= ( 0x18 + adch ) << 2;
        txBuf[1]= txBuf[2]= 0;
        spiXfer(hndl,txBuf,txBuf,3); // pigpio: SPI読み出し
        int data =  // 読み出したバッファからの移し替え
          ( txBuf[1] & 0xff ) << 4 |
          ( txBuf[2] & 0xf0 ) >> 4;
        printf("%d %d\n",count,data);
        count++;
        sleep(1);
      }
      spiClose(hndl);
    }
    gpioTerminate();
  }
}

2018年台風12号 Jongdari の動きと天気図

あまりにもへんてこな動きをした台風だったので*1、2018年7月28日21時の天気図と衛星画像を簡単にまとめてみた。低気圧は反時計回りの渦なのだが、今回は上空10,000m位の高さにかなり強くて大きな低気圧があって、衛星画像を見ても日本の南におおきな渦が回っているのが見える。*2f:id:arakik10:20180729083954j:plain

見たところ台風12号はこの上空の低気圧の流れに流されて西へと向かう奇天烈な軌道を取ったようにみえる。藤原の効果*3というときは主に同じ高度の2個の渦の相互作用を考える(例えば英語版Wikipediaにあるように2個の台風の融合)ようだが、今回は「上下2層」の相互作用なので、「融合」は無くて「吹送(みたいな何か)」が起きたのか。

*1:2018年7月28日3時JSTのJTWCの進路予想f:id:arakik10:20180729152042g:plain

*2:この季節にこのような場所と高度にこのような低気圧ができるのが珍しいことかどうかは知らない。

*3:Fujiwhara effect - Wikipedia, 藤原の効果 - Wikipedia

こどもといっしょに簡単なゲームプログラムを pygame で書いた

f:id:arakik10:20180322183954p:plain
最近、うちの子が「ゲームプログラミング」を熱く語るので、簡単なゲームプログラムを Python 3.6.3 + pygame 1.9.3 で作った。目の前でちょっとずつ作ってみせつつ、ときどきコピペをやらせて変数名やパラメータを書き換えさせる。ゲームパッド(の左レバー)で「自機(赤い正方形)」を操作しながら、ランダムに逃げ回る「獲物(青い正方形)」を60秒以内に何度も捕まえる「鬼ごっこゲーム」スクリプトpygame ライブラリだと「窓枠を作る」「窓枠内に絵を描く」「ジョイスティックのデータを取る」「クロックを使う」といった基本機能の API が大抵あるので、LEGO みたい。

import pygame
import numpy

pygame.init()
screen = pygame.display.set_mode((240,180))
pygame.display.set_caption("My Game")
font=pygame.font.SysFont('Calibri',25,True,False)
clock = pygame.time.Clock()

posRect= [120-10, 90+10, 20, 20]
posRect0= [120-5, 90+5, 10, 10]
x=0
y=0
x0=0
y0=0
score=0
timeRemain=600

try:
    j = pygame.joystick.Joystick(0)
    j.init()
    print( 'Joystickの名称: ' + j.get_name())
    print( 'ボタン数 : ' + str(j.get_numbuttons()))
except pygame.error:
    print('Joystickが見つかりませんでした。')

done = False
while not done:

    screen.fill((255,255,255))

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

        if event.type == pygame.JOYAXISMOTION:
            u , v = j.get_axis(0), j.get_axis(1)
            if int(u*10)+int(v*10) != 0:
                x= x + int(u*10)
                y= y + int(v*10)
                if x > 100:
                    x= 100
                if x < -100:
                    x= -100
                if y > 80:
                    y= 80
                if y < -80:
                    y= -80
                posRect= [120-10+x, 90-10+y, 20, 20]

    r= numpy.random.rand(2)
    speed= 0.5
    x0= x0 + int(r[0]*20-10)*speed
    y0= y0 + int(r[1]*20-10)*speed
    if x0 > 100:
        x0= 100
    if x0 < -100:
        x0= -100
    if y0 > 80:
        y0= 80
    if y0 < -80:
        y0= -80
    posRect0= [120-5+x0, 90-5+y0, 10, 10]

    if (x0 - x)**2 + (y0 - y)**2 < 150:
        score= score + 1

    pygame.draw.rect(screen, (255,0,0), posRect, 2)
    pygame.draw.rect(screen, (0,0,255), posRect0, 2)

    timeRemain= timeRemain - 1
    text= font.render(str(score)+' '+str(timeRemain),True,(0,0,0))
    screen.blit(text,[0,0])
    pygame.display.flip()

    if timeRemain == 0:
        pygame.time.wait(10000)
        done = True

    clock.tick(10)

pygame.quit()

参考にしたページ
Joystickの入力を取得する - 強火で進め
Program Arcade Games With Python And Pygame Chapter 5: Introduction to Graphics

n乗根、あるいは「量」と「量の値」に関するとりとめのない素人考え

  • 2016.1.27の日記をgdgdと考え直す…
  • 大学教養程度の数学のコンテンツを高校数学の教程まで遡りつつ考えると、n乗根(\sqrt[n]{a}=a^{1/n})がいきなり暗黙のうちに実数の連続性を前提している強烈な「天下り式」であることに気付いてから考え始めた。
  • 「数の位取り記法」と「量」の区別を考える。
  • \sqrt3は「量」と「操作」を表しており、 操作(\sqrt3)^2=3を通して「量の計算の体系」に組み込まれている。
  • 「量」を「数の位取り記法」で表現することで「量」としての大きさの概算ができる。
  • 「量の計算」と「位取り記法を用いた量の値の計算」を区別して考える
  • 「量」を「数の位取り記法」で表現するアルゴリズムがいくつかある。
  • たとえば1/3=0.333...は小学校で学習するわり算の筆算、 すなわち量としての「商」を「数の10進位取り記法」で表現するアルゴリズムを実行すると、 アルゴリズムが止まらない例になっている。
  • 例えば「開平計算」や「バビロニアアルゴリズム+わり算の筆算」を用いて、 \sqrt3の「10進の位取り記法」1.732...を得ることができるが、 アルゴリズムは止まらないことがこれらのアルゴリズムとは別の論理から論理的に分かるし、 アルゴリズム自体に自動停止する機構は組み込まれていない。
  • 「数」と「量」を区別して考えるとき、 分数の計算ルールは「量」の計算体系。
  • 「計量・計測」の分野では "quantity value" 「量の値」という表現があるよなあ。 「量」があって「真の値」を持つけれど、その値の「精度」は測定の方法によるし、 その「精度」の制限内で「測定値」を知り得るに過ぎない。 「量」と「数の位取り記法」の一つの接点である。
  • 「数」あるいは「数の位取り記法」のルールとして確立された 「算法(たし算、ひき算、かけ算、わり算)」が、 「量」の計算に拡張されているということなのか?
  • 離散量にしても連続量にしても量の「単位」を抱えている。
  • 例えば身長1.5mならば「長さの次元を持つ量である"mという単位"の1.5倍」という意味。 だから単位とは分数で書いて計算を進めるときに、分母、分子に現れたら約分をして無次元化しないといけない量。
  • 連続量の中に「数の位取り記法」に対して 記数アルゴリズムが「止まるもの」 「止まらないが『周期的』な動作になるもの」 「止まらないし『周期的』にもならないもの」 の3種類に分類される。
  • \sqrt2の計算で (1.1)^3\lt(1.01)^{34}\lt(1.001)^{346}\lt(1.0001)^{3465}\lesssim\sqrt{2}=2^{1/2} では指数の桁が1個ずつ増えて収拾がつかなくなるので、 「数の位取り記法」を悪用して、指数法則(a^m)^n=a^{mn}が小数でも利用できると前提して、 ((1.1)^{10})^{0.3}\lt((1.01)^{100})^{0.34}\lt((1.001)^{1000})^{0.346}\lt((1.0001)^{10000})^{0.3465}\lesssim\sqrt{2}=2^{1/2} とおいて指数を規格化すると\sqrt2に対応する指数は 0.3465... に収束しそう。
  • この桁を増やしていく作業の極限で万能の指数が作れる。
    これが万能の指数の底 \displaystyle e=\lim_{N\to\infty}\left(1+\frac1N\right)^N の由来。(Jakob Bernoulliのアイディア)
    桁を一つ増やす操作で1にどんどん近づくから、指数の底は正の数。
  • これに対してx\in\mathbb{R}に対し\displaystyle e=\lim_{x\to\infty}\left(1+\frac1x\right)^x=\lim_{x\to0}\left(1+x\right)^{1/x}は実数の指数を前提とした式で、ただの天下りで、値を求めるアルゴリズムが無い。
  • n乗根の「値(近似値列)」の導入で、 n乗根という実数を前提とする量のうさん臭さや、 eの定義にたどり着く教科書があってもいいのではないか?
  • 指数関数はe^xしかない。一般の底の指数関数はa^x:=e^{x\ln a}で定義される。
  • 底の値e=2.7...のときだけ指数法則を使わずに級数\displaystyle e^x=1+x+\frac{x^2}{2!}+\cdots+\frac{x^n}{n!}+\cdotsで指数関数の値を求めることができる。
  • このあたりの「値を求めるアルゴリズムの存在」が高校までの教程で不足しているのではないかと感じている部分。
  • 分母の有理化(例えば\frac{1}{\sqrt2}=\frac{\sqrt2}{2})の必要性は、むかしむかし関数電卓普及以前の有効数字がせいぜい4桁程度の時代に、量の値を筆算で求めなくてはいけない場合に、「2という正確な値でわり算を実行」と「1.414という近似値で面倒なわり算の実行」の対比の中で合理的な算法であったといえるが、スプレッドシートで10桁くらいは強引に計算できる時代に意味があるだろうか?
  • 数学IIIまで習った後ならば、f(xy)=f(x)+f(y)を出発点として対数関数(とその逆関数としての指数関数)を論理的かつ関数の値を求めるアルゴリズム(の方向性)付きで導出できる:e関連の極限の式を避けて対数関数と指数関数を微分する - あらきけいすけのメモ帳
  • 0.999999...は 「止まらないアルゴリズムで定義されている位取り記法された数」であり、 標準的な「量」の演算の体系では、その「量の値」は1に等しい。