Pebble Coding

ソフトウェアエンジニアによるIT技術、数学の備忘録

C++最適化手法

メモリ使用量が増えてもよいので速度を優先させたい場合の最適化方法を考えます。

  • 計算した値をキャッシュし計算回数を減らす
  • 同じ値の設定処理を何度も行わない
  • 関数の戻り値では、構造体の値を返す代わりに構造体のconst参照を返す
  • クラスの不要な関数を削除する、不要な機能のインターフェース実装があれば削除する
  • 不要なら空のデストラクタを定義しない

Effective Modern C++ ―C++11/14プログラムを進化させる42項目

Effective Modern C++ ―C++11/14プログラムを進化させる42項目

swift 循環参照

swift 循環参照の一例を挙げます。

iOSのソースを例にとります。

ViewController.swift

import UIKit
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let model = Model()
        model.action()
    }
}

Model.swift

import Foundation

class Model {
    private let message:String = "hello"
    private var myclosure:((Void)->Void)?
    
    init()
    {
        print("Model init")
        
        myclosure = {
            print("\(self.message)")
        }
    }
    
    deinit
    {
        print("Model deinit")
    }
    
    func action(){
        myclosure?()
    }
}

ここでmodelはローカル変数ですから、viewDidLoadを抜けた時は破棄されるはずです。 しかし結果は以下のようになり、"Model deinit"が表示されませんからdeinitが呼ばれず、破棄されていないことが分かります。

Model init
hello

原因は、myclosureがselfを強参照した結果、modelがmyclosureを、myclosureがmodelを互いに参照してるためです。 ガベージコレクション方式でない、リファレンスカウンタ方式のメモリ管理方式を採用している言語ではこのようなことが起こります。 Modelのinit()を以下のように修正すると、破棄されるようになります。

init()
{
    print("Model init")
       
    myclosure = { [unowned self] in // <- 修正
        print("\(self.message)")
    }
}

結果

Model init
hello
Model deinit

このケースでは、actionメソッドを実行中にmodelのインスタンスがなくなってしまうことはありませんので、 [unowned self]を使えばよいです。
ただし、actionメソッドを実行中にmodelのインスタンスnilになってしまうことがあるような複雑なケースの場合は、[weak self]を使います。この場合、少しタイピング量が増えて、以下のような書き方になります。

init()
{
    print("Model init")
        
    myclosure = { [weak self] in 
        if let weakself = self { 
            print("\(weakself.message)")
        }
    }
}

selfがnilになってしまっても、オプショナルで判定して処理をスキップすることができます。

iOS/MacOSXのvDSP関数、多すぎてなかなか見つけられないのをなんとかする(応用編)

複素数を扱うためにvDSP.hで定義された構造体

typedef struct DSPComplex {
    float  real;
    float  imag;
} DSPComplex;

typedef struct DSPSplitComplex {
    float  * __nonnull realp;
    float  * __nonnull imagp;
} DSPSplitComplex;

1次元高速フーリエ変換

vDSP_create_fftsetup
vDSP_destroy_fftsetup

1次元高速フーリエ変換(In-Place Complex)

vDSP_fft_zip         テンポラリバッファ未使用
vDSP_fft_zipt        テンポラリバッファ使用

1次元高速フーリエ変換(Out-Of-Place Complex)

vDSP_fft_zop       テンポラリバッファ未使用
vDSP_fft_zopt      テンポラリバッファ使用

1次元高速フーリエ変換(In-Place Real)

vDSP_fft_zrip       テンポラリバッファ未使用
vDSP_fft_zript      テンポラリバッファ使用
vDSP_fftm_zrip      複数信号,テンポラリバッファ未使用
vDSP_fftm_zript     複数信号,テンポラリバッファ使用

vDSP_fft_zripの引数

vDSP_Length Log2N -> 要素数を2の何乗かで指定します。要素数が1024なら210=1024なので10を指定します。
FFTDirection
Direction -> kFFTDirection_Forward: フーリエ変換, kFFTDirection_Inverse : 逆変換

参考: Using Fourier Transforms

1次元高速フーリエ変換(Out-of-Place Real)

vDSP_fft_zrop       テンポラリバッファ未使用
vDSP_fft_zropt      テンポラリバッファ使用
vDSP_fftm_zrop      複数信号,テンポラリバッファ未使用
vDSP_fftm_zropt     複数信号,テンポラリバッファ使用

1次元高速フーリエ変換(固定長)

vDSP_FFT16_copv     16要素 interleaved
vDSP_FFT32_copv     32要素 interleaved
vDSP_FFT16_zopv     16要素 split
vDSP_FFT32_zopv     32要素 split

2次元高速フーリエ変換(In-Place Real)

vDSP_fft2d_zrip
vDSP_fft2d_zript

2次元高速フーリエ変換(Out-of-Place Real)

vDSP_fft2d_zrop
vDSP_fft2d_zropt

離散フーリエ変換

vDSP_DFT_zop_CreateSetup
vDSP_DFT_zrop_CreateSetup
vDSP_DFT_DestroySetup
vDSP_DFT_Execute

離散コサイン変換

vDSP_DCT_CreateSetup
vDSP_DCT_Execute

相関,畳み込み

vDSP_conv           2つの実ベクターの相関または畳み込み
vDSP_zconv          2つの複素ベクターの相関または畳み込み
vDSP_wiener         ウィーナフィルタとして使えるFIRフィルタの生成
vDSP_desamp         デシメーション,アンチエイリアスするFIRフィルタ
vDSP_zrdesamp       デシメーション,アンチエイリアスするComplex-real FIRフィルタ
vDSP_f3x3           3x3カーネルでの2次元畳み込みで画像をフィルタ
vDSP_f5x5           5x5カーネルでの2次元畳み込みで画像をフィルタ
vDSP_imgfir         1カーネルでの2次元畳み込みで画像をフィルタ

ウィンドウ

vDSP_blkman_window
vDSP_hamm_window
vDSP_hann_window

単一チャネル4次IIRフィルタ

vDSP_biquad_CreateSetup
vDSP_biquad_DestroySetup
vDSP_biquad

複数チャネル4次IIRフィルタ

vDSP_biquadm_CreateSetup
vDSP_biquadm_DestroySetup
vDSP_biquadm_ResetState
vDSP_biquadm_SetActiveFilters
vDSP_biquadm_SetCoefficientsSingle
vDSP_biquadm_SetCoefficientsDouble
vDSP_biquadm_SetTargetsSingle
vDSP_biquadm_SetTargetsDouble
vDSP_biquadm_biquadm

複素ベクター変換

vDSP_ctoz   DSPComplex から DSPSplitComplex へ変換
vDSP_ztoc   DSPSplitComplex から DSPSplitComplex へ変換

floatから24ビット整数への変換

vDSP_vsmfix24
vDSP_vsmfixu24
vDSP_vflt24
vDSP_vfltu24
vDSP_vfltsm24
vDSP_vfltsmu24

Rx メモ

RxSwiftとRxCocoaの区別がわかりづらいのでメモ。
RxCocoaはUIKit,NSFoundationなどに特化したiOS/macOS環境特有の機能。

RxSwift

  • combileLatest

仕様:複数の変数のいずれかが変更された場合にそれぞれの最新の値をまとめて受け取る
使い道:2つのUITextFieldに入力した値の合計をUILabelに表示する場合など

extension Observable {
    public static func combineLatest<O1: ObservableType, O2: ObservableType>
        (_ source1: O1, _ source2: O2, resultSelector: @escaping (O1.E, O2.E) throws -> E)
            -> Observable<E>
}
  • Variable

仕様:BehaviorSubject のラッパー
使い道:

public final class Variable<Element>

RxCocoa

  • orEmpty

仕様:String?型をString型に変換する。nilの場合は"“に変換される。
使い道:UILabelのタイトルなどString型のプロパティに設定する場合など

public protocol ControlPropertyType : ObservableType, ObserverType {
    func asControlProperty() -> ControlProperty<E>
}

extension ControlPropertyType where E == String? {
    public var orEmpty: ControlProperty<String>
}
  • bindTo

仕様:
使い道:

extension ObservableType {    
    public func bindTo<O: ObserverType>(_ observer: O) -> Disposable where O.E == E
}
  • drive

仕様:
使い道:

extension SharedSequenceConvertibleType where SharingStrategy == DriverSharingStrategy {
    public func drive<O: ObserverType>(_ observer: O) -> Disposable where O.E == E
}