リブートキャンプ by Swift 目次

 

 前回の説明を読めば「iPhoneアプリ開発、号外 IBMのSwiftサイト」のサンプルとして書いた、階乗計算のプログラムもわかるんじゃないかと思われ。

 

 1! 2! 3! 4! 5! ・・・

 

 ↓ループを使った階乗計算例

 

http://swift.sandbox.bluemix.net/#/repl/59479547ea3ae2065baec60f

 

 問題はその後の、マクローリン展開を使ったsin値の計算プログラムですな。
 ↓そもそもsin値ってなんだ?の中学生や、ダメダメの高2以上な人はここを見ましょう。
 

http://eleking.net/math/m-trigonometric/mt-trigonometric.html

 

 ↓最初、wikiを見ましょうと書こうと思ったけど…

 

https://ja.wikipedia.org/wiki/三角関数

 

 ムズイわっ!

 まあ、そんなわけでsin値です。こいつはマクローリン展開で以下のようなxの累乗と、階乗を使った計算の和で計算できるんですよ。


 ↓sin値のマクローリン展開(テイラー展開の一種)については、このページがわかりやすいような…

 ただ三角関数の微分についてなんかは説明してないので、知らないと読んでで目が点になるかも

 

http://www.yamamo10.jp/yamamoto/lecture/2006/3E/2nd/html/node2.html


 といっても、私もテイラー展開は、なんとなくそうなんだ〜て思うレベルですが、とにかくsin値は上の式で求まるらしい。

 けど、実際のとこどうなんだよっと、確かめたいけど、こんな式計算するのめんどくせーよっ、ということでプログラムで実践しますた。それがこの前のプログラム。

 

 ↓マクローリン展開を使ったsin値の計算例(上で作った累乗、階乗関数を利用)

 

http://swift.sandbox.bluemix.net/#/repl/59479a3eea3ae2065baec614

 

 結果、合ってる…

 すげーよ、テイラー、あんたすげーよ。

 power、factorial関数はそれぞれ、ループを使った累乗計算例、階乗計算例で作った関数をコピペして使ってます。

 

http://swift.sandbox.bluemix.net/#/repl/594793c6ea3ae2065baec60d

http://swift.sandbox.bluemix.net/#/repl/59479547ea3ae2065baec60f

 

 ちなみにループ使って、0度から90度までのsin値を求めてるんですが、テイラー展開でsinの引数xとして指定する角度の単位は1周を360分割する度数法ではなく、弧度法のラジアンが前提です。

 

 ↓ラジアン

 

https://ja.wikipedia.org/wiki/ラジアン

 

 なので、度数法単位から弧度法単位に変換する関数も作ってます。

//	angleで指定される360度単位の角度をラジアン単位に変換
func rad(angle:Double) ->Double {
	return 2.0 * 3.14 * (angle / 360.0)
}
 ここでretrunの横の演算式内で使ってる / (スラッシュ)は割り算の記号です。*(アスタリスク)は、前回の*=の説明で想像つくと思うけど掛け算の記号。 
 なので算数だと
 
    2 x 3.14 x (angle ÷ 360)
 
と書いてるのと同じことになります。この計算結果がrad関数の戻り値となる。
 後は、以下のif文を説明すれば、主役のsin関数の方も何やってるか理解できるでしょう。
        if (k % 2) == 1 {    // kが奇数の時だけ計算
            let factorial_k = factorial(x:k)         //  k!
            let power_x = power(base:x, exponent:k)  //  xのk乗
            result += Double(sign) * power_x / factorial_k
            sign *= -1       // 符号反転
        }
 ということで、まずは「k % 2」の%から。
 これはkを2で割った時の余りを計算するための記号です。
 例えばkの値が2なら、2で割った時の余りは0となり、3なら1、4なら0、5なら1となります。
 で、この計算結果を1と比較しているのが「== 1」の部分。
 これは == が値の一致を調べる記号で、 == の右辺と左辺が一致するときは真(正しい)、一致しないときは偽(正しくない)という結果を算出します。
 
 
 
 そして、この結果に合わせて動作を変えるのがif文です。ifキーワードの後ろが真の時だけ { } で囲まれた処理が実行されます。
 
 
 
 なので、kが1、3、5の時だけ
            let factorial_k = factorial(x:k)         //  k!
            let power_x = power(base:x, exponent:k)  //  xのk乗
            result += Double(sign) * power_x / factorial_k
            sign *= -1       // 符号反転
という処理が実行されることになります。
 これで、sin値のマクローリン展開の式が5!のレベルまで計算されることになるわけですよ。
 
 処理内で出てくるletというキーワードは定数宣言です。定数は変数と同じ記憶容器ですが、一度値を記憶したら後から変更できないようになってます。
    let factorial_k = factorial(x:k)
 と書くことで、factorial_kはfactorial(x:k)の戻り値で固定される。試しに
      let factorial_k = factorial(x:k)
      factorial_k = 0.0
とか書き込んでみるといいでしょう。Runさせると「無理!」って注意されます。
 
 ↓こんな感じで注意される
 
 
 { } の中で宣言された変数や定数は { } 内が寿命となっているので、ループ中のkが1、2、3、…と変化する処理ごとにfactorial_kは新しく作られ、factorial(x:k)の値が設定されます。
 それと
    result += Double(sign) * power_x / factorial_k
のDouble(sign)というのは、変数signがInt型なので、これをDouble型に変換しています。こうしないとDouble型のresult、power_xやfactorial_kとの演算式に組み込めません。
 ちなみにInt型に変換するときはInt(power_x)という風に書きます。
 型を統一するだけなら、Int型に合わす手もありますが、sin値をInt型で計算するの意味ないから。
 
 ループ使ってマクローリンを展開してるので
    for k in 1...15 {
なんかにすると、かなり精度が上がります。
 比較してるのは、swiftに用意された標準のsin関数の値。この標準のsin関数を呼び出すためにプログラム先頭で
import Foundation
てしてます。
 
 ↓Appleが公開してるC言語のsinのソースはここ(多分、今ならGitHubにも置かれてんじゃないかと思われ)
 
 ±π/4までは、13!までのマクローリン展開を使うっぽい。
 それ以上の大きさは、象限を分けてcosにしたりとか、色々調整するみたい。
 __ieee754_rem_pio2てのは渡された角度をπ/2で割った余りや象限を返す関数みたっす。
 
 ↓__kernel_sinソースの一部を移植
 
 結局、どっちもマクローリンかーいと突っ込んだところで、今回はおしまい。
 
 ということで、最後に指数関数と三角関数のテイラー展開から導き出されるオイラーの公式をたたえて、皆さん、ご一緒に〜
 
 
thumb
 
 でわでわ。
 

リブートキャンプ by Swift 目次

 

 前々回IBMのSwift環境、そのサンプルとして示した累乗計算例の説明

 

↓ループを使った累乗計算例

 

http://swift.sandbox.bluemix.net/#/repl/594793c6ea3ae2065baec60d

 

 まず、前回説明したSwiftのプログラムルール

 

 ルールその1、上から順に実行する。

 ルールその2、// から改行まではメモ書きなのでプログラムとみなさない。

 

てのがあるので、最初の

  // baseに対するexponent乗をループで行う

はメモ書きであってプログラムじゃない。

 加えてルールその3、関数定義部は飛ばす。

 

 

 なので、メモ書きの後の

func power(base:Double, exponent:Int) -> Double {
	//	exponentが0や負の数の対処は省略
	var result = 1.0
	for _ in 1...exponent {
		result *= base
	}
	return result
}

てのもプログラムではあるけど、関数定義部なんで、すぐには実行されません。

 関数定義てのは何かというと

 

 

ラノベ本の原型から抜粋(129ページ〜部分に相当)


「関数も定義したんですか?」

「うん、見よう見まねで」

関数定義

 関数は自分で定義することもできる。

 数学だとこうなる。

 

    数学での書き方

 Swiftだとこうなる。

 

    Swiftでの書き方

 

 数学と違い、Swiftでは、関数の定義であることを示すキーワードや、仮引数や戻す値がどういう型なのかを指定する必要が出てくるのだ。

§

 型とは記憶容器の種類を意味する。

 数値を扱う変数なら、整数を扱える記憶容器にするか、実数を扱える記憶容器にするかでInt型とDouble型に別れる。整数を扱うInt型では小数点以下が扱えない。

 一見、Double型の方が万能そうだが、コンピュータの精度の点で限界があり、例えば、今回のような0.1は0.1000000000000000055…と記憶され、加算していくと正確には2.0にならない。

 その点、Int型の場合、1は1として記憶してくれる。ある程度の誤差は許容しつつ使うのがDouble型だ。

 実は、これまでのプログラムで使っていた変数にも型は設定されていた。

 変数や定数宣言で初期値に小数点をつけた数値を設定するとDouble型、付いていなければInt型となるルールだ。

 だから左京さんは変数tの宣言時に0ではなく0.0と書いた。

    var t = 0.0		← Double型の変数になる
    var t = 0		← Int型の変数になる

§ 

 関数を定義する時は、まず仮引数ごとに、この型を明示する必要がある。  それに加えて、もし値を戻すタイプの関数なら ( ) の後ろに、自分が戻す値の型を明示する必要もある。

 

 

 そして関数の処理内で、retrunキーワードを使って、戻したい値を指定して関数から戻るようにする。

 
 

 関数を呼び出す側は、こうした関数の定義にそった形で、関数呼び出し文を書き、戻される値を定数や変数に設定して利用する。

 

 

 関数の定義や呼び出し方には、こういったルールがある。


 
てなわけで、関数定義部は一旦無視して、その下の
//	1-5の数でテスト
for exponent in 1...5 {
	print("2 の", exponent, "乗 =", power(base:2, exponent:exponent))
}
に注目してください。
 最初の1行はメモ書き、「1-5の数でテスト」て書いてるように、累乗計算をテストしてます。2の1乗、2の2乗、2の3乗、2の4乗、2の5乗てのをループ文でテストしてる。
 ループ文がどういうものかというと
 

ラノベ本の原型から抜粋(109ページ〜部分に相当)


 ループ文は同じ処理を繰り返すための文法だ。

 

    立たされて

    ららら ……… *1 

    一人静かな廊下だね

    (*1を4回繰り返す)

 

 よく歌詞カードなんかで見る表現。同じようなことがSwiftでも書けるようになっている。

 

for文

 

 for文はいくつかあるループ文の1つで、カウント用変数の値を1つずつ増やしながら、指定された処理を繰り返すというもの。

 

 この書き方だと、変数iが用意され、その値が1から10,000まで1つずつ変化し、その間 { } 内の処理が繰り返されることになる。

 

 ここでは、{ } 内の処理として

と書いているので、このfor文は、変数iの値を1、2、3、…と変化させつつ、10,000回、totalの値にiの値を加える処理を繰り返すプログラムを書いたことになる。

 

 最初にtotalの値を0にしておけば、ループを抜けた時には、totalの値は1から10,000までの総和になっているわけだ。

 ループ文を使う方が、最初の足し算をひたすら並べたやり方よりずっと簡単で、書き間違う可能性もずっと少ない。おまけにループ範囲を書き換えるだけで、1から10の総和でも、100から10,000の総和でも計算できる。

for i in 1...10 {		← 1から10の総和
for i in 100...10000 {	← 100から10,000の総和

 

なので、今回の

 

 

なら、exponentを1〜5に変化させながら、上で無視した関数定義部で定義されているpowerという関数を呼び出し、その結果をprint関数で表示させてるってことになります。

 power関数は、引数のbase:2でを2に指定、exponent:exponentで、そのをexponent(が記憶してる値)乗するって指定になる。そしてその計算結果が関数の戻り値として返されます。
 で、その戻り値をprint関数の引数に渡して画面に表示してる。

 

 

 ちなみにprint関数はかなり凝った関数定義によって、こんな感じで「,」で区切って複数の引数を渡すことができるようになってます。

 power関数が何やってるかは、以下を参考に自分で考えよう!

 でわでわ。

 

リブートキャンプ by Swift 目次

 

 テッテレー♪

 前回紹介したIBMのSwift環境は、数多あるSwift入門サイト(Swift 入門 で検索しよう)のサンプルコードを試すことができます。

  しかも、iPhoneのSafariでも使えるので、電車やバスの中、休息中の公園、図書館、あらゆるところでSwiftプログラミングの学習ができるわけですよ。

 ノマド学習!

 

「え、違いますよ~、やだなあ。私もスタバでドヤ顔してみたーい(はあとまーく)」

「ネトゲ廃人がスタバとかマジ笑う」 

 

 ↓例えば、こんな感じ

 

 

 

 こいつはラノベ本に書かれているプログラム、1〜10の総和の縮小版、1〜2の総和ってことになります。何やってるかは、以下を読むべし。

 読んだ後は1〜10の総和を自分で書き込んで試すべし!

 ちなみにIBMのSwift環境は、iPhoneからだと日本語入力できません。なので、文中に出てくるメモを日本語で書くことはできない。そこんとこは諦めるように。

 

ラノベ本の原型から抜粋(102ページ〜部分に相当)


 

 書きながら間違いを確認でき、対話形式で学習ができるわけだ。 例えば、1から10までの数の総和を計算させるプログラムなら、こんな風に書く。  

 最初の1行は無くてもいい。 この1行は、このプログラムを説明しているメモで、コンピュータの振る 舞いには影響しない。 

 役者さんが、台本にメモを書き込むのに似ている。 Swiftには、こんな風にコンピュータの振る舞いとは関係ない文章をプロ グラムコード内に残せる仕組みが用意されている。 振る舞いに影響は及ぼさないが、メモが効果的なのは間違いない。誰が見 たって「これって1から10までの総和のプログラムなんだ」ってなる。

 

§

 実際のプログラムは次の一文から始まる。

 

変数宣言

 

 変数宣言とは記憶容器を用意する一文。

 1から10までの数の総和を計算させるには、整数を記憶し、1を足すと1増 え、2を足すと2増える記憶容器が必要だ。 このような記憶容器は、変数と呼ばれ、varというキーワードで用意される。 変数は必要なだけ用意できるので、プログラマが変数ごとに呼び名をつけ る。ここでは総和を記憶するのでtotalと名付けた。 

 

 

 以後、totalという変数が利用できるようになる。 この時点でのtotalに記憶されている値は1。 この一文を変数宣言という。

§

その次の行が、変数totalの記憶値に2を加算する動作の記述。この記述は演算式とも言う。

 

演算式 

 

 

 演算式を記述どおり実行すると、変数totalの記憶値は3となる。そんな 演算式が10行並んでいる。 

 

 

 変数totalを用意し1を記憶させ、その記憶値に、2、3、4、...と値を加算 しているわけだ。 

 

 最後の行では、10まで足し終わった変数totalの記憶値を結果画面に表示 させている。 

 printは受け取った値を結果画面に表示する関数。 

関数

 Swiftの関数も、数学で使う関数も、なんらかの機能を提供するという点 では同じだ。
 数学で使われる関数は、こんな感じ。 

 

 これで数式中に、f(1)と書けば2を意味するし、f(2)と書けば5を意味する ことになる。関数fはx2+1を計算するという機能を提供しているわけだ。

 Swiftでも、関数名の後ろの ( ) の中に、渡したい引数を書くことで、 その関数の機能を利用できる。 

 

 受け取った値を元に、特定の計算式で新しい値を計算するのが数学の関数 なら、受け取った値を元に何かアクションを起こすのがSwiftの関数。

 print関数が提供する機能は、受け取った引数の値を結果画面に表示する ことなので、これで変数totalの記憶値を結果画面に表示することになる。

 こんな風に関数の機能を使うことを、関数を呼び出すと表現する。 print関数を呼び出し、変数totalの記憶値を画面に表示させたわけだ。 

 

 以上で1から10までの数の総和を計算させ、結果を画面に表示させるプロ グラムを書いたことになる。

 ただし、あまりスマートなプログラムとは言えない。

 想像してみて欲しい。このやり方で10,000までの総和を計算させるプログ ラムを書いてる自分の姿を!

§

 そんな写経のような作業を回避するために、たいていのプログラム言語に はループ文が用意されている。 

 


 

 というわけで、ループ文は次回!