どれだけの人が必要かわかりませんが、物理学とかやってると「AA ± aa」みたいな文言見たことあるんじゃ無いかと思います。つまり「正確には AA になるはずだが、実際の環境においてはそんな超絶に精密にぴったりそんな結果になるわけがないから、上下に aa の誤差がある」と言うようなことです。例えば 1kg の水が欲しいとき、測量機器によってそんなに精密に 1kg の水が出てくることはほとんどないから、例えばプラマイ 10g の誤差でも OK だよ、と言ったときに、1kg ± 10g で 990g ~ 1010g のニュアンスを表すことがよくあります。
Swift では範囲演算子 ...
があるので、990 ... 1010
で書けば上記のその範囲を表すことができますが、ぱっと見「欲しいのは 1kg でプラマイの 10g は誤差だよ」と言うことはなかなか読み取りにくいと思います。そこで 1000 ± 10
で 990 ... 1010
を表したいと思いました。というわけで早速演算子を定義します:
infix operator ± : RangeFormationPrecedence
extension Numeric where Self: Comparable {
public static func ± (lhs: Self, rhs: Self) -> ClosedRange<Self> {
let added = lhs + rhs
let subtracted = lhs - rhs
let lowerBound = min(added, subtracted)
let upperBound = max(added, subtracted)
return lowerBound ... upperBound
}
}
ここで Swift 4 の Numeric
というプロトコルを使っています。このプロトコルは何のためにあるのかというと中に使っている +
と -
の演算子が使えるということを保証しています。そしてなぜあえて (lhs - rhs) ... (lhs + rhs)
を使わずに lowerBound
と upperBound
をそれぞれ min
と max
で定義しているのかというと、実際の利用時に rhs
の値がマイナスになることも十分ありうると考えていますので、確実に lowerBound
と upperBound
を計算しました。
これで 1000 ± 10
を書けば 990 ... 1010
の範囲を返してくれます。便利ズイ₍₍(ง˘ω˘)ว⁾⁾ズイ
P.S.1
「 ±
どうやって入力するの」というツッコミをいただきましたが、まあ US 配列なら Opt
+ Shift
+ =
で ±
を入力できます。JIS は知らん。
P.S.2
ちなみに実用的な使い道として、iPhone の画面サイズが 16:9 かどうかを判定するときに、実際の計算ではぴったり 16.0 / 9.0
と結果が一致することがあまりないです(唯一一致するのは iPhone 6+ の 736.0 / 414.0
です)ので、逆に ((16.0 / 9.0) ± 0.01).contains(568.0 / 320.0)
というふうに判定することができます。ちなみに自分はさらに …=
という演算子も作っています。