情報セミナー2開始

 本年度も新規に本研究室に配属された3年生7名と共に,情報セミナー2を毎週2コマずつ実施します。本日はその2回目,前回は私(幸谷)が前説を行いましたが,今回からはあらかじめ割り当てられた受講生の中から二人ずつ,先生役を務めて頂きます。

 テキストは前年度から使っている「Webアプリケーション開発入門」,これを9月下旬~11月末までの2か月ちょっとで第5章まで解説し,実際にプログラムを打ち込んで実行しながらHTML, JavaScript, CSS, PHP, SQLを学んでいきます。

 今年の3月には全面的に書き換えてだいぶ改良しましたが,セミナーの解説を聞きながら見てみると色々直すべき箇所が見つかるもんです。といっても,解説直前に書き換えられては先生役の受講生に気の毒ですので,終わったところからチマチマ修正をかけることにしました。本日は第1章の「JavaScriptの基礎」まで終わりましたので,ここまで訂正をしてあります。

 5章まで終わる11月末までには修正も終わるという寸法ですが,直しても直してもまだ物足りないところが出てくるのが,自作テキストの困った所です。Web文書ですからナンボでも修正は効きますしね。無理しない範囲であれこれ直していく予定です。

卒研メモ:W3C Payment Request API

 通販サイトや金融分野でのWebの利用が活発な昨今,金銭のやり取りのための標準APIであるW3C Payment Request APIが,主要ブラウザで実装されているようです

 仕様をざっと見たところ,JavaScriptで支払情報,支払い完了情報等のオブジェクトが定義されており,オブジェクトに情報を突っ込んでJavaScript関数を呼び出すだけで支払いが可能になるという便利なAPIになっています。勿論,現在でもクレジット情報のやり取りは普通にWeb上で行われていますが,全く標準化されておらず,旅行業者や通販業者ごとにバラバラの取引ツールを使わざるを得ない状況になっていました。

 今後はAmazon BusinessのようにB2Bでも標準的なAPIで金銭のやり取りが行われるようになっていくでしょう。巨大なプラットフォームに依存しないW3CでのWeb APIの標準化と実装の勧めは自由競争社会を維持する上で重要な活動です。

[模擬講義] コンピュータの計算は正しくない!

オープンキャンパス模擬講義

「コンピュータの計算は正しくない!」

静岡理工科大学 情報学部
コンピュータシステム学科
幸谷 智紀(こうや とものり)


1.「数」とは?

 現在のICT社会で使用される「データ(data)」は例外なく全て「数」を表現したものです。小学校では自然数,分数(有理数),小数を,中学校では負の数と整数を,高校では無理数を習いますが,それらの数を総称して「実数(real number)」と呼びます。実数を幾何学的に表現する時には直線=数直線を使用します。全ての数は,この数直線上のどこかに「点(point)」として存在しています。

 自然数,整数,有理数は全て分数として表現できる数です。下記の図に示す通り,分数は無数に存在します。

 ちょっと脱線しますが,下記のような問題はご存知でしょうか?

 解答については検索して調べて頂ければ何らかの手かがりが得られるでしょうが,実際の分数の計算はこのようにしてはいけませんね。どのように計算できるのか,ちょっと試してみましょう。

分数の計算フォーム

 実数にはもう一つ,分数としては表現できない「無理数(irrational number)」があります。有名なものとしては円周率\pi = 3.1415...や平方根\sqrt{2} = 1.4142...があります。これも実数の一種なので,数直線上の点として実在しています。

 有理数(分数)を小数で表現すると,次のように必ず同じ数のパターンが繰り返し出てきます。

\[\begin{split}
\frac{1}{2} &= 0.50000\cdots = 0.5\dot{0} \\
\frac{1}{3} &= 0.33333\cdots = 0.\dot{3}
\end{split}\]

 無理数では同じパターンの数の羅列が永久に続くことはありません。ちょっと計算してみましょう。

Try! MPFR

 従って,実数を一言で表現すると「循環したりしなかったりする)無限桁の小数として表わすことのできる数」ということになります。何故無限桁が必要になるのかは,微分積分(数学II, III)に登場する「極限」というものと深い関係がありますが,それは大学に入ってからじっくり考えてみて下さい。

 現在の科学技術では実数を土台とする計算が不可欠です。そしてほとんどの計算はコンピューターの中で行います。では,次にコンピューターの中身について見ていくことにしましょう。

2.コンピュータの仕組みと「データ」

 今のコンピューターの筐体とぱかっと開けると,マザーボードと呼ばれるデジタル回路基板の上に様々な集積回路が載っていることが分かります。下記は本研究室で故障したマシンのマザーボードの写真です。

 マザーボードの上に乗っている集積回路のうち,重要なものがCPU(Central Processing Unit)とメモリ(RAM)です。コンピューターで行われる処理は,全てのデータが「数」として表現されてメモリに格納され,処理内容に応じてメモリ内のデータが読み出されて処理され,またメモリに書き戻されます。

 このCPUとメモリとのやり取りに要する時間,CPU内の処理(計算)に要する時間が短ければ短いほど,コンピューターの性能が高いと言えます。とても高速な処理が可能になっていますが,困ったことに,メモリの大きさは有限で,処理時間も短いとはいえゼロにはなりません。「無限の長さを持つ実数」をそのままコンピューターのメモリに格納することは不可能ですし,仮にできたとしても,無限の長さの処理時間を要することになります。「無限大(∞)」とは果てのないことを意味し,それ故に完ぺきな数学,特に微分積分のような解析学という体系が成り立つわけですが,これではコンピューターには実数の計算が出来ないことになってしまいます。

3.「誤差」を含まざるを得ない科学技術計算

 仕方がないので,コンピューターの中では無限桁の小数を適当な長さに切って,有限桁の小数(=有理数の一種)として扱うことにします。この適当長さに切る操作のことを「丸め(Round-off)」と呼び,丸めに伴って起きる元の正しい値(真値)とのズレを「誤差(error)」と呼びます。

 この丸めに伴う誤差を,関数グラフアプリを使ってみていくことにしましょう。

MPFRgraph

コンピューターは計算が高速なので,いくらでも長い桁の計算ができそうですが,長くなればなるほど計算時間はかかるようになりますし,科学技術開発競争を世界中で行っている昨今,あまり誤差ばかり気にして長い桁の計算ばかりすることは難しいのが現状です。従って,最近のAIの中核技術であるDeep Learningではなるべく短い桁の小数で計算しようとしています。

 しかし,いくら計算が速くても,途中で誤差が拡大されて,不正確な値しか出てこないようでは困ります。一般には,丸める桁数を長くすれば誤差も小さくできるわけですが,とてもたちの悪い問題があることは良く知られていて,いくら桁を長く取っても足りなくなるということもあります。

5.誤差評価付き計算の例

 性質の良くない問題の例として,「複雑系(Chaos system)」というものがあります。一番シンプルなものとして,ロジスティック写像で定義される次のような数列x_0, x_1, ..., x_i, x_{i+1}, ...の生成問題を取り上げましょう。

 出発値x_0 = 0.7501として,次の式の右辺を計算して次のx_1を導出します。

\[ x_{i+1} := 4x_i (1 – x_i) \]

これで実数列\{x_i\}^{100}_{i=1}を,下記のCプログラム

#include <stdio.h>

main()
{
    int i;
    float x[102]; /* 単精度 */

    x[0] = 0.7501;

    for(i = 0; i <= 100; i++)
    {
        x[i+1] = 4 * x[i] * (1 - x[i]);
        if(i%10 == 0) 
        	printf("%5d %25.17e\n", i, x[i]);
    }
}

を用いてIEEE754単精度(約7桁)及び倍精度(約15桁)で計算した結果は次のようになります。

    i      単精度           倍精度
    0   7.501000e-01 7.50099999999999989e-01
   10   8.445168e-01 8.44495953602201199e-01
   20   1.229039e-01 1.42939724528399537e-01
   30   4.977781e-01 8.54296020314155413e-01
   40   5.816439e-01 7.74995884542777125e-01
   50   5.580120e-01 7.95132827423636751e-02
   60   2.287482e-02 2.73872762849587226e-01
   70   9.985481e-01 9.97021556611396687e-01
   80   9.421800e-01 3.52785425069070790e-01
   90   2.129389e-01 6.35558111134618908e-01
  100   7.568640e-01 5.15390006286616020e-01

同じ値になる名図ですが,x_{20}あたりでもう単精度の値は最初の一桁目しか合っていません。x_{30}以降はもう全く違う数です。

 このような場合はもっと桁数を増やして計算する必要があります。50桁計算すると下記のようになります。

  0, 7.501e-01
 10, 8.4449595360221744753714870256154137267401952291229e-01
 20, 1.4293972451230765528428175723130628307376969200214e-01
 30, 8.5429600370442189166613118425888744374797589008230e-01
 40, 7.7497575311820124128022346126421168481511313675586e-01
 50, 9.3375332197703029055189668015168234762823013462054e-02
 60, 4.0822016829087813187102766181952686730359229911213e-01
 70, 7.1511999705058574897099346417593218350311240577887e-02
 80, 4.6325330290077571055993467458320747053550671068192e-01
 90, 1.3344050120868840464692012150021107621136608489291e-03
100, 7.8817989371509906806704770440086762650658767283966e-02

100桁計算すると,

  0, 7.501e-01
 10, 8.44495953602217447537148702561541372674019522912291280007848388118986290823419270975121157e-01
 20, 1.42939724512307655284281757231306283073769692002141121387637872878254442652405447154653323e-01
 30, 8.54296003704421891666131184258887443747975890082277146848716525830873157517999293072280730e-01
 40, 7.74975753118201241280223461264211684815113136725464353115716739919423777262939033931884043e-01
 50, 9.33753321977030290551896680151682347628230351487453020066411681729685131997586455460349178e-02
 60, 4.08220168290878131871027661819526867303629812881299069587191914174238088850476295365965331e-01
 70, 7.15119997050585748970993464175932183301720988330772170512558519903814407400108286900737962e-02
 80, 4.63253302900775710559934674583207430627755245547675072149154489741355095166291517037937750e-01
 90, 1.33440501208688404646920121499911906832767847107910033479094701619779865654038757784875352e-03
100, 7.88179893715099068067047704626992647240094450346038441154434366642728380004689090274960709e-02

となり,大分同じ数に近づいてきたことが分かります。

 このように,丸めによる誤差の影響が大きく出る「悪条件問題」というものが,科学技術計算にはたまに出てきます。計算途中で誤差がどの程度は行っているのかを自動的に調べる「区間演算(interval arithmetic)」という技術もありますが,このような悪条件問題の場合は大した役には立たず,結局桁数を多くしないとまともな値を得ることはできません。下記の例は,MPFIと呼ばれる多倍長計算を区間演算に利用できるソフトウェアを使ったロジスティック写像の掲載例です。一応,プログラムもつけておきましょう。

$ ./logistic_mpfi
prec(bits) = 128
    0, [7.5009999999999999e-1,7.5010000000000001e-1] 3.918e-39
   10, [8.4449595360221744e-1,8.4449595360221745e-1] 4.865e-33
   20, [1.4293972451230765e-1,1.4293972451230766e-1] 3.014e-26
   30, [8.5429600370442189e-1,8.5429600370442190e-1] 5.288e-21
   40, [7.7497575311819887e-1,7.7497575311820361e-1] 6.112e-15
   50, [9.3375329714176199e-2,9.3375334681229861e-2] 5.319e-08
   60, [4.0561739523590902e-1,4.1082572849550305e-1] 1.276e-02
   70, [-2.9373100713009889e43,2.1377489377594625e43] 5.075e+43
   80, [-1.2245050211453045e45127,8.9118419393669329e45126]2.116e+45127
   90, [-9.5278547330878072e46210753,6.9342905040200581e46210753]1.646e+46210754
  100, [-@Inf@,@Inf@]       inf

$ ./logistic_mpfi
prec(bits) = 256
    0, [7.5009999999999999e-1,7.5010000000000001e-1] 1.151e-77
   10, [8.4449595360221744e-1,8.4449595360221745e-1] 1.430e-71
   20, [1.4293972451230765e-1,1.4293972451230766e-1] 8.857e-65
   30, [8.5429600370442189e-1,8.5429600370442190e-1] 1.554e-59
   40, [7.7497575311820124e-1,7.7497575311820125e-1] 1.796e-53
   50, [9.3375332197703029e-2,9.3375332197703030e-2] 1.563e-46
   60, [4.0822016829087813e-1,4.0822016829087814e-1] 3.749e-41
   70, [7.1511999705058574e-2,7.1511999705058575e-2] 2.244e-34
   80, [4.6325330290077571e-1,4.6325330290077572e-1] 3.633e-29
   90, [1.3344050120868840e-3,1.3344050120868841e-3] 1.322e-20
  100, [7.8817989371509897e-2,7.8817989371509917e-2] 2.348e-16

// logistic 写像
// MPFR & MPFI版
#include <stdio.h>
#include "mpfr.h"
#include "mpfi.h"

int main()
{
	int i;
	unsigned long prec;
	mpfi_t x[102];
	mpfr_t relerr;

	printf("prec(bits) = "); scanf("%ld", &prec);
	mpfr_set_default_prec(prec);

	// 初期化
	mpfr_init(relerr);
	for(i = 0; i < 102; i++)
		mpfi_init(x[i]);

	// 初期値
	//x[0] = 0.7501;
	mpfi_set_str(x[0], "0.7501", 10);

	for(i = 0; i <= 100; i++)
	{
		if((i % 10) == 0)
		{
			printf("%5d, ", i);
			mpfi_out_str(stdout, 10, 17, x[i]);
			mpfi_diam(relerr, x[i]);
			mpfr_printf("%10.3RNe\n", relerr);
		}

		//x[i + 1] = 4 * x[i] * (1 - x[i]);
		mpfi_ui_sub(x[i + 1], 1UL, x[i]);
		mpfi_mul(x[i + 1], x[i + 1], x[i]);
		mpfi_mul_ui(x[i + 1], x[i + 1], 4UL);

	}

	// 消去
	mpfr_clear(relerr);
	for(i = 0; i < 102; i++)
		mpfi_clear(x[i]);

	return 0;
}

6.まとめ

 以上,まとめますと

  1. 実数は無限桁の小数として表現される数である。
  2. コンピューターのメモリは有限なので,無限桁の実数を格納することはできず,丸めて短い有限桁に収めなければならない。
  3. 丸めに伴う誤差が甚大な影響を及ぼす「悪条件問題」というものが存在する。
  4. 悪条件問題を解決するには桁を増やして対処するしかない。しかしこれは計算時間を要する解決策である。

となります。「高性能計算研究室」ではこのように長い桁の計算,多倍長計算を用いて様々な悪条件問題の解決に取り組んでいます。

新研究室サーバ稼働開始

 本年度から本学独自のVPSの運用が本格的に始まり,物理サーバ(PC本体を自分で設置して運営するタイプのサーバ)として運用していたサービスをVPSへ移行するよう,情報センター長(私です)からお触れが出ました。ということで,水野先生にVPSのインスタンス(仮想サーバマシン)を設置して頂き,

の二つのサービスをVPSへ移行しました。見かけはほとんど変わってませんが,PHP 7で運用し,Perl CGIを廃止した都合上,チマチマと必要最低限のアップデートはかけてあります。これで物理サーバのハードウェア故障に悩まされることがなくなるかと思うと,大変気が楽になります。停止後の物理サーバ,何に使いましょうかね?

 ちなみに,URLは後ほど公開しますが,このインスタンスは本研究室のサーバーとしても利用できるようにもう一つ別のFQDNを持っています。ということで3つのFQDNを持つインスタンスということになります。
 本年度の卒研で利用する必要のあるメンバーには,アカウント情報を既に送付してあります(のでちゃんと稼働報告して下さいな>該当者の方々)。

 トラブルがあり,EVの取得がまだできていませんが,本研究室サーバとしての本格運用はEVを使ったHTTPS通信ができるようになってから,卒研用として広く外部公開していきたいと考えております。