2014年2月23日日曜日

ファイル

ハードディスクなどのストレージ上のデータを扱うのにファイルを使用するというのは多くの人が知っていることだと思います。

プログラミングにおいては、ファイルはもっと大きな意味を持っています。何度かコンピュータの基本は、CPUとメモリとI/Oという話をしていますが、ファイルはI/Oを抽象化して理解しやすくするために使います。

I/Oはディスプレイや、キーボードやハードディスクなどのデバイスが繋がっており、これらのデバイスとデータのやりとりをするのに、ファイルという概念を使用します。

例えば、C言語において、printf()の画面表示は、fprintf()でstdoutのファイルに書き込みをするのと同じ意味をもっています。このように画面表示もファイルとして扱っています。

Windowsでも似たような概念はありますが、Linuxではデバイスをファイルとして抽象化することが徹底されています(Plan9というOSの影響が大きいそうです)。

例えば、/dev/sdaはハードディスク自体で、/dev/sda1はパーティション、というようにファイルで表現されています。CPUも/proc/cpuinfoというファイルになっており、このファイルの中身を見ることでCPUの色々な情報を見ることができるようになっています。

そういう事もあり、ファイルという存在はコンピュータにとって非常に重要な存在であり、そのファイルを扱うソフトウェアのExplorer(Windowsの場合)は重要な役目を持っていました。



しかし、プログラマにとっては理解しやすいように作られたファイルも、コンピュータに詳しくない人には理解がしづらいものらしく、Explorerを使うことができない人もいるようです。

一時期アプリ中心からファイル中心の考え方にシフトしようとした時期がありました。例えばワープロで文書を作る場合に以下の二通りの作り方があります。
  • メニューからワープロソフトを起動する→文書を保存する
  • 文書ファイルを作る→文書ファイルからワープロソフトを起動する。
この後者の考え方にしようとしたのです。しかし、結局はうまく行かず、今では完全に前者が主流となっています。最近のスマホやタブレットでは、ファイルの存在をユーザーには見えないようにしていきつつあります。

プログラマにとっては必須のファイルは、今後はユーザー視点からは消えていくことになりそうです。

Chromium OSを試してみる

Windowsの代わりとしてMac OSやLinuxだけでなく、Google Chrome OSというOSが存在しています。

このChrome OSは、以下のような特徴があります。
  • ブラウザに機能を絞っている
  • Googleのサービスに頼っている
  • 機能を絞っているので速い
  • 機能を絞っているのでセキュリティに強い
  • アップデートが容易
  • 安い
このOSを乗せたChromebookが米国の法人市場で2013年11月に9.6%のシェアを獲得したそうです

この数字はAndroidタブレットの8.7%を凌ぐものとなっています。

Chrome OSのフリーソフト版であるChromium OSが存在し、Chromebookのような専用ハードで無く、普通のPCでも使えるようになっています。今は日本では発売もされておらず有名ではないですが、今後成長する可能性もあり、古いPCで使ってみるのも良いかと思います。


以下のサイトから、USBメモリから起動するためのイメージや、VirtualBoxの仮想環境で動作させるためのイメージがダウンロードできます。

http://chromeos.hexxeh.net/
http://chromium.arnoldthebat.co.uk/

私はEee PC 901-Xを持っているのですが残念ながら、どちらのUSBメモリ用のイメージもkernel panicになってしまい、動作しませんでした。Eee PC 1015PEMでは動作するようなのですが

USBメモリへのイメージの書き込みはRaspberry Piでの記事で紹介した、 Win32 Disk Imagerで出来ますので、挑戦してみてください。

私はVirtualBox上で動かしてみました(古いPCは使えませんでしたが)。ただしViratulBoxもhttp://chromeos.hexxeh.net/側のイメージしか使えませんでした。こちらのほうが少し古いです。

Viratual Box の新規でダウンロードしたvdiファイルを選択するとChromius OS の環境ができます。たぶんタイプはUbuntuで良いと思われます。





作成したら、起動します。最初に言語を設定します。日本語にも対応しています。ただマウスが正しく動きませんでした。ViratualBoxのメニューの「仮想マシン」-「マウス統合の無効化」をしてください。


次にGoogleのアカウントでログインします。


アカウントの画像を選択します。



画面が起動します。


キー入力の設定において、日本語入力にmozcを使用することができます。mozcはGoogle日本語入力のフリー版で、非常によい日本語変換ができるようになっています。







Ctrl+Alt+Tキーを押すと、croshという、コンソールが環境が起動します。ここでshellと入力すると、通常のLinuxのシェルのようなものが使えるようになります。

Googleのサービスをよく利用している人、ネット利用が主なPCの用途の人にはそれなりに使えるのではないかと思います。一度お試しください。


なお、私のPCでは動きませんでしたが、もしかすると自分でビルドをすれば動かすことも出来るのかもしれません。以下の環境で自分でChromium OSがビルドができるようです。
  • Ubnutu 12.04 LTS(64bit版)
  • メモリ 4Gバイト以上
  • ストレージ 10GB以上の空き容量
日経Linux 2013年12月号にて、Chrimoum OSのビルドの仕方や、その他の設定方法について書かれているので、力のある人は試してみてはいかがでしょうか。

2014年2月16日日曜日

大画面のスマートフォン

Nexus 5は、約5インチ(正確には4.95インチ)と大型の画面サイズのスマホとなっています。大画面になると片手で使えず不便という話があります。

私も男としては手の大きさはそれほど大きくはありません(だいたい手の付け根から中指の先までが7.5cmほどです)。そのため、私も正直Nexus 5ほどの大画面は必要なく、できればもっと小さい画面のスマホが欲しいと思っていました。しかし、SIMフリーであること、価格が安いこと、OSのアップデートが期待できること、などの利点からNexus 5の購入を決めました。

実際に使ってみて、最初は確かに使いにくかったです。しかし、現在では思ったより片手で使えるという印象があります。もちろん全ての操作は無理ですが。

例えば、最近のアプリはナビゲーションドロワーという左側から引き出すメニューがよく使われています。下はGoogle Mapでのナビゲーションドロワー表示画面です。



これは左上のアイコンをタップすることでも表示できるのですが、どこか左端を掴んで引っ張ることで表示することもできます。この方法では、無理に左上のボタンを押す必要がなくなっています。

また、Nexus 5標準のIMEでは日本語変換は手が小さいと大変ですが、Google日本語入力であれば下のように左寄せにすることができます(右寄せもできます)。このように設定することで、文字の打ち間違いが少なくなりました。


2013年のベストアプリでSmartNewsというアプリがあるのですが、これは操作方法もフリックメインで非常によく出来ており大画面であっても片手で操作しやすいです。全ての操作を片手で行うのは無理ですが、必要な時のみ両手を使えばいいと感じました。


結局のところ、大画面が片手で使いやすいかどうかはアプリ次第ではないかと感じました。Nexus 5の表示は非常に綺麗で、広い画面は効果的で良かったのではないかと思います。


ここから大画面とは少し関係がなくなりますが、むしろ必要無いのは、1920×1080のHDの解像度だったと思います。確かに解像度は細かければ細かいほど良いです。しかし必要以上なスペックは速度やバッテリーに悪影響なだけです。個人的な事ですが、私は目が悪いということもあって「細かい文字が読める」と宣伝されても小さい文字を読む気にはなれません。Nexus 5は特にバッテリーの持ちが良くなく、無理な解像度だったと感じます。

iPhoneも6インチが出るなどの噂がありますが、実際はどうでしょう?Androidと違い、解像度に柔軟性のない今のiPhoneの仕組みでは大画面化は非常に難しいと思われます。

今の9.7インチのiPadは、現在主流の縦横比である16:9にしようとして2731×1536ドットとすると丁度12インチぐらいになります(iPhone5のときのように従来のアプリは左右が黒くなりますが)。そのためiPadの12インチは出そうな気がします。

しかしiPhoneで6インチ版が出るとしたら、私では従来のアプリは真ん中に表示するか、拡大表示するぐらいしか方法が思いつず、見た目も使い勝手が悪くなりそうです。ですが、なんとかして大画面でも片手で使いやすいようにUIを大幅変更するのでは無いでしょうか。

2014年2月15日土曜日

WindowsからLinuxへの移行

世の中、ほとんどの人はOSはWindowsを使っていると思いますが、私はLinuxデスクトップのFedoraを使っています。私も昔はWindowsを使用していました。なぜLinuxを使用しようとしたか?理由は今サポート切れで話題になっているWindows XPが原因の一つでした。

Windows XPでは、アクティベーションというネットワーク等で認証をしなければインストールが出来ないという仕組みが初めて入ったWindowsでした。この仕組みは確かに海賊版を防ぐという目的には良いのですが、Microsoftが認証をしてくれなくなったら、自分の意志とは関係なく使えなくなるのでは無いかという不安があったためでした。

どうやらその不安は当たったようで、サポート切れ間近となった今もMicrosoftはWindows XPのアクティベーションをどのようにするかの発表は特にないようです。噂では2017年までは認証サーバーが動作するなどの話もあるようですが、どうなるのでしょう?

個人的にはサポート切れよりもアクティベーションがどうなるかの方が気になります。サポート切れになった場合、ネットに繋がない、ウィルスに感染したら再インストールと言う手もありますが、アクティベーションでインストールができなくなったら元も子もないです。

WindowsからLinuxへの移行は個人的には非常に良かったと思っています。Windows XPのサポート終了にともない、Linuxデスクトップが気になる人もいると思いますので参考にLinuxへの移行について書いてみます。



1.第一の難関、インストールを越えられるか?


ほとんどの方はWindowsが最初から入っている状態でPCを買っていて、OSのインストールはしたことが無いと思います。OSのインストールはそれほど難しくはないのですが、やはり多少の知識が必要です。それを苦と思うのであれば、Linuxは使用しない方が良いかと思います。

2.自作派には向いているかも


自作派の人はイントールはもちろんできると思いますが、さらにHDDを交換してLinuxを試すといったハードウェアまで含めた作業が出来るのが強みだと思います。また、自作の場合はWindowsも別途購入する必要があるので、その購入費用を抑えることもできます。

3.何に使うか?


WindowsやLinuxも道具の一つでしかありません。自分のしたいことが出来なくては意味がないでしょう。Windowsで動くソフトウェアはLinuxでは動かないので、そのソフトウェアがどうしても使いたい場合はLinuxは使用できません。Windowsのソフトウェアを動かすためのWineというソフトがありますが、あまり期待しない方がいいです。

しかし、インターネット使用であればFirefoxやGoogle ChromeはLinux用があります。Flash Playerも動作しますので、「艦これ」や「アメーバピグ」等のFlash Playerを使ったゲームなら動作すると思います。

WordやExcelやPowerPointの代わりとしてはLibreOfficeといったソフトウェアがあります。代わりのソフトウェアは使い勝手が違っていたり、機能が少ない場合もありますが、あまり難しいことをしないのであれば十分かと思います。

Linuxへの移行はやりたいことが出来るか確認することが大事でしょう。

4.大きな心が必要


一番重要なことかもしれません。Linux自体やLinuxで動くソフトウェアは無料であることが多いです。LinuxでもWindows等と同様(以上?)に不具合もありますし、使い勝手が悪いソフトウェアもあります。しかし、サポートを望むのは難しいです。多少の使い勝手の悪さは仕方ないと思う大きな心が無いと使えないかもしれません。

例えばWindows 8 などで使い勝手が変わったことに文句を言う人も多いですが、Linuxではそれ以上に使い勝手が変わって行くことを覚悟した方が良いです。

5.LiveDVDでとりあえず試す


Linux系のインストール用DVDは、LiveDVDといって、インストールを行う目的と試しに使う目的の2つの目的のDVDとなっています。つまりイントールをせずに動かすことができます。一度この状態で使用してみて、使えそうだったらインストールすると言う手があると思います。私の場合はKnoppixを最初に使ってこれなら使える!と考えました。

なお、DVDでなくUSBメモリから起動することができる場合もあります。

6.Ubuntuをおすすめ


Linuxというのは基本的な部分の名前で、実際にはこのLinuxを使ったいくつもの種類のOS(ディストリビューションと言う)があります。その数は600近いです。どれを使うかは悩むかもしれませんが、UbuntuがLinuxでは一番良く使われており、日本語の情報も多く、関連雑誌も多く、一番おすすめできるかと思います。

ただ、なぜか私の場合はLiveDVDでは動くのにインストールすると動かないと言うことがありました。そういう場合はFedoraなど別のLinuxを使うといいでしょう。

もし、PCが非常に古いのであれば、軽量のLinuxであるPuppy Linuxを選ぶと言う手もあります。

7.安くコンピュータを勉強するには一番?


最近はPCの勉強をしようと思う人は少ないかもしれませんが、コンピュータの仕組みが知りたい、プログラミングを勉強したい、と言う方にはLinuxはよい選択肢になると思います。やはり情報はWindowsの方が多いですし、開発環境としても Visual Studio の方が優れていると思いますが、使いにくいのも勉強になるのではないかと思います(汗)

使いやすさはともかく、プログラミング言語の選択肢の多さや、それらを試すことの気軽さはWindows以上と思っています。プログラミングは慣れればテキストやCUIベースが一番つぶしが効いて便利かとも思います。

8.将来性は?


アクティベーションの不安からFedoraへの移行をした私ですが、Linux OSに不安が無いかと言えば、将来性には不安はあります。少数ゆえにソフトウェアの新バージョンがでなかったり・・・。実際にFirefox用(正確にはNPAPI)のFlash Playerは開発終了が宣言されました。

ただアクティベーションのあるWindowsとは異なり、セキュリティの問題はあっても、今のハードウェアが壊れるまで使い続けることは可能だと思っています。そのときには別のディストリビューションに移行したり、Windowsに戻ればいいだけでしょう。

Fedrora 20 で Emscripten

ブラウザで動くプログラミング言語といえば、Javascriptです。Javascriptも良い言語だとは思いますが、やはりC/C++言語が使いたいこともあります。

今の所、ブラウザ上でC/C++で作成したプログラムを動かすには以下の2通りだと思います。

Native Client

Google Chromeのみで動作可(モバイルは現時点では不可?)。 普通のC/C++コンパイラのようにバイナリを作成する。サンドボックス化やジャンプ指令など危険な命令を使用させないことで、安全を確保。

Emsclipten

C/C++のプログラムからアセンブラっぽいJavascriptのコードを生成する。どのブラウザでも動作するが、最適化のための特殊なヒントを入れることでFirefoxではより高速に動作可能(asm.js)。




今回はEmscliptenをFedora 20で試してみました。

環境として、git, python, Node.js, clangが必要です。 pythonは最初から入っていると思うので、以下のようにgit, Node.js, clangをインストールします。

$ sudo yum install git nodejs clang


Fedora 19からNode.jsが追加されています。Fedora 18以前の場合は、Node.jsは以下のようにインストールします。

$ sudo yum --enablerepo=updates-testing install nodejs


次に、emscriptenのコードをGithubから持ってきます。

$ git clone https://github.com/kripken/emscripten.git


いつものように、Hello Worldのプログラムを作成して、以下のようにコンパイルします。emccがコマンドとなっています。C++の場合はem++です。

$ emscripten/emcc -o hello.html hello.c

hello.htmlができていると思うので、Firefoxで確認してみます。
$ firefox hello.html


以下のようにhello!が表示されます。


サンプルもいくつか入っているので、以下のように試してみると良いかと思います。

$ emscripten/em++ -o test.html emscripten/tests/hello_world_sdl.cpp

2014年2月1日土曜日

C++11のムーブコンストラクタの速度を試す

もうC++14が出ると言う話なので今更ですが、C++の2011年バージョン(C++11)のムーブコンストラクタ(右辺値参照)についてです。

C++11ではC++の機能アップが色々とありましたが、特にムーブコンストラクタ(右辺値参照)はSTLを使っていれば何もプログラムを変更せずに速度向上が見込めますし、素晴らしいです。

ムーブコンストラクタ(右辺値参照)のテスト用に以下のrvalue.cppを作成してみました。動作を切り替えるためのマクロが多く、見にくいプログラムですみません。

#include <stdio.h>
#include <string.h>
#include <vector>
#include <memory>

/**
 * 数値を文字列で持つクラス
 * コンストラクタで数値を指定する
 */
class NumStr {
private:
        int capa_;
        char *str_;
public:
        explicit NumStr(int n) {
                capa_ = 16;
                str_ = new char[capa_];
                sprintf(str_, "%d", n);
        }

        ~NumStr() {
                delete[] str_;
        }

        NumStr(const NumStr& ns) {
                capa_ = ns.capa_;
                str_ = new char[capa_];
                strcpy(str_, ns.str_);
                #ifdef PRINT
                printf("copy1 %s\n", str_);
                #endif
        }

        NumStr& operator=(const NumStr& ns) {
                 capa_ = ns.capa_;
                 str_ = new char[capa_];
                strcpy(str_, ns.str_);
                return *this;
        }

// C++11からの新機能 ムーブコンストラクタ
#if __cplusplus >= 201103L
        NumStr(NumStr&& ns) {
                str_ = ns.str_;
                ns.str_ = nullptr;
                #ifdef PRINT
                printf("move1 %s\n", str_);
                #endif
        }

        NumStr& operator=(NumStr&& ns) {
                str_ = ns.str_;
                ns.str_ = nullptr;
                return *this;
        }
#endif
};

/**
 * メイン
 */
int main()
{

// 普通にNumStrを使う
#if !(defined(SHARED_PTR)||defined(PTR))

        std::vector<NumStr> list;
        #ifdef RESERVE
        list.reserve(9999999 * 2 + 1);
        #endif
        for (int i = -9999999; i < 9999999; i++) {
                list.push_back(NumStr(i));
        }
#endif

// NumStrをnewでメモリ確保する
#ifdef PTR
        std::vector<NumStr*> list;

        #ifdef RESERVE
        list.reserve(9999999 * 2 + 1);
        #endif
        for (int i = -9999999; i < 9999999; i++) {
                list.push_back(new NumStr(i));
        }
        // メモリの解放が必要
        for (std::vector<NumStr*>::iterator i = list.begin();
                                        i < list.end(); i++) {
                delete (*i);
        }
#endif

// NumStrをnewでメモリ確保。shared_ptrで自動でメモリ解放
#ifdef SHARED_PTR
        std::vector<std::shared_ptr<NumStr> > list;

        #ifdef RESERVE
        list.reserve(9999999 * 2 + 1);
        #endif
        for (int i = -9999999; i < 9999999; i++) {
                list.push_back(std::make_shared<NumStr>(i));
        }
#endif
        return 0;
}

ムーブコンストラクタの動きが分かりやすいようにstd::stringクラスの代わりとして、NumStrクラスを作成しています。16バイトサイズ固定で、数値を文字列して持つ、簡単なクラスです。

そして、そのクラスで作成した文字列をstd:vector(配列のクラス) に保存するだけです。

配列に保存する方法として、以下の3つで動作を試します。
  1. 普通(C++98)
  2. 普通(C++11)
  3. newのメモリ確保
  4. スマートポインタを使ってメモリ確保
速度比較の結果は以下です(上記の順番です。環境はFedora 20、gcc 4.8.2です。)

$ g++ -std=c++98 -O2 rvalue.cpp
$ time ./a.out

real 0m4.835s
user 0m4.283s
sys 0m0.478s
$ g++ -std=c++11 -O2 rvalue.cpp
$ time ./a.out

real 0m4.062s
user 0m3.665s
sys 0m0.354s
$ g++ -std=c++11 -DPTR -O2 rvalue.cpp
$ time ./a.out

real 0m3.512s
user 0m3.112s
sys 0m0.386s
$ g++ -std=c++11 -DSHARED_PTR -O2 rvalue.cpp
$ time ./a.out

real 0m3.968s
user 0m3.334s
sys 0m0.590s

1番は以前のバージョンC++98で動作させたもの。遅いです。
2番はmain()側は同じですが、NumStrクラスではC++11の新しいムーブコンストラクタを使った状態になります。速くなっています。
以前のバージョンでは速度を速くしよう考えるとnewでメモリを取得して、ポインタを配列に入れる必要がありました。それが3番です。しかしメモリの解放が必要であり、管理が大変です。
そこで、メモリを自動解放するスマートポインタを使ったのが4番です。

2番は原理上もっと速くてもいいはず。そこで、調べてみると・・・

$ g++ -std=c++11 -DPRINT -O2 rvalue.cpp
$ ./a.out | head -n20
move1 -9999999
move1 -9999998
copy1 -9999999
move1 -9999997
copy1 -9999999
copy1 -9999998
move1 -9999996
move1 -9999995
copy1 -9999999
copy1 -9999998
copy1 -9999997
copy1 -9999996
move1 -9999994
move1 -9999993
move1 -9999992
move1 -9999991
copy1 -9999999
copy1 -9999998
copy1 -9999997
copy1 -9999996

どうも配列のメモリサイズを拡張するときに、コピーコンストラクタが動作して遅くなっているようでした。ムーブコンストラクタでも問題ないはずですけど、なぜコピーコンストラクタが動作するのだろう?

そこで、メモリサイズ拡張が一回で済むように、予めメモリ確保をするようにしてみました。

$ g++ -std=c++98 -DRESERVE -O2 rvalue.cpp
$ time ./a.out

real 0m3.198s
user 0m2.977s
sys 0m0.210s
$ g++ -std=c++11 -DRESERVE -O2 rvalue.cpp
$ time ./a.out

real 0m2.581s
user 0m2.369s
sys 0m0.203s
$ g++ -std=c++11 -DRESERVE -DPTR -O2 rvalue.cpp
$ time ./a.out

real 0m3.356s
user 0m3.011s
sys 0m0.335s
$ g++ -std=c++11 -DRESERVE -DSHARED_PTR -O2 rvalue.cpp
$ time ./a.out

real 0m3.591s
user 0m3.072s
sys 0m0.507s

2番のムーブコンストラクタを使ったものが一番速くなりました。

最後のまとめです。
  • ムーブコンストラクタ(右辺値参照)は速い!
  • 無理にnewを使わなくても良くなり、プログラムが作りやすい!
  • しかしstd::vectorライブラリ内でメモリ拡張時にコピーコンストラクタが無駄に起動して遅くなることがある。