これは、Swiftオプションに関する以前の投稿に続く問題の詳細な説明です。
ここ、 ここ、ここで与えられたリードのおかげで、文字列配列から分数(倍音比の場合)または小数(セントの場合)を読み取って、音階の音符の周波数を計算することができます。
文字列配列の各要素は、最初にテストされて、/
または.
2つの関数のいずれかが含まれているかどうかが確認されます。次に、オプションのチェーンを使用して入力エラーが識別されるため、小数と小数の両方がこのチューニングファイル形式で概説されているルールに準拠します。
例1と1aは、両方の形式で正しく入力されたデータで何が起こるかを示しています。
スケール画分と小数の混合物と
C D E F G Ab B C’
let tuning = [ "1/1", "193.15686", "5/4", "503.42157", "696.57843", "25/16", "1082.89214", "2/1"]
デバッグ領域の列は入力データ(トップダウン)を示し、行は出力周波数(lからr)を示します。
Optional("1/1")
Optional("193.15686")
Optional("5/4")
Optional("503.42157")
Optional("696.57843")
Optional("25/16")
Optional("1082.89214")
Optional("2/1")
[261.62599999999998, 292.50676085897425, 327.03249999999997, 349.91970174951047, 391.22212058238728, 408.79062499999998, 489.02764963627084, 523.25199999999995]
例2と3は、両方の関数が不正な入力(つまり、誤って入力されたデータ)にどのように反応するかを示しています。
不良分数が報告されます(たとえば、分母がない場合はメッセージが出力されます)
Optional("1/1")
Optional("5/")
User input error - invalid fraction: frequency now being set to 0.0 Hertz
Optional("500.0")
Optional("700.0")
Optional("2/1")
[261.62599999999998, 0.0, 349.22881168708938, 391.99608729493866, 523.25199999999995]
不正な小数は報告されません(たとえば、700以降は.0はありません-これによりメッセージが生成されます)
Optional("1/1")
Optional("5/4")
Optional("500.0")
Optional("700")
Optional("2/1")
[261.62599999999998, 327.03249999999997, 349.22881168708938, 0.0, 523.25199999999995]
注:オプションがnilの場合、レポートに加えて0.0(Hz)が行に表示されます。これはコードの他の場所に挿入されました(コメント付きのコンテキストで説明されています)。
一言で言えば問題?分数の関数は障害を報告しますが、10進数の関数は不正な入力を検出できません。
どちらの関数も、ガードステートメントでオプションのチェーンを使用します。これは不完全な分数に対しては機能しますが、関数が小数の誤った入力条件を報告するようにすることは何もしません。コードを徹底的にチェックした後、問題はガードステートメントに設定した条件にあると確信しました。しかし、私はこれを正しく理解することができません。誰かが私が間違ったことを説明できますか?
Tuner.swift
import UIKit
class Tuner {
var tuning = [String]()
let tonic: Double = 261.626 // frequency of middle C
var index = -1
let centsPerOctave: Double = 1200.0 // mandated by Scala tuning file format
let formalOctave: Double = 2.0 // Double for stretched-octave tunings
init(tuning: [String]) {
self.tuning = tuning
let frequency = tuning.flatMap(doubleFromDecimalOrFraction)
print(frequency)
}
func doubleFromDecimalOrFraction(s: String?) -> Double {
index += 1
let whichNumericStringType = s
print(whichNumericStringType as Any) // eavesdrop on String?
var possibleFrequency: Double?
// first process decimal.
if (whichNumericStringType?.contains("."))! {
possibleFrequency = processDecimal(s: s)
}
// then process fractional.
if (whichNumericStringType?.contains("/"))! {
possibleFrequency = processFractional(s: s)
}
// Insert "0.0" marker. Remove when processDecimal works
let noteFrequency = possibleFrequency
let zeroFrequency = 0.0
// when noteFrequency? is nil, possibleFrequency is set to zeroFrequency
let frequency = noteFrequency ?? zeroFrequency
return frequency // TO DO let note: (index: Int, frequency: Double)
}
func processFractional(s: String?) -> Double? {
var fractionArray = s?.components(separatedBy: "/")
guard let numerator = Double((fractionArray?[0])!.digits),
let denominator = Double((fractionArray?[1])!.digits),
numerator > 0,
denominator != 0,
fractionArray?.count == 2
else
{
let possibleFrequency = 0.0
print("User input error - invalid fraction: frequency now being set to \(possibleFrequency) Hertz ")
return possibleFrequency
}
let possibleFrequency = tonic * (numerator / denominator)
return possibleFrequency
}
func processDecimal(s: String?) -> Double? {
let decimalArray = s?.components(separatedBy: ".")
guard let _ = s,
decimalArray?.count == 2
else
{
let denominator = 1
let possibleFrequency = 0.0
print("User input error (value read as \(s!.digits)/\(denominator) - see SCL format, http://www.huygens-fokker.org/scala/scl_format.html): frequency now being forced to \(possibleFrequency) Hertz ")
return possibleFrequency
}
let power = Double(s!)!/centsPerOctave
let possibleFrequency = tonic * (formalOctave**power)
return possibleFrequency
}
}
extension String {
var digits: String {
return components(separatedBy: CharacterSet.decimalDigits.inverted).joined()
}
}
precedencegroup Exponentiative {
associativity: left
higherThan: MultiplicationPrecedence
}
infix operator ** : Exponentiative
func ** (num: Double, power: Double) -> Double{
return pow(num, power)
}
ViewController.swift
import UIKit
class ViewController: UIViewController {
// test pitches: rational fractions and decimal numbers (currently 'good')
let tuning = ["1/1", "5/4", "500.0", "700.0", "2/1"]
// Diatonic scale: rational fractions
// let tuning = [ "1/1", "9/8", "5/4", "4/3", "3/2", "27/16", "15/8", "2/1"]
// Mohajira: rational fractions
// let tuning = [ "21/20", "9/8", "6/5", "49/40", "4/3", "7/5", "3/2", "8/5", "49/30", "9/5", "11/6", "2/1"]
// Diatonic scale: 12-tET
// let tuning = [ "0.0", "200.0", "400.0", "500", "700.0", "900.0", "1100.0", "1200.0"]
// Diatonic scale: mixed 12-tET and rational fractions
// let tuning = [ "0.0", "9/8", "400.0", "4/3", "700.0", "27/16", "1100.0", "2/1"]
// Diatonic scale: 19-tET
// let tuning = [ "0.0", "189.48", "315.8", "505.28", "694.76", "884.24", "1073.72", "1200.0"]
// Diatonic 1/4-comma meantone scale. Pietro Aaron's temperament (1523) : mixed cents and rational fractions
// let tuning = [ "1/1", "193.15686", "5/4", "503.42157", "696.57843", "25/16", "1082.89214", "2/1"]
override func viewDidLoad() {
super.viewDidLoad()
_ = Tuner(tuning: tuning)
}
}
一言で言えば問題?分数の関数は障害を報告しますが、10進数の関数は不正な入力を検出できません。
10進数の関数は、「不正な」入力を検出します。ただし、"700"
は含まれていません。文字列にが含まれている場合に"."
のみ呼び出しprocessDecimal(s:)
ます"."
。文字列が含まれていない場合"."
も含まれていない"/"
、doubleFromDecimalOrFraction(s:)
文字列を解析するために、任意の関数を呼び出すことはありません。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加