//: [Previous](@previous) // Xcode で Editor メニュー > Show Render Markup でお読みください //import UIKit import Foundation /*: # 中学3年の数学 */ /*: ## 平方根 */ /*: ### 有理数と無理数 */ /*: #### 平方根 𝑎 を正の実数とする(負数は考えない) 𝑥² = 𝑎 にあてはまる 𝑥 の値を平方根といい、±√𝑎 とあらわす √𝑎 と −√𝑎 が存在する Swift では sqrt(a) 関数で実数値を求めることができる ##### 発展 立方根 𝑎 を実数とする 𝑥³ = 𝑎 にあてはまる 𝑥 の値を立方根といい、∛𝑎 とあらわす 𝑎 が実数であれば ∛𝑎 しか存在せず、−∛𝑎 は存在しない 負の値が存在しないということではないので注意。例えば、∛{-1} = -1 である。なぜなら、(-1)³ = -1 Swift では cbrt(a) や pow(a, 1.0/3.0) 関数で実数値を求めることができる ##### 発展 4乗根 𝑎 を正の実数とする(負数は考えない) 𝑥⁴ = 𝑎 にあてはまる 𝑥 の値を4乗根といい、±∜𝑎 とあらわす 負の数 𝑥 の偶数回の積は正の値になるので、∜𝑎 と −∜𝑎 が存在する Swift では pow(a, 1.0/4.0) や sqrt(sqrt(a)) 関数で実数値を求めることができる */ print("平方根") for 有理数 in [ (49, 1), (16, 25), (5, 1), ] { let (分子, 分母) = (Double(有理数.0), Double(有理数.1)) print("√{\(分子)/\(分母)}\t= ±\(sqrt(分子))/\(sqrt(分母))") } print("立方根") for 有理数 in [ (49*7, 1), (16*4, 25*5), (5, 1), ] { let (分子, 分母) = (Double(有理数.0), Double(有理数.1)) print("∛{\(分子)/\(分母)}\t= \(cbrt(分子))/\(cbrt(分母))\t= \(pow(分子, 1.0/3.0))/\(pow(分母, 1.0/3.0))") } print("4乗根") for 有理数 in [ (49*7*7, 1), (16*4*4, 25*5*5), (5, 1), ] { let (分子, 分母) = (Double(有理数.0), Double(有理数.1)) print("∜{\(分子)/\(分母)}\t= ±\(pow(分子, 1.0/4.0))/\(pow(分母, 1.0/4.0))\t= ±\(sqrt(sqrt(分子)))/\(sqrt(sqrt(分母)))") } print("平方根の大小") for 実数列 in [ // 例題24(1) [ (0.0, "0"), (-sqrt(6.0), "−√6"), (sqrt(7.0), "√7"), (-sqrt(5.0), "−√5"), (3, "3") ], // 練習24(A)(1),(A)(2) [ (4.0, "4"), (sqrt(15.0), "√{15}"), (sqrt(17.0), "√{17}") ], [ (sqrt(0.5), "√{0.5}"), (sqrt(0.6), "√{0.6}"), (0.5, "0.5") ], ] { print(実数列.sorted(by: { $0.0 < $1.0 })) } // 例題24(2) for a in 1... { if !(sqrt(Double(a)) < 2) { break } print("√{\(a)} < 2") } // 練習24(B) for a in 4... { if !(sqrt(Double(a)) < 4) { break } if 3 < sqrt(Double(a)) { print("3 < √{\(a)} < 4") } } print("平方根の値と計算機") for 実数 in [ // 例題25 Double(5), Double(7), // 練習25 Double(15), Double(50), 1.23, 65.2, ] { print("√{\(実数)}\t= ±\(String(format: "%.3f", sqrt(実数)))") } /*: #### 有理数 プログラミング言語 Swift は「有理数」を標準で扱うことはできない (有理数体 ℚ をストラクチャで、有理数体に関する演算を演算子のオーバーロードで定義するなどして、自前で扱うようにすることは不可能ではない) #### 無理数 プログラミング言語 Swift はもとより記憶域が有限である計算機では「無理数」を直接扱うことは不可能である 例えば Double.pi は無理数である円周率 𝜋 の近似値に過ぎない #### 無限小数 有理数の循環小数、及び、循環しない無限小数である無理数を無限小数という #### 集合 ℝ, ℚ, ℝ∖ℚ, ℤ, ℕ, ℂ, 𝕄𝑛(ℝ), 𝕄𝑛(ℂ), ℍ, 𝕆, ℚ𝑝, 𝐶𝓁(𝑉,𝑄) 以上を、大学で使う集合の記号を使って、まとめると、 実数 ℝ には、有理数 ℚ 、無理数 ℝ∖ℚ があり、 有理数 ℚ には、整数 ℤ 、有限小数、循環小数があり、 整数 ℤ には自然数 ℕ があり、 無限小数には、循環小数、無理数が ℝ∖ℚ ある 数にはほかに、高校で学ぶ複素数 ℂ や大学で学ぶ ℝ 成分の 𝑛 次正方行列 𝕄𝑛(ℝ)、ℂ 成分の 𝑛 次正方行列 𝕄𝑛(ℂ) やコンピュータグラフィックスで学ぶ四元数 ℍ、その倍の次元の八元数 𝕆、𝑝-進数 ℚ𝑝, クリフォード代数 𝐶𝓁(𝑉,𝑄) など様々な数があることを知っておこう */ /*: #### 有理数と循環小数(1) 有理数から循環小数を求める 剰余演算をくりかえすことで求まる */ func 循環小数(_ 分子: UInt64, _ 分母: UInt64) -> (商のリスト: [UInt64], 循環小数位: UInt64) { var 商 = 分子 / 分母 var 余り = 分子 % 分母 var 商のリスト = [ 商 ] // 添字0は整数部分、添字1から小数部分 #if false // 当初、このようなアルゴリズムで行っていたが、まったくの間違いであった。1/17 = 0.0̇588235294117647̇ などが求まらない。間違いの好例 while 余り != 0 { 余り &*= UInt64(10) 商 = 余り / 分母 余り %= 分母 if let i = 商のリスト.dropFirst().firstIndex(where: { $0 == 商 }) { return (商のリスト: 商のリスト, 循環小数位: UInt64(i)) } 商のリスト.append(商) } #elseif false // これだとメモリの使い過ぎ。さらに下で改良 var 小数桁 = UInt64(0) var 余りの小数桁 = Array(repeating: UInt64(0), count: Int(分母)) repeat { 小数桁 += 1 余りの小数桁[Int(余り)] = 小数桁 余り &*= 10 商 = 余り / 分母 商のリスト.append(商) 余り %= 分母 } while 余りの小数桁[Int(余り)] == 0 if 余りの小数桁[Int(余り)] < 小数桁 { return (商のリスト: 商のリスト, 循環小数位: 余りの小数桁[Int(余り)]) } if 商のリスト[Int(小数桁)] != 0 { return (商のリスト: 商のリスト, 循環小数位: 小数桁) } #else // 余りの小数桁を辞書型に改良 var 小数桁 = UInt64(0) var 余りの小数桁 = Dictionary() repeat { 小数桁 += 1 余りの小数桁[余り] = 小数桁 余り &*= 10 商 = 余り / 分母 商のリスト.append(商) 余り %= 分母 } while 余りの小数桁[余り] == nil if let 桁 = 余りの小数桁[余り], 桁 < 小数桁 { return (商のリスト: 商のリスト, 循環小数位: 桁) } if 商のリスト[Int(小数桁)] != 0 { return (商のリスト: 商のリスト, 循環小数位: 小数桁) } #endif return (商のリスト: 商のリスト, 循環小数位: UInt64(0)) } func 商のリストと循環小数位から文字列(_ 商のリスト: [UInt64], _ 循環小数位: UInt64) -> String { var 小数点以下の文字列 = 商のリスト[1...].reduce("", { $0 + "\($1)" }) if 0 < 循環小数位 { if 循環小数位 < 商のリスト[1...].count { let index = 小数点以下の文字列.index(小数点以下の文字列.startIndex, offsetBy: Int(循環小数位)) 小数点以下の文字列.insert("\u{0307}", at: index) } return "\(商のリスト[0])." + 小数点以下の文字列 + "\u{0307}" } else { return "\(商のリスト[0])." + 小数点以下の文字列 } } func 循環小数の文字列から商のリストと循環小数位(_ 循環小数の文字列: String) -> ([UInt64], UInt64) { let 循環小数の文字列の整数部と小数部 = 循環小数の文字列.split(separator: ".") let 循環小数の文字列の小数部 = String(循環小数の文字列の整数部と小数部[1].unicodeScalars.filter({ $0 != "\u{0307}" })) var 商のリスト = [UInt64]() var 循環小数位 = UInt64(0) if let index = 循環小数の文字列の整数部と小数部[1].unicodeScalars.firstIndex(of: "\u{0307}") { 循環小数位 = UInt64(index.utf16Offset(in: 循環小数の文字列の整数部と小数部[1])) } 商のリスト.append(UInt64(String(循環小数の文字列の整数部と小数部[0]))!) 商のリスト.append(contentsOf: 循環小数の文字列の小数部.map { UInt64(String($0))! }) return (商のリスト, 循環小数位) } /*: #### 最大公約数 3_1 を参照 #### 最小公倍数 3_1 を参照 #### 役分 分子と分母をそれらの最大公約数で最大公約数が 1 になるまで繰り返し割っていくと「役分」となる */ func 最大公約数(_ x: UInt64, _ y: UInt64) -> UInt64 { var x = x, y = y while y != 0 { (x, y) = (y, x % y) } return x } func 最小公倍数(_ x: UInt64, _ y: UInt64) -> UInt64 { return x &* y / 最大公約数(x, y) } func 最大公約数(_ x: [UInt64]) -> UInt64 { if var 公約数 = x.first { for y in x.dropFirst() { 公約数 = 最大公約数(y, 公約数) } return 公約数 } else { return 0 } } func 最小公倍数(_ x: [UInt64]) -> UInt64 { if var 公倍数 = x.first { for y in x.dropFirst() { 公倍数 = 最小公倍数(y, 公倍数) } return 公倍数 } else { return 0 } } func 役分(分子: UInt64, 分母: UInt64) -> (分子: UInt64, 分母: UInt64) { let 約数 = 最大公約数(分子, 分母) return (分子: 分子 / 約数, 分母: 分母 / 約数) } for (x, y) in [ (42, 54), (28, 98), ] { let x = UInt64(x), y = UInt64(y) print(x, y, "最大公約数: \(最大公約数(x, y)), 最小公倍数: \(最小公倍数(x, y))") } for x in [ // 例題19 [UInt64]([ 42, 54 ]), [UInt64]([ 16, 28, 40 ]), // 練習19 [UInt64]([ 28, 98 ]), [UInt64]([ 36, 54, 135 ]), ] { print(x, "最大公約数: \(最大公約数(x)), 最小公倍数: \(最小公倍数(x))") } do { var numeratorAndDenominatorList = Array(repeating: (UInt64(2), UInt64(3)), count: 8/* これ以上増やすと実行時エラー */) let f = UInt64(256) for (i, _) in numeratorAndDenominatorList.enumerated() { for _ in 0.. UInt64 { var r = UInt64(1) for _ in 0.. UInt64 { var r = r for _ in 0.. (分子: UInt64, 分母: UInt64) { var 分子 = UInt64(0), 分母 = UInt64(1) for n in 商のリスト.dropFirst() { 分子 &*= 10 分母 &*= 10 分子 += n } if 0 < 循環小数位 { let 循環小数桁数 = UInt64(商のリスト.dropFirst().count) - (循環小数位 - 1) /* 0.7̇ は 10𝑥 = 7̇ … (1) 100𝑥 = 77̇ … (2) ここで、(2)-(1) (100 - 10)𝑥 = 77̇ - 7̇ = 70 𝑥 = 70/90 = 7/9 1.0̇9̇ の 0.0̇9̇ は 100𝑥 = 0̇9̇ … (1) 10000𝑥 = 090̇9̇ … (2) ここで、(2)-(1) (10000 - 100)𝑥 = 090̇9̇ - 0̇9̇ = 0900 𝑥 = 900/9900 = 1/11 0.40̇9̇ は 1000𝑥 = 40̇9̇ … (1) 100000𝑥 = 4090̇9̇ … (2) ここで、(2)-(1) (100000 - 1000)𝑥 = 4090̇9̇ - 40̇9̇ = 40500 𝑥 = 40500/99000 = 9/22 (𝑥 = 40900/99000 = 409/990 となったら誤り) 0.123456789̇ は 100000000𝑥 = 123456789̇ … (1) 1000000000𝑥 = 1234567899̇ … (2) ここで、(2)-(1) (1000000000 - 100000000)𝑥 = 1234567899̇ - 123456789̇ = 1111111110 𝑥 = 1111111110/900000000 = 12345679/100000000 以上を鑑みて、一般化する 分母𝑥 = 分子 … (1) 10^{循環小数桁数}分母𝑥 = 10^{循環小数桁数}分子 + 分子 … (2) ここで、(2)-(1) (10^{循環小数桁数}分母 - 分母)𝑥 = 10^{循環小数桁数}分子 - 分子 - 10^{循環小数桁数}⌊(10^{-循環小数桁数}分子)⌋ */ 分子 = pow10(循環小数桁数)&*分子 &- pow10(循環小数桁数)&*divpow10(分子, 循環小数桁数) 分母 = pow10(循環小数桁数)&*分母 &- 分母 } (分子, 分母) = 役分(分子: 分子, 分母: 分母) return (分子: 商のリスト[0]&*分母 + 分子, 分母: 分母) } print("有理数から循環小数") for (分子, 分母) in [ // 例題27 (3, 8), (7, 9), (12, 11), (5, 7), // 練習27 (31, 125), (9, 22), (11, 37), (90, 13), (3, 11), // 応用 (1111111100, 9000000000), (1111111101, 9000000000), (1111111102, 9000000000), (1111111103, 9000000000), (1111111104, 9000000000), (1111111105, 9000000000), (1111111106, 9000000000), (1111111107, 9000000000), (1111111108, 9000000000), (1111111109, 9000000000), (1111111110, 9000000000), ] { let (商のリスト, 循環小数位) = 循環小数(UInt64(分子), UInt64(分母)) let 分数 = 商のリストと循環小数位から分数(商のリスト, 循環小数位) let 役分した分数 = 役分(分子: UInt64(分子), 分母: UInt64(分母)) print("\(分子)/\(分母)=\(役分した分数.分子)/\(役分した分数.分母)", 商のリストと循環小数位から文字列(商のリスト, 循環小数位), "\(分数.分子)/\(分数.分母)") } print("循環小数から有理数") for 循環小数の文字列 in [ // 例題28 "0.68", "0.2̇7̇", // ちなみに「上付きドット」は Unicode U+0307(Swift \u{0307}) を「絵文字と記号の表示(Emoji & Symbols)⌃⌘スペース」の文字ビューアか何かで入力できます "0.704̇", // 練習28 "0.475", "0.4̇05̇", "2.03̇1̇", // 応用 "0.3̇", "0.9̇", "0.123456789", "0.1̇23456789̇", "0.12̇3456789̇", "0.123̇456789̇", "0.1234̇56789̇", "0.12345̇6789̇", "0.123456̇789̇", "0.1234567̇89̇", "0.12345678̇9̇", "0.123456789̇", "9.876543210", "9.8̇76543210̇", "9.87̇6543210̇", "9.876̇543210̇", "9.8765̇43210̇", "9.87654̇3210̇", "9.876543̇210̇", "9.8765432̇10̇", "9.87654321̇0̇", "9.876543210̇", ] { let (商のリスト, 循環小数位) = 循環小数の文字列から商のリストと循環小数位(循環小数の文字列) let 分数 = 商のリストと循環小数位から分数(商のリスト, 循環小数位) let 商のリストと循環小数位 = 循環小数(分数.分子, 分数.分母) print(商のリストと循環小数位から文字列(商のリスト, UInt64(循環小数位)), "\(分数.分子)/\(分数.分母)", 商のリストと循環小数位から文字列(商のリストと循環小数位.商のリスト, 商のリストと循環小数位.循環小数位)) } /*: ### 西来路 文朗, 清水 健一: 素数はめぐる 循環小数で語る数論の世界(ブルーバックス), 2017/2/15 より */ print("有理数から循環小数") for (分子, 分母) in [ // P.14... (1, 7), (2, 7), (3, 7), (4, 7), // P.28, P.52 (1, 11), (1, 13), (1, 17), // 元には戻せない、UInt64 の範囲を超えてしまう (1, 19), (1, 23), // 求まらない、UInt64 の範囲を超えてしまう (1, 29), // 〃 /*(1, 47), // 〃 (1, 59), // 〃 (1, 61),*/ // 〃 /*(1, 97),*/ // 実行時エラー // P.64 (1, 101), (1, 103), (1, 107), /*(1, 109), // 実行時エラー (1, 113), (1, 127),*/ // P.105 (1, 13), (10, 13), (9, 13), (12, 13), (3, 13), (4, 13), (2, 13), (7, 13), (5, 13), (11, 13), (6, 13), (8, 13), // P.107 (1, 3), (2, 3), // P.107 (1, 7), // P.107 (1, 11), (10, 11), (2, 11), (9, 11), (3, 11), (8, 11), (4, 11), (7, 11), (5, 11), (6, 11), ] { let (商のリスト, 循環小数位) = 循環小数(UInt64(分子), UInt64(分母)) let 分数 = 商のリストと循環小数位から分数(商のリスト, 循環小数位) let 役分した分数 = 役分(分子: UInt64(分子), 分母: UInt64(分母)) print("\(分子)/\(分母)=\(役分した分数.分子)/\(役分した分数.分母)", 商のリストと循環小数位から文字列(商のリスト, 循環小数位), "\(分数.分子)/\(分数.分母)") } print("循環小数から有理数") for 循環小数の文字列 in [ // P.14... "0.1̇42857̇", "0.2̇85714̇", "0.4̇28571̇", "0.5̇71428̇", // P.28, P.52 "0.0̇9̇", "0.0̇76923̇", //"0.0̇588235294117647̇", // なぜか、計算が終わらない "0.0̇52631578947368421̇", //"0.0̇434782608695652173913̇", // なぜか、計算が終わらない //"0.0̇344827586206896551724137931̇", // 〃 /*"0.0̇212765957446808510638297872340425531914893617̇", // とんでもなく遅いので、やらない "0.0̇169491525423728813559322033898305084745762711864406779661̇", // 〃 "0.0̇16393442622950819672131147540983606557377049180327868852459̇", // 〃 "0.0̇10309278350515463917525773195876288659793814432989690721649484536082474226804123711340206185567̇",*/ // 〃 // P.64 "0.0̇099̇", // P.105 "0.0̇76923̇", "0.7̇69230̇", "0.6̇92307̇", "0.9̇23076̇", "0.2̇30769̇", "0.3̇07692̇", "0.1̇53846̇", "0.5̇38461̇", "0.3̇84615̇", "0.8̇46153̇", "0.4̇61538̇", "0.6̇15384̇", // P.107 "0.3̇", "0.6̇", // P.107 "0.1̇42857̇", // P.107 "0.0̇9̇", "0.9̇0̇", "0.1̇8̇", "0.8̇1̇", "0.2̇7̇", "0.7̇2̇", "0.3̇6̇", "0.6̇3̇", "0.4̇5̇", "0.5̇4̇", ] { let (商のリスト, 循環小数位) = 循環小数の文字列から商のリストと循環小数位(循環小数の文字列) let 分数 = 商のリストと循環小数位から分数(商のリスト, UInt64(循環小数位)) let 商のリストと循環小数位 = 循環小数(分数.分子, 分数.分母) print(商のリストと循環小数位から文字列(商のリスト, UInt64(循環小数位)), "\(分数.分子)/\(分数.分母)", 商のリストと循環小数位から文字列(商のリストと循環小数位.商のリスト, 商のリストと循環小数位.循環小数位)) } //: [Next](@next)