組込み系プログラマの終末

プログラミング、デバイスドライバ、資格、試験、等などなど

Googleフォームで申し込みフォーム【自動返信、自動リマインダ送信、申し込み上限、付き】

Googleフォームで申し込みフォームを作成する機会があったので備忘のため書いておきます。下記機能に対応しています。

自動返信
申し込みがあった時点で、申し込み者に「受け付けた」を通知する。

申し込み上限
申し込みの上限を決めておき、それを超えた場合は自動返信で「すでに満席だからキャンセル待ち」を通知する
申し込み上限を超えた分はスプレッドシートを赤くする

リマインダ
申し込み者のうち、スプレッドシート上に手動で追加した「リマインド通知」の値が「通知」となっている人物に、指定時刻にリマインダを送信



//*************
//申し込み上限
//*************
var maxMoushikomi=3;

//*************
//ユーザに通知する文言(申し込み受付時の自動返信)
//*************
var MailTitleOK="XXXX講座にお申込み頂きありがとうございます";
//MailBodyOK1の前には申し込み者の氏名が入ります
var MailBodyOK1  = "様\n";
    MailBodyOK1 +=  "この度はXXXX講座にお申込み頂きありがとうございます\n";
    MailBodyOK1 += "下記のとおり受け付けました。\n";
    MailBodyOK1 += "------------------------------------------------------------\n";

               //MailBodyOK1とMailBodyOK2の間は申し込み者の情報(名前、アドレス)が記載されます

var MailBodyOK2 =  "------------------------------------------------------------\n\n";
    MailBodyOK2 += "クレジットカードか銀行振り込みでの決済を MM/DD までにお願いします。\n";
    MailBodyOK2 += "◆クレジットカードでお支払いの場合\n";
    MailBodyOK2 += " 下記サイトでお支払い願います。(外部サイト)\n";
    MailBodyOK2 += " http://aaa.bbb.ccc \n";
    MailBodyOK2 += "◆銀行振り込みでお支払いの場合\n";
    MailBodyOK2 += " 〇〇銀行\n";
    MailBodyOK2 += " 口座番号 AAAAAAA\n";
    MailBodyOK2 += " 上記口座にお支払い願います。\n";
    MailBodyOK2 += " \n";
    MailBodyOK2 += " MM/DDまでにお支払い頂けますよう、ご協力よろしくお願い致します。\n";
    MailBodyOK2 += " \n";
//*************
//ユーザに通知する文言(満席時のキャンセル通知)
//*************
var MailTitleNG="※申し込み未完了※XXXX講座は満席でした。";

//MailBodyNGの前には申し込み者の氏名が入ります
var MailBodyNG = "様\n";
    MailBodyNG +="この度はXXXX講座にお申込み頂きありがとうございます\n";
    MailBodyNG +="大変申し訳ございませんが現在講座が満席のため、キャンセルがで次第ご案内いたします。";          
    MailBodyNG +="MM/DDまでにキャンセルの有無に関わらず連絡致します。"
//*************
//ユーザに通知する文言(リマインド)
//*************
var MailTitleReminde="申し込みいただいた講座開催日が近づいています";
//MailBodyRemindeの前には申し込み者の氏名が入ります
var MailBodyReminde =  "様\n";
    MailBodyReminde +=  "こんにちは。\n";
    MailBodyReminde +=  "お申込みいただいたXXXX講座の開催が近づいております。\n";
    MailBodyReminde +=  "◆講座詳細\n";
    MailBodyReminde +=  " 日時 MM/DD 12:00~15:00\n";
    MailBodyReminde +=  " 場所 ビッグサイト\n";
    MailBodyReminde +=  " 持ち物 筆記用具\n";
    MailBodyReminde +=  "\n";
    MailBodyReminde +=  "当日お会いできることをスタッフ一同楽しみにしております\n";
//*************
//管理者への通知で使用する文言,アドレス
//*************
var kanriAdress = "admin_XXXX@gmail.com";
var kanriTitle = "講座申し込み通知";
var kanriReminderTitle="リマインダを通知しました";
//kanriReminderBodyの前にはリマインドリストが入ります
var kanriReminderBody="以上のお客様にリマインドを通知しました。\n";

//*************
//フォーム項目名
//*************
var name = 'お名前';
var mail = 'ご連絡先メールアドレス';

//*************
//リマインダ
//*************
//スプレッドシートの項目名(手動で入力)
var remind = 'リマインド通知';
//各行に記載する文字(手動で入力)
var sendJudge='通知';
//=======================================================================================
//↑変更する箇所はここまで↑これより下はプログラム内容を理解したうえで編集すること
//=======================================================================================
//自動返信用関数
function autoreply() {
 
 var title = MailTitleOK; 
 var body=MailBodyOK1;

 var address = "";
 var userName;
 
 var sheet = SpreadsheetApp.getActiveSheet();
 var rows = sheet.getLastRow();
 var cols = sheet.getLastColumn();
 var rg = sheet.getDataRange();
 Logger.log("rows="+rows+" cols="+cols);
 var userObj = rg.getCell(rows, 1);
 for (var i = 1; i <= cols; i++ ) {
   var col_name = rg.getCell(1, i).getValue(); 
   var col_value = rg.getCell(rows, i).getValue(); 
   
   body += "■"+col_name+"\n";
   body += col_value + "\n\n";
   if ( col_name === name ) {
     //body = col_value+" 様\n\n"+body;
     userName=col_value;
   }
   else if ( col_name === mail ) {
     address = col_value;
   }

 }
 body += MailBodyOK2;
 
 if(rows <= (maxMoushikomi+1)){
    var kanriBody = userName+"様の申し込みがありました";
    Logger.log("address="+address);
   GmailApp.sendEmail(kanriAdress,kanriTitle,kanriBody);
   GmailApp.sendEmail(address,title,userName+body);
 }else{
   var body2 = userName+MailBodyNG;
    var kanriBody = userName+"様の申し込みがあり、キャンセル待ちを通知しました";
   GmailApp.sendEmail(address,MailTitleNG,body2);
   GmailApp.sendEmail(kanriAdress,kanriTitle,kanriBody);
   userObj.setBackgroundRGB(255, 0, 0); 
 }
}

//リマインド用関数
function reminder() {
 var sheet = SpreadsheetApp.getActiveSheet();
 var rows = sheet.getLastRow();
 var cols = sheet.getLastColumn();
 var rg = sheet.getDataRange();
 var addIndex;
 var nameIndex;
 var kanriBody="";
   
 Logger.log("rows2="+rows+" cols2="+cols);
 for (var i = 1; i <= cols; i++ ) {
   var col_name = rg.getCell(1, i).getValue(); 
   var col_value = rg.getCell(rows, i).getValue(); 
   if ( col_name === mail ) {
     addIndex = i;
   }
   if ( col_name === name ) {
     nameIndex = i;
   }
   if ( col_name === remind ) {
     for(var k =1;k<=rows;k++){
       var col_remind = rg.getCell(k, i).getValue(); 
       var col_add = rg.getCell(k, addIndex).getValue(); 
       var col_name= rg.getCell(k, nameIndex).getValue();  
       if(col_remind === sendJudge){
         Logger.log("send k="+k+" col_remind="+col_remind+" col_add="+col_add);
         kanriBody+=col_name;
         kanriBody+=",";
         kanriBody+=col_add;
         kanriBody+=",\n";
         GmailApp.sendEmail(col_add,MailTitleReminde,col_name+MailBodyReminde);
       }else{
         Logger.log("not send k="+k+" col_remind="+col_remind+" col_add="+col_add);
       } 
     }
   }
 }
  
  GmailApp.sendEmail(kanriAdress,kanriReminderTitle,kanriBody+kanriReminderBody);
}

このプログラムのうち、動作をいじるのは下記2か所。好きに設定してください。

//*************
//申し込み上限
//*************
var maxMoushikomi=3;


//*************
//管理者への通知で使用する文言,アドレス
//*************
var kanriAdress = "admin_XXXX@gmail.com";

返信のメッセージは適宜変更が必要です。


フォームは↓のように、「お名前」と「ご連絡先メールアドレス」が必須です。
f:id:public2015:20180624003449p:plain


リマインドの通知のためのスプレッドシートの設定は↓のように「リマインド通知」列を追加します。
f:id:public2015:20180624003527p:plain


リマインダの時刻、プログラム設定は↓です。
f:id:public2015:20180624003849p:plain


使用は自己責任でお願いしますm(_ _)m

最小二乗法で近似直線を求める

とあるウェアラブルバイス開発時にセンサの測定値に誤差が乗ってしまう問題がありました。色々調べているとその誤差は「人の歩く速度」によって大きさが変わることが分かったので、歩く速度を変えて誤差の大きさを測定しました。その結果が下のグラフです。(縦軸:誤差量、横軸:速度)

f:id:public2015:20160630222637p:plain

 

 

性別や体重、年齢の違う人たちに同じように歩いてもらいました。その結果誤差は「性別や体重、年齢には依存せず、速度にほぼ比例する」という特性を掴みました。つまり以下のように誤差を直線として表すことができます。

f:id:public2015:20160630222643p:plain

この直線の方程式(Y(誤差量)=αxX(速度)+β)を見つけることで誤差量を算出できるようになるため、下記式で誤差を取り除いた真の値(に近い値)を知れるようになります。

真値=測定値ー(α✕速度+β)

さて、ではこのαとβはどう求めるのでしょうか?今日はその方法をできるだけ分かりやすく説明したいと思います。

 

連立方程式

まずは単純に2点を選んで直線の方程式を求めてみるとどうなるか考えてみましょう。

 

f:id:public2015:20160630225201p:plain

多くのデータの振る舞いとよく似た直線を求めたいので、上図の【期待する直線】が求めたい近似直線となります。

さて連立方程式の場合、選んだ2点によって赤破線や青破線のように期待しない直線となってしまうことがあります。よって連立方程式で近似直線を求めるのは不適切となります。

 

最小二乗法で求める

今回の目的は、人の歩く速度によって乗る誤差がどの程度か推測するために、誤差を式で表すことです。そのために(Y(誤差量)=αxX(速度)+β)におけるαとβを見つける必要があります。このようなケースではデータの近傍を繋ぐ補間方法である最小二乗法が有効です。

 

図中の4点をそれぞれ以下のようにx1〜x4とy1〜y4で表します。

(X1,Y1)

(X2,Y2)

(X3,Y3)

(X4,Y4)

 

さてではY(誤差量)=αX(速度)+βにx1〜x4とy1〜y4を代入してみましょう。

Y1=αX1+β

Y2=αX2+β

Y3=αX3+β

Y4=αX4+β

 

上記4つの関係を満たすαとβは・・・4点が厳密に同一直線上にいない限り、残念ながら存在しません。あれ、このままではαとβは解が無いとなってしまいます。それは困る。そこで新たに真値との「誤差」を用意しましょう。

f:id:public2015:20160630231204p:plain

先ほどの式を書きなおすと下記になります。ε(イプシロン)が真値との誤差を表しています。

Y1=αX1+β+ε1・・・①

Y2=αX2+β+ε2・・・②

Y3=αX3+β+ε3・・・③

Y4=αX4+β+ε4・・・④

 

ε1〜ε4が最小になるαとβを見つけることで、良い近似直線を見つけることができます。

 

特定のεではなく、εの合計が最小となるものを見つけなければなりません。しかしεは正負どちらもありえるため単純に加算すると誤った結果を得てしまうことがあります。

4つの誤差が 1、−1、2、2 の場合、和は0

4つの誤差が 0.1、0.2、0.1、0.3の場合和は0.7 どっちが誤差が小さいか?

 このような場合は全て二乗することで正のみとし、その後加算します。

誤差の大きさ指標=(ε1)^2+(ε2)^2+(ε3)^2+(ε4)^2

 

さてでは誤差の大きさ指標に先ほどの式①〜④を代入してみましょう。

誤差の大きさ指標

 =(Y1ー(αX1+β))^2

  +(Y2ー(αX2+β))^2

  +(Y3ー(αX3+β))^2

  +(Y4ー(αX4+β))^2

 

シグマ∑を使って整理すると⇓になります。

誤差の大きさ指標 ∑(ε^2) =∑(Yi − (αXi +β))^2

 

∑(Yi − (αXi +β))^2を後々のために展開するておきます。

∑( Yi^2 −2Yi(αXi +β)+(αXi +β)^2)

=∑( Yi^2 −2Yi(αXi +β)+(αXi)^2 +2αβXi + β^2)・・・⑤

 

誤差を最小にするためには式⑤の値が最小になればいいわけですね。

 

突然ですが、∑(ε^2) ≧0なので当然式⑤も0以上となります。これを利用して式⑤を最小とするα、βを求めることができるのです。

 

さて式⑤ ∑( Yi^2 −2Yi(αXi +β)+(αXi)^2 +2αβXi + β^2) は複雑に見えますね。でも求めたいα、βに着目すると、式⑤はα^2とβ^2を含んだ2次関数としてみることができます。常に0以上の2次関数ということはつまり下図のような「下に凸」として考えることができます。

f:id:public2015:20160630235513p:plain

2次関数における最小値を求める方法は微分が一般的です。微分によって接線の傾きを求め、傾き=0の点が最小となります。

 

式⑤は変数としてα、βの2つを持っています。このような関数の微分偏微分という大学で習う微分を用いる必要があります。偏微分?!まぁ身構えず気楽に行きましょう。

 

偏微分を簡単に言うと、

式⑤をαで偏微分するということは、α以外を定数として普通に微分すること。

式⑤をβで偏微分するということは、β以外を定数として普通に微分すること。

です。

 

さっそくやってみます。

∑( Yi^2 −2Yi(αXi +β)+(αXi)^2 +2αβXi + β^2)をαで偏微分すると

=∑( −2YiXi+2α(Xi)^2 +2βXi )

=−2∑( XiYi − αXi^2  − βXi )

 

これが0のとき誤差の大きさ指標 ∑(ε^2)は最小なので

−2∑( XiYi − αXi^2  − βXi )=0

∑( XiYi − αXi^2  − βXi )=0

α∑Xi^2  =∑( XiYi  − βXi )

α=∑( XiYi  − βXi ) / (∑Xi^2)・・・★1

 

 続いて

∑( Yi^2 −2Yi(αXi +β)+(αXi)^2 +2αβXi + β^2)をβで偏微分すると

=∑( −2Yi + 2αXi +2β )

=−2∑( Yi − αXi  − β )

 

同様にこれが0のとき誤差の大きさ指標 ∑(ε^2)は最小なので

∑( Yi − αXi  − β )=0

α∑Xi  =∑( Yi   − β )

α=∑( Yi   − β ) / ∑Xi  ・・・★2

 

うん。なんとか★1と★2を求められました。この2つを頑張ってα、βについて解くと、最小二乗法 - Wikipediaの下記公式を導出できます。

 

f:id:public2015:20160701002205p:plain

 上記式に、(X1,Y1)(X2,Y2)(X3,Y3)(X4,Y4)を代入し、

∑( XiYi)=X1Y1 + X2Y2 + X3Y3 + X4Y4

といった具合で一個づつ計算することでαとβを求めることができます。

切片0の近似直線がいい場合

さて頑張ってαとβを求めたわけですが、下の図なにか変です。

f:id:public2015:20160630222643p:plain

誤差量は人の歩く速度に比例して大きくなり、停止している場合(速度=0)は理論的には誤差量も0になるはずなんです。

 

このようにX=0のときYも0になるようなデータの場合、β=0、つまり切片0として近似直線を求めたいことがあるのです。

f:id:public2015:20160630222647p:plain

この場合は式★1(α=∑( XiYi  − βXi ) / (∑Xi^2))のβに0を代入し

α=∑( XiYi )  / (∑Xi^2)

でαを求めることができます。

まとめ

みなさんご存知のように、近似直線はエクセルの機能で求められます。なので中々理論に立ち返る機会は少なく、私はすぐ忘れてしまいます・・・。理解の助けになれば幸いです。

Linuxをメインマシンとして2年使って感じたこと。Windowsとの比較

 Linux debian 3.2.0@デスクトップ を約2年使用しました。

 

家庭でのLinuxの導入を考えている方々に向けて、実際に使用する中で感じたことをWindowsと比較してみます。

 

比較表の見方

◎・・・ほぼ全ての人が問題なく使える

◯・・・多少の知識を要求したり、若干の不便があるが十分使える

△・・・かなりの知識を要求したり、大きな不便があるがなんとか使える

✕・・・私の知る限りできない

メディア用途

f:id:public2015:20160629225625p:plain

 

映画を見たり音楽を聞いたりゲームをしたりといった用途の場合、Linuxは向いていません。i tunesとIEのみサポートのブラウザゲームハンゲーム?)は私の知る限りムリです。IE依存でないブラウザゲーム天鳳など)は問題なくプレイできます。

 

またHDMIは本来映像と音声を出力可能なインターフェイスなのですが、音声が出ないことがよくあるそうです。私の環境でも結局出せず、スピーカー端子を使用して音を出しています。

 

私の持っていたPCゲームは全てWindows用です。wineというツールを駆使するとLinuxでも使える(らしい)のですが、ゲームの起動画面までしか進めませんでした・・・。ちなみにwine自体は素晴らしいツールで、WindowsのexeをLinuxで実行できるようになります。シンプルなexe(tera term やエディタ)なら使えるものが多かったです。

 

オフィス用途f:id:public2015:20160629224730p:plain

オープンオフィスというOffice互換ソフトがあり、文書作成、表計算が可能です。機能面ではよく似ていますが、操作性は微妙に違いOfficeに慣れている場合若干ストレスを感じます。(例えばExcelのセル内での改行が、WindowsではAlt+Enter/LinuxではShift+Enterなど)慣れればレポート位なら問題なく作れますが、ピボットテーブルやマクロなど凝った機能を使用するとどこまで互換性があるか不明です。

 

文字化けは、Shift-JISやUTF-8といった文字コードの知識があれば回避できますが、知識なく使っていると「メールの本文が読めない」「添付ファイルが文字化けする」などが起きることがあります。Linux単体で使っている分にはあまり文字化けに出くわしません。Windowsとのデータのやり取りが増えると文字化け問題が増えます。

 

日常的に行なっている提携作業を自動化する場合、windowsだとbat(バッチ)やvbs(VBスクリプト)があります。Linuxの場合、シェル(debianではbash)があります。bashは標準で様々な機能を持っていて、さらにその機能の組み合わせ自由度も高くだいたいのことはできます。batやvbsは素人なこともありますが、同じ機能を作ろうとした際にbashの方が簡単だと個人的に感じています。

セキュリティ

f:id:public2015:20160629224733p:plain

システムとしての堅牢性ではなく、セキュリティに関する作業のしやすさを比較しています。Windowsのセキュリティアップデートはアップデート中操作不可になるため煩わしいです。その点Linuxはアップデート時に操作不可になることはほぼなく、ストレスなくセキュリティ更新ができます。

 

Adobe Flash Player(youtubeを見るのに必要)はわりとよく脆弱性が発見され更新されているのですが、Linuxでの更新作業は完全に手動のようで、ライブラリファイルを手で置き換えたり、対話式シェルを実行したりする必要があり煩わしいです。(私が知らないだけかもしれませんが)

 

ハードウェアの拡張性

f:id:public2015:20160629224736p:plain

Linuxを使う上で最大の難所が「ハードウェア拡張」だと思われます。CPUやHDD、有線LANなど、ほぼ全てのパソコンに共通するハードウェア部品に関してはかなり広くサポートしています。しかし無線LAN、プリンター、USB-LAN変換等の周辺機器はドライバがなければ使えません。機器を買った時についてくるドライバインストールディスクは間違いなくWindows用なので、Linuxのドライバはメーカーサイトか、オープンソースかから見つけてきて、さらにそれを自力でシステムに組み込む必要があります。

 

人気のディストリビューション(mintやubutnu)などの方が周辺機器への対応は進んでいることが多いように感じます。例えばdebianではUSB接続の無線LAN子機用ドライバは自分で探す必要がありましたが、ubuntuでは自動認識することがありました。

 

ソフトウェア開発

f:id:public2015:20160629224739p:plain

Linuxの最大の魅力の1つはソフトウェア開発がしやすい点だと思います。例えばeclipseを導入しようとした時、WindowsならWEB上を彷徨いjavaやらeclipse本体やらを自分で集めて来る必要がありますが、Linuxにはソフトウェア管理システムがあるため、

sudo apt-get install eclipse

と一行書けばインストールされます。ただし、debianのソフトウェア管理システムはデフォルトではかなり保守的なデータベースを参照しているためソフトの(この場合eclipseの)バージョンが古いことが多いです。どうしても最新版を使いたい時はWindowsと同様自分で入手・適用する必要があります。

 

またLinuxにはシェル(debianではbash)と呼ばれるソフトウェアが充実していて「フォルダ内の画像全ての名前を変更する」「ファイルの中から特定の情報だけ取り出す」などが簡単に行なえます。人手だと時間のかかる作業を簡単に行えるためとても便利です。

 

コストパフォーマンス

f:id:public2015:20160629233900p:plain

お金についてはオープンソースであるLinuxの圧勝です。また古いパソコンを使う場合、Linuxであれば軽量ディストリビューションを選択することで低スペックパソコンでもサクサク動作するようになります。また各ディストリビューションの最低要求スペックがあれば多少古いパソコンでもサクサク動きます。

 

一方学習コストについては、敷居が下がったとは言えまだ高いと思います。パソコンやネットワークといったIT一般に明るく、根気がないとなかなか続けられません。ただ知識をつけLinuxに慣れてしまえば、よく手に馴染む使いやすい道具となるので学習する価値は十分あります。

 

まとめ

私はパソコンを新調した際にOS代をけちってLinuxに移行しました。なにかと不便はありますが概ね良好で、案外なんとかなるものです。Windows10騒動も我関せずでしたしね。

 

結局WindowsLinuxも素晴らしいOSということです(?)

ラッパー関数とは?メリットと使いドコロ

ラッパー関数、ラップ関数、または単にラッパー等、色々な呼ばれますが、ここでは「ラッパー関数」で統一します。

ラッパー関数のラッパーはwrap【包む】から来ています。もともとある関数を包む関数、それがラッパー関数です。

今回はラッパー関数の使いドコロをまとめたいと思います。

最初に包まれる関数たちを紹介します。サンプルコードはC/C++で記述します。

//nano単位でsleepする
int nanosleep(const struct timespec *req, struct timespec *rem); 
//時刻time_tを渡すと時刻を表す文字列を返す 
char *ctime_r(const time_t *timep, char *buf);

ラッパー関数の役割①呼び出しの簡略化

nanosleepの簡略化

nanosleepの呼び出しにはtimespec構造体が必要です。引数に構造体を指定する関数はそれだけで使いにくくなりがちです。さらに個人的にはナノ単位よりも秒単位の方が好きですし一般的なので秒表示にします。以下のように「引数を簡略化」「単位を変更」したラッパー関数を作りました。

int my_sleep(double sec)
{
    double  integer;
    double  fraction;
    fraction = modf(sec, &integer);
    struct timespec req={(int)integer,(int)(fraction*1000*1000*1000)};
    return nanosleep(&req, NULL);
}
    //呼び出し元
    //my_sleep(1.5);

ctime_rの簡略化

ctime_rとはctimeのスレッドセーフ版です。スレッドセーフにするために作業用データ領域を第二引数で渡しています。引数が増えるとそれだけで呼び出しをためらってしまいます・・・。またctime_rは戻り値で文字列を返してきますが、このような関数は文字列メモリをライブラリ内で管理しているため戻り値をいつまでも保持しておくことはできません。戻り値は実行したその行でのみしか正しいと保証されていません。以下のように「引数を簡略化」「文字列メモリの管理をライブラリから呼び出し元に変更」したラッパー関数を作りました。

void get_time_str(char *p_data,int size)
{
    time_t timer;
    time(&timer);
    char buf[256];
    strncpy(p_data,ctime_r(&timer,buf),size);
}

    //呼び出し元
    //char aaa[256];
    //get_time_str(aaa,256);
    //printf("%s\n", aaa);

ラッパー関数の役割②異常処理の統一

nanosleepの異常処理

nanosleepの戻り値は関数実行の成否を示しています。仕様は以下です。

呼び出しがシグナルハンドラーにより割り込まれた場合、 nanosleep は -1 を返し、 errno に EINTR を設定

例えばC++でnanosleepを使用する場合を想定しますと、C++は異常を通知する仕組みとして例外があります。C++で普通に書くならば(コーディング規約で例外禁止でないなら)異常は適切に例外を送出するべきです。戻り値での異常通知と例外での異常通知を混在させると、特に戻り値での異常通知が無視されてしまいがちです。

  //引数を見ていないため、失敗していても気付けない!
  nanosleep(timespec,null);

このような事態を避けるために「異常を例外化」したラッパーを作りました。この変更によって戻り値で戻すものがなくなったため、void型に変更しています。

void my_sleep(double sec)
{
    double  integer;
    double  fraction;
    char buf[256];
    fraction = modf(sec, &integer);
    struct timespec req={(int)integer,(int)(fraction*1000*1000*1000)};
    if(nanosleep(&req, NULL) == -1)
    {
         strncpy(buf,strerror(errno),256);
         throw std::runtime_error(buf);
     }
}
    //呼び出し元
    //my_sleep(1.5);

ラッパー関数の役割③プラットフォームの違いを吸収する

実はスリープする関数はWindowsLinuxで関数名が違います。my_sleepはlinuxのライブラリを使用しているため、このままではWindows(VCやVC++)ではコンパイルできません。まぁ殆どの場合それで困らないのですが、環境マクロを使うことで実行するプログラムを分けることができ、ラッパー関数は環境マクロで分類するのに適したレイヤーです。

Windows側のコードは未検証です。

int my_sleep(double sec)
{
#ifdef _WIN32
    //Windows
    int ms=(int)(sec*1000);
    Sleep(ms);
#else
    //Linux
    double  integer;
    double  fraction;
    char buf[256];
    fraction = modf(sec, &integer);
    struct timespec req={(int)integer,(int)(fraction*1000*1000*1000)};
    if(nanosleep(&req, NULL) == -1)
     {
         strncpy(buf,strerror(errno),256);
          throw std::runtime_error(buf);
     }
#endif
}

ラッパー関数の役割④機能の付加

どちらかと言えばラッパー関数を作る際は引数を隠蔽するなど機能を削ることが多い気がしますが、逆に機能を付加することもできます。例えばprintfに何か文字を追加するなどが考えられます。以下は単純に「debug!!」を付加しているだけすが、ファイル名、行番号、時間等を付加することで汎用的なログ化することもできます。ファイルディスクリプタをstdoutにするとprintfの用に振るまい、ファイルポインタを指定するとファイルに出力できます。

void debug_printf(FILE *fp, const char* format, ...){
  va_list arg;
  va_start(arg, format);
  char buf[1024];
  sprintf(buf,"debug!! %s",format);
  vfprintf(fp, buf, arg); 
  va_end(arg);
}
 //debug_printf(stdout,"aaa %d",10);

ラッパー関数の役割⑤名前の変更

分かりにくい名前のライブラリ関数の名前を変えます。上で既にあげていますが、ctime関数のままだと多少分かりにくいのでget_time_strに変更しています。

void get_time_str(char *p_data,int size)
{
    time_t timer;
    time(&timer);
    char buf[256];
    strncpy(p_data,ctime_r(&timer,buf),size);
}

まとめ

ラッパー関数はライブラリの機能に手を加えずに変更をかけられるため便利なテクニックです。ただし実行時はオーバーヘッドになるため、速度的に若干不利になります。またラッパー関数をまたラッパーして、またラッパーして・・・と複数ネストしてしまうと逆にわかりにくくなってしまうため、ラップする目的を決めて設計することが大事ですね。

高得点で合格するための電験三種の過去問の使い方 

私は電験三種のために7ヶ月勉強し本番では4科目とも80点以上を取り、比較的余裕のある一発合格をしました。今回は電験三種の過去問の取り組み方について焦点を当て、私が実施した方法をまとめたいと思います。

 

 なおオススメ参考書や勉強方法全般については電験三種カテゴリにまとめてますのでよろしければご覧ください。

 

過去問も色々あるけどどれがいいの?

最新の問題を含んだ10年分を買えば間違いありません。10年分の過去問も何社かから販売されていますが、解説ページの読みやすさで選択しましょう。読みやすさのポイントは解説が難しすぎると感じないかです。変に見栄を張らずに分かりやすいものを選ぶことが大切です。

 

過去問はいつやるべき?

過去問をやろうかなぁと思った時、まず疑問に浮かぶのはいつから過去問に取り組めばいいんだろう?ということではないでしょうか

・まず最初に過去問をやるべきなのか

・参考書を1周読んでからやるべきなのか

・基礎を完璧にしてからやるべきなのか

 

私は参考書を「おおよそ」1周読んでから取り組むのが良いと考えています。

 

参考書を初見で100%理解することは難しいです。もし100%理解しながら読み進めようとすると膨大な時間がかかってしまいます。かといって分からない部分を全て後回しにしながら進めると、1周読んでもほとんど理解できていない状態になってしまいます。

 

なので出来る限り理解しながら読み進め、どうしても分からない箇所は付箋などを貼って次に進むのがいいと思います。付箋が10箇所以内だと「何箇所かわからないけど、だいたいわかった」程度の理解となります。

 

そこまで理解が進んでから過去問に取り組むと問題文を理解でき、ものによっては正答出来る状態のはずです。

 

何に気をつけて過去問に取り組めばいい?

最も重要なことは間違えた問題だけでなく、その問題に関連した分野まで広げてやり直すことです。間違えた問題だけをやり直していると、”点”でしか知識が増えないため中々定着しません。

 

具体的には電力で原子力発電に関する問題を間違えたなら、

①関連する分野を確認する

発電にはどんな種類があるのか(火力・水力・原子力など)確認する。

 

②その分野をしっかりやり直す

原子力発電の種類や基本原理、利点と問題点を確認する。

 

③間違えた問題を解き直す。

過去問の間違えた問題をやり直します。復習直後なので問題なく解けるはずです。

 

このやり方は時間がかかりますが、何度も復習できるため記憶の定着が良いです。参考書をやり直しても、その分野を理解できない場合は付箋を貼って次に進みましょう。

 

何年分やる?

10年分やれば十分だと思います。逆にいうと10年分しかないため貴重です。無駄なくやり切る必要があります。

 

私が実施した方法は最初の5年分は時間を計らずに解く。残りの5年分は時間を計って時間内に解ききる練習をしました。

 

最初から時間に拘ると、時間切れで解けなかったのか、実力が無くて解けなかったのかわからないままになってしまいます。なので時間をかけてでも自分がどの程度解けるのかを知っておくことは重要です。

 

それ以外に気をつけたことは、最初の5年分は奇数年、残りの5年分は偶数年で分けて取り組んだことです。

 

つまり時間を計らずに2004年、2006年、2008年、2010年、2012年の過去問を解き、時間を計って2003年、2005年、2007年、2009年2011年の過去問を解きました。

 

このように実施することで問題の流行りや難易度のばらつきをできるだけ抑えることができ、バランスよく10年分を使えます。

 

10年分やりおわったらどうするの?

 私の述べた方法で取り組むと10年分実施するのに3ヶ月近くかかるかもしれません。やり終えた後については10年分解いた段階での仕上がり具合によって変わってきます。

①時間を計って解いて70点以上安定して取れる場合

合格圏内に到達しています。過去問の2周目は間違えた問題だけやれば十分です。ここで間違えたり、悩んだりするならもう一度その分野を復習しましょう。

 

また余力があれば予想問題集をやるのも良いですが、難易度としては予想問題の方が3割増しで難しいため、予想外に低い点数を取ってしまい自信を無くすことになるかもしれません。あまり必要ないと思います。

②70点以下を取ることが多い場合

まだ実力が足りておらず、合格ライン上〜圏外にいます。70点以下の場合はいわゆる頻出分野を抑えられていないと思われます。

理論なら電気回路

機械なら各種電動機・発電機

電力なら各種発電等が頻出です。10年分やれば頻出分野も自ずと見えてくるでしょう。

頻出分野に絞った学習に切り替え、十分復習した後もう一度過去問に取り組みましょう。

 まとめ

本試験の傾向も時間とともに変わるため、過去問は直近10年分の価値が高いです。この10年分をしっかり計画的にやり切ることが大切です。なんとなくやるのではなく、この年の過去問は「時間を計らずに徹底的に解ききる」とか「時間内に絶対に終わらす」という意志を持って取り組むことで、過去問から得られるものが増えるはずです。

 

また過去問の解説だけを読んで分かったような気になって先に進むと、知識の抜け漏れが起きやすいです。よって間違えた問題は必ず参考書まで戻って復習すること、これが高得点合格の最大のポイントだと考えています。以上勉強中の皆様の参考になれば幸いです。

プログラム言語変換ソフトによる開発効率UPのススメ 

最近のプログラマ事情

近年のソフトウェア開発はゼロからフルスクラッチで作ることは稀です。ほとんどの場合、既に運用されているシステムに機能を拡張する・機能を追加するといった派生開発ではないでしょうか。

 

そのため開発で使用する環境は既に運用されているモノを踏襲するため、フレームワークプログラミング言語の選択はプロジェクトによって決まってしまいます。

 

いくら「Javaがいいんだ!Javaをやらせろ!」と叫んでも、無情にC言語プロジェクトに投入されたりするわけです。私の場合、希望していないのですがC言語C++PerlPythonRubyC#等など多数の言語での開発を経験しました。

 

さて、多数の言語で開発していると特に感じることとしてプログラム資産を共通化しにくいと言うことがあります。

 

例えば「以前にC++で実装した設定ファイルを読み書きするちょっとしたクラス、あれを今回のC#プロジェクトでも使いたいな〜」という場合に、私はC++のコードをじーっと見つめて、C#の文法で書き直していたりしたわけです。

 

プログラム言語変換ソフト【SWIG】を使おう

結論からいうと【SWIG】というOSSC/C++ソースコード食わせると、PerlPythonRubyC#Java等の別言語用のソースコードを吐いてくれるのです。

サポート言語

現在は23言語に対応しているようです。

        Allegro CL
        C#
        CFFI
        CLISP
        Chicken
        D
        Go
        Guile
        Java
        Javascript
        Lua
        Modula-3
        Mzscheme
        OCAML
        Octave
        Perl
        PHP
        Python
        R
        Ruby
        Scilab
        Tcl
        UFFI

SWIGの歴史

SWIGの歴史は長く、Ver1のリリースは1996年で、当時 はTcl、PerlPythonへの変換をサポートしていました。その後も活発に開発が続けられ、2010年にはVer2をリリースしています。そして 2014年でついにVer3になり、サポート言語も増え続けています。

ライセンス

SWIGのライセンスはGPLと、ユタ大学とカリフォルニア大学の大学ライセンスです。

The University of Utah and the Regents of the University of California
All Rights Reserved

世間での使用例

SWIGを使用した有名なOSSも数多くあります。SubversionOpenCV等もSWIGを使っているようです。メジャーなOSSで使用されていると信頼感が上がりますよね。

 

開発者向けドキュメント

使用者向けドキュメントは残念ながら英語のみですが、各言語ごとに豊富な解説とサンプルが載っています。

 

引数や戻り値が無い、またはint等の組込み型のみで構成されいる関数を別言語から呼び出すのは非常に簡単で、英語ドキュメントを読みこまなくてもWEB上の情報だけで実現できます。

void reset(void); //別言語から簡単に呼び出せる

 

この英語ドキュメントの熟読が必要な場合として以下のようにポインタで値を返す場合や

void getData(int* out); //別言語から呼ぶためのインターフェイス設定が必要

 

例えばC++からは呼び出す場合はAuto/Manualモードを設定できるけどC#から呼ばれたときはManualのみに制限したい場合といった

void setMode(int mode) //C++ではAuto/Manualを通過/C#ではAutoを弾く

 

言語間の調整が必要な場合、英語ドキュメントを熟読しないと実現できません。

 

環境構築&Tips

需要がありそうなら後々まとめます。

 

まとめ

業務上複数のプログラム言語を使う場合、プログラム資産をきちんと残すことが難しくなってしまいます。そんな時役に立つ言語変換ツール【SWIG】の紹介でした。

国語が苦手でも小論文試験(昇進・昇格試験)に合格できる勉強方法

私の勤務している会社では年に1度昇進試験があります。

 

試験としては業務に関する小論文、その他いくつかの筆記試験と面接があり、これら全てに合格すると年収で100万程度アップします。この試験を合格すると以後の昇進は非試験となりますが、逆に受からないといつまでも平社員のままで昇進しませんし、毎年試験を受けなければなりません。

 

合格率は15%程度で、1年目で受かる人もいれば20年目のベテランでも受かっていない人もいて、社内の評判としては【難しい試験】。皆が一様に声を揃えて「小論文が難しい」と言います。

 

私はこの試験を約3ヶ月の勉強で1年目で合格しました。

 

一般的に小論文試験を合格するためには国語スキルが必要と言われていますが、私の国語スキルは非常に低いです。あまり本を読まないため語彙力がなく、加えて人との関わりを避けがちだったため基本的なコミュニ ケーション(特に順序立てて説明すること)にも難があります。しかし幸いなことに小論文試験ではコミュニケーションが下手でも、多少日本語が不自由でも、押 さえるべきポイントを押さえることで合格できます。 

 

今回は実際に私の行った「国語が苦手でも合格できる勉強法」をお伝えしたいと思います。

 

【小論文試験(昇進試験)の分析】

試験まで十分時間が取れるならば国語力を底上げする方法が本質的で良い方法だと思います。しかし多くの方は仕事や育児が忙しく十分な時間が取れないのではないでしょうか。そのような場合【分析】は非常に有効です。自分の会社の小論文試験は受かるかもしれないけど、それ以外の小論は全くダメダメ状態、そんな状態を目指しましょう。

 

★合格レベルの小論文の分析

まず可能な限り合格者の論文を集めましょう。といってもなかなか集まるものではなく、私は2件しか集められませんでした。しかし2件でも集められれば有用なデータです。どのような内容が書かれているのか、どこが骨子か、題意にどのように答えているか、10回、20回読み込んで完全に理解しましょう。

 

私の入手した2件はそれぞれ

(1)自分の実施した施策が非常に効果的だったという【事実】を全面に出す論文

(2)自分の【考え】を全面に出し、その考えに基づき業務の中で〜という具体的な行動をした

という対象的なものでした。合格レベルの論文には優れた【事実】か、説得力があり可能性を感じる【考え】かが必要だと考えました。これを受け自分の方針を決めるのですが、自分の場合は勤続年数が短く具体的で強力な【事実】は持っていなかったため【考え】を全面に打ち出していく方針を選びました。逆に言えば【事実】を最小限に押さえるように気をつけたとも言えます。

 

練習で様々なお題について論文を書きましたが、文章全体の【事実】と【考え】のバランスは論文の完成度を高める上で非常に重要でした。基本的には人柄を見る試験なので【考え】に重点を置くべきだと思います。逆に【事実】を全面に出す方針は難易度が高いと思われます。「小論文なんだから考えを書くのは当然だろ?」と思われるかもしれませんが、実際に書いてみると前提条件の説明や、具体例、手順などを書きがちで、これらは【弱い事実の集合】なので結果的に完成度の低い小論文になってしまいます。

 

私の場合は合格論文(2)を目指し、自分の書いた論文との差異を分析し、差がなくなるように詰めていきました。

 

★小論文の問題(テーマ)の傾向を分析

私の勤務する会社の場合、問題の一例は以下のようでした。

 

(1)会社がこれからも価値を高めるためにはどうすればよいと思うか

(2)周囲の人を巻き込んで何をしたか

(3)会社にとって危機は何か。あなたはどう備えるか。

 

私はこれらの問題は全て【会社の成長ためにあなたはどう考え、どう行動したのか、行動していくのか】という1つのパターンに集約できると考えました。 おそらく良くあるテーマ設定なのではないでしょうか。

 

このようなテーマ設定では【会社の成長】と【自分の考え・行動】を繋げる必要があります。一般的にこの2つの接着剤は経営方針です。社長の言葉を調べることで、会社の長期的な目標が見えるはずです。例えば事業の多角化を推進するだとか、コストダウンによって競争力を底上げするだとか。社長の言葉は社員向けのものより、株主向けのものの方が具体的で分かりやすい場合が多いので、株主向けの方針説明資料を探しましょう。

 

経営方針をうまく小論に取り入れると、それだけで高い視点から全体を捉えている雰囲気を醸し出せます。

 

例えば

(1)会社がこれからも価値を高めるためにはどうすればよいと思うか

 価値を高めるためには〜といった理由からXXXが必要だ。そのためには一層のコストダウンが求められている。そこで私は〜を達成するために〜を検討し、結果〜くらいのコストダウンを実現した。

 

(2)周囲の人を巻き込んで何をしたか

 〜という理由で、会社が成長していくためにはコストダウンによって競争力を増すことが有効だ。しかし私の職場には〜という問題があり、それによって〜工程のコストが大きくなることがあった。そこで〜と連携し、この工程の〜改善を実施し、コストダウンを実現した。

 

(3)会社にとって危機は何か。あなたはどう備えるか。

 会社にとって危機は〜だ。近年〜は〜で〜だ。この危機に対処するためには〜。よって全社一体での総合的なコストダウンが必要だと考えた。そこで私は〜な理由で関連部門との一層の連携が必要だと考え、〜を実施した。それによって部門間で〜を共通化でき、〜工程のコストダウンを実現した。

 

【会社の成長ためにあなたはどう考え、どう行動したのか、行動していくのか】という問題のパターンに対する解のひとつは【経営方針に沿って問題に応え、自分の考え・行動に繋げる】ことだと言えるのではないでしょうか。よって経営方針をよく理解し、それぞれの方針について自分との関わりを整理しておくと良いと思います。

 

【実践】

さて、いよいよ実際に筆を進めましょう。小論試験では「なにも書くネタがない〜」ということをよく聞きます。ほとんどの場合そのように言う人は、過去に自分がやったことからネタを探しています。しかしそのやり方は危険です。上で述べた【問題の分析】と重複しますが、業務系小論文の場合は「会社の方針」「経営目標」ありきで考え、それに繋げられるネタを探すべきです。

 

会社の方針を理解し、自分の経験と照らし合わせいくつかストーリーはできましたか?まず下手くそでもいいのでそのストーリーを小論文として書き上げましょう。話はそれからです。

 

★自分の文章の癖を知り修正する

 自分の文章の癖は自分自身ではなかなか発見できません。この点に関しては上司・友人・家族に小論を見てもらい、「どんな印象を受けるか」「分かりにくい箇所はどこか」と言う観点でアドバイスをもらうことをおすすめします。内容についてがっつり意見をもらうというよりは、文章の雰囲気を見てもらうことを期待しているため、気楽に話せて、あまり忙し過ぎない人に見てもらうといいと思います。私の場合は妻に見てもらい、以下のようなアドバイスを得ました。

 

・なんとなくネガティブな印象を受ける

・文章の繋がりが悪く、内容が頭に入ってこない

・淡白な印象で、盛り上がりに欠ける。眠くなる。

 

これに対して原因を追求していく。

・なんとなくネガティブな印象を受ける

 余計な一言が多い。例えば「本来は〜すべきだったが、〜によってできなかった」といった できなかった情報を付けがち。

 

・文章の繋がりが悪く、内容が頭に入ってこない

 接続詞を使っていないため文章がぶつ切りになり読みにくいケースや、くどい説明によって大事な主張が隠れてしまうケースがありました。「しかし」「つまり」「よって」等をうまく使えていない箇所もありました。

 

・淡白な印象で、盛り上がりに欠ける。眠くなる。

 【事実】と【考え】のバランスで、【事実】が多い場合に淡白になるがちです。さらにその事実が説明などの【弱い事実の羅列】だとこれまたつまらないものになってしまいます。また考えの根拠が弱かったり、当たり前の主張だけだと盛り上がりの無い文章になってしまいます。

 

まずは自分の文章の癖を発見することが重要です。そのためには他者の目が有効です。

 

最近ならウェブで簡単に添削できるサービスもあるみたいですね。

coconala.com

 

★「題意に沿った」論文を書けるようにする

3割〜4割の受験者は題意に沿っていない小論文を書いてしまい、確定不合格となってしまっているそうです。つまり題意に沿って書き上げられれば、それだけで合格可能性が上がります。具体的には全体で合格率15%の試験において、題意に沿っていないため不合格が40%だとすると、題意に沿っている小論文の合格率は15/60で25%まで上がるんです。

 

しかし題意に沿っていても肝心の内容がお粗末ではいけません。題意に沿ってなおかつある程度の内容が書ける受験者は半分程度だとすると、その受験者の合格率はなんと15/30で50%まで上がります。

 

つまり題意に沿って、なおかつある程度の内容がかければ2〜3年間での合格率は85%まで上がるのです。

 

よって小論文試験においては、題意に沿うことはスタートラインで、絶対に外してはいけないポイントなのです。

 

さて題意に沿った小論文を書くためには何が必要なのでしょうか。 

 

答えは【全体構成をしっかり考える】ことです。理想的には小論文を書き始めてから殆ど筆を止めずに書き上げられるような全体構成が望ましいです。

 

つまり全体構成は小論に登場する【要素】と、その要素間の【繋がり】を正確かつ十分に含んでいる必要があります。

 

このレベルの全体構成を書けると、小論文を書き始める前にそれを見ながら題意に沿っているかどうかといった確認が可能になります。このひと手間で題意に沿っていない→確定不合格をかなり回避できるはずです。

 

試験時間にもよりますが、私の場合は最初の30分を全体構成に充てると決めて試験に臨みました。

 

最初は全体構成を書いても、小論文を書き始めるとすぐに筆が止まると思います。私はそうでした。そのようなとき、なぜ今筆が止まったのか、逆にどのようなことを予め考えていれば止まらなかったのかということを意識し、少しずつ構成力を磨いていくことで構成力はアップしていきます。

 

 ★内容のブラッシュアップ

 さて自分の文章の癖を修正しマシな日本語になり、題意に沿って書けるようになっても結局内容がお粗末であれば合格は難しいです。ブラッシュアップは絶対に避けては通れないでしょう。

 

この段階では上司に添削を依頼することが最も効率的です。上司はつまらないこと(日本語が変だとか、題意に沿っていないだとか)に惑わされず、真っ直ぐに小論文の主張を理解し、有用なアドバイスをくれるでしょう。

 

逆に言えば、日本語が変だとか、題意に沿っていないだとかというレベルのものを添削してもらっても、内容のブラッシュアップまでは到達できないと言えます。

 

上司に見せずに自分でブラッシュアップすることもできなくはないですが、有効性は下がります。会社によってカラーも違いますし、上司の意見を聞くことは1度はすべきと思います。

 

 【総仕上げ】

意外と忘れがちなのが、時間内に書き上げなければ意味がない、ということです。時間を計って論文を書く練習は欠かせません。

 

私は手書き試験だったため本番までに15本程度時間を計って書きましたが、15本目では最初より30分程度早くかけるようになっていました。論文試験は時間との戦いでもあるので、このスキルアップは本当に有効です。

 

【まとめ】

約3ヶ月間、毎日2時間程度(直前の土日はフル)この昇給試験にかけ、なんとか合格はしましたが、はっきり言って余裕はありませんでした。基本的な国語力は低いままなので試験の傾向ががらっと変わったら全く対応できませんしね。

 

この試験において勝敗を分けたのは【他者の目】を積極的に活用したことだと思います。自分の書いた文章を人に見せ、ダメ出しをされるというのは私にとっては苦痛でしたが、早期から妻の協力を得たこと、何度も上司に添削を依頼したことが最も大きなポイントだったと感じています。

 

読んでくださった方の一助となれば幸いです。