Pebble Coding

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

Windowsでgo環境を作る場合の備忘録

Windowsにgoをインストールする場合

ここ https://golang.org/dl/

にあるインストーラー go1.8.windows-amd64.msi

をダウンロードして実行する

GOROOTはC:\go\ となる。

GOPATHは未設定の状態となるので、デフォルトでは %USERPROFILE%\go となる。

goのソースは一つのユーザー環境で一カ所にしか置けない構造にしないといけない。

例えば、D:\develop\にgoのソースを置きたければ、

GOPATHという環境変数にD:\develop\goと入れればよい。

「システム」-「システムの詳細設定」-「環境変数

例えばsampleというアプリを作るのであれば、 D:\develop\go\src\sample というフォルダを作る gitリポジトリはD:\develop\go\で初期化すればいいだろう。

Windows8環境でHTTPサーバを立ち上げる場合、 「コントロールパネル」-「Windowsファイアウォール」-「Windowsファイアウォールの有効化」でファイアウォールを切っておく必要がある。

SIMD組み込み関数が多すぎるので一覧にしておく

大量の計算を常に行うような場合、C言語の速度をさらに上げるには、CPUのSIMD命令に置き換えられる組み込み関数を使う方法がある。 ただし、これもvDSPと同じで量が多くまた見やすい一覧がないので作ってみる。 なお、独断と偏見で使いそうもないものは一覧に載せていない。

__m128 _mm_load_ss(float * p) r0 := *p r1 := 0 r2 := 0 r3 := 0
__m128 _mm_load1_ps(float * p) r0 := *p r1 := *p r2 := *p r3 := *p
__m128 _mm_load_ps(float * p) r0 := p[0] r1 := p[1] r2 := p[2] r2 := p[3] The address must be 16-byte aligned
__m128 _mm_loadu_ps(float* p) r0 := p[0] r1 := p[1] r2 := p[2] r3 := p[3] The address does not need to be 16-byte aligned
__m128 _mm_loadr_ps(float* p) r0 := p[3] r1 := p[2] r2 := p[1] r3 := p[0] The address must be 16-byte aligned

__m128 _mm_set_ss(float w) r0 := w r1 := 0 r2 := 0 r3 := 0
__m128 _mm_set1_ps(float w) r0 := w r1 := w r2 := w r3 := w
__m128 _mm_set_ps(float z, float y, float x, float w) r0 := w r1 := x r2 := y r3 := z
__m128 _mm_setr_ps(float z, float y, float x, float w) r0 := z r1 := y r2 := x r3 := w
__m128 _mm_setzero_ps(void) r0 := 0 r1 := 0 r2 := 0 r3 := 0

void _mm_store_ss(float * p, __m128 a) *p := a0
void _mm_store1_ps(float * p, __m128 a) p[0] := a0 p[1] := a0 p[2] := a0 p[3] := a0
void _mm_store_ps(float *p, __m128 a) p[0] := a0 p[1] := a1 p[2] := a2 p[3] := a3 The address must be 16-byte aligned
void _mm_storeu_ps(float *p, __m128 a) p[0] := a0 p[1] := a1 p[2] := a2 p[3] := a3 The address does not need to be 16-byte aligned
void _mm_storer_ps(float * p, __m128 a) p[0] := a3 p[1] := a2 p[2] := a1 p[3] := a0 The address must be 16-byte aligned
__m128 _mm_move_ss(__m128 a, __m128 b) r0 := b0 r1 := a1 r2 := a2 r3 := a3

__m128 _mm_add_ss(__m128 a, __m128 b) r0 := a0 + b0 r1 := a1 r2 := a2 r3 := a3
__m128 _mm_add_ps(__m128 a, __m128 b) r0 := a0 + b0 r1 := a1 + b1 r2 := a2 + b2 r3 := a3 + b3
__m128 _mm_sub_ss(__m128 a, __m128 b)
__m128 _mm_sub_ps(__m128 a, __m128 b)
__m128 _mm_mul_ss(__m128 a, __m128 b)
__m128 _mm_mul_ps(__m128 a, __m128 b)
__m128 _mm_div_ss(__m128 a, __m128 b)
__m128 _mm_div_ps(__m128 a, __m128 b)
__m128 _mm_sqrt_ss(__m128 a, __m128 b)   ルート
__m128 _mm_sqrt_ps(__m128 a, __m128 b)   ルート
__m128 _mm_rcp_ss(__m128 a, __m128 b)    逆数
__m128 _mm_rcp_ps(__m128 a, __m128 b)    逆数
__m128 _mm_rsqrt_ss(__m128 a, __m128 b)  ルートを取ってから逆数
__m128 _mm_rsqrt_ps(__m128 a, __m128 b)  ルートを取ってから逆数
__m128 _mm_min_ss(__m128 a, __m128 b)
__m128 _mm_min_ps(__m128 a, __m128 b)
__m128 _mm_max_ss(__m128 a, __m128 b)
__m128 _mm_max_ps(__m128 a, __m128 b)

__m128 _mm_shuffle_ps(__m128 a, __m128 b, int i)

_MM_SHUFFLE(z, y, x, w) (z<<6) | (y<<4) | (x<<2) | w

        例
        a[0] = 0;
        a[1] = 1;
        a[2] = 2;
        a[3] = 3;
        b[0] = 4;
        b[1] = 5;
        b[2] = 6;
        b[3] = 7;
        __m128 m1 = _mm_loadu_ps(a);
        __m128 m2 = _mm_loadu_ps(b);
        __m128 m3 = _mm_shuffle_ps(m1, m2, _MM_SHUFFLE(3, 2, 1, 0));
        _mm_storeu_ps(c, m3);
        printf("c[0] %f c[1] %f c[2] %f c[3] %f", c[0], c[1], c[2], c[3]);
        c[0] 0.0 c[1] 1.0 c[2] 6.0 c[3] 7.0 
        _MM_SHUFFLEの第3,4引数がm1から選択するもの、第1,2引数がm2から選択するもの

        __m128 m3 = _mm_shuffle_ps(m1, m2, _MM_SHUFFLE(1, 1, 1, 1));
        c[0] 1.0 c[1] 1.0 c[2] 5.0 c[3] 5.0

__m128 _mm_unpackhi_ps(__m128 a, __m128 b)
r0 := a2
r1 := b2
r2 := a3
r3 := b3

__m128 _mm_unpacklo_ps(__m128 a, __m128 b)
r0 := a0
r1 := b0
r2 := a1
r3 := b1

__m128 _mm_movehl_ps(__m128 a, __m128 b)
r3 := a3
r2 := a2
r1 := b3
r0 := b2

__m128 _mm_movelh_ps(__m128 a, __m128 b)
r3 := b1
r2 := b0
r1 := a1
r0 := a0

int _mm_movemask_ps(__m128 a) r := sign(a3)<<3 | sign(a2)<<2 | sign(a1)<<1 | sign(a0)

__m128 _mm_and_ps(__m128 a , __m128 b ) r0 := a0 & b0 r1 := a1 & b1 r2 := a2 & b2 r3 := a3 & b3
__m128 _mm_andnot_ps(__m128 a , __m128 b ) r0 := ~a0 & b0 r1 := ~a1 & b1 r2 := ~a2 & b2 r3 := ~a3 & b3
__m128 _mm_or_ps(__m128 a , __m128 b ) r0 := a0 | b0 r1 := a1 | b1 r2 := a2 | b2 r3 := a3 | b3
__m128 _mm_xor_ps(__m128 a , __m128 b ) r0 := a0 ^ b0 r1 := a1 ^ b1 r2 := a2 ^ b2 r3 := a3 ^ b3 

__m128 _mm_blend_ps( __m128 a, __m128 b, const int mask )
r0 := (mask0 == 0) ? a0 : b0
r1 := (mask1 == 0) ? a1 : b1
r2 := (mask2 == 0) ? a2 : b2
r3 := (mask3 == 0) ? a3 : b3

__m128 _mm_blendv_ps( __m128 a, __m128 b, __m128 mask )
r0 := (mask0 & 0x80000000) ? b0 : a0
r1 := (mask1 & 0x80000000) ? b1 : a1
r2 := (mask2 & 0x80000000) ? b2 : a2
r3 := (mask3 & 0x80000000) ? b3 : a3

int _mm_extract_ps( __m128 a, const int ndx )
r := (ndx == 0) ? a0 : ((ndx == 1) ? a1 : ((ndx == 2) ? a2 : a3)) 

__m128 _mm_hadd_ps( __m128 a, __m128 b )
The result of the operation on operand a (A3, A2, A1, A0) and operand b (B3, B2, B1, B0) is (B3 + B2, B1 + B0, A3 + A2, A1 + A0).

__m128 _mm_hsub_ps( __m128 a, __m128 b )

void _mm_prefetch(char * p , int i )
Loads one cache line of data from address p to a location closer to the processor.
The value i specifies the type of prefetch operation: the constants _MM_HINT_T0, _MM_HINT_T1, _MM_HINT_T2, and _MM_HINT_NTA, corresponding to the type of prefetch instruction, should be used

void _mm_stream_ps(float * p , __m128 a )
Stores the data in a to the address p without polluting the caches.
The address must be 16-byte aligned.

void _mm_sfence(void)
Guarantees that every preceding store is globally visible before any subsequent store.

SSE2 : SSE の doubleバージョン

__m128  : float(32bit) * 4
__m128d : double(64bit) * 2
__m128i : 整数 shortなら * 8

AVX :
    2011 : Sandy Bridge
    2012 : Ivy Bridge
    2013 : Haswell
    2014 : Broadwell
    2015 : Skylake
    2016 : Kaby Lake
    2017 : Cannonlake

FMA(Fused Multiply Add) Haswell : 2013
AVX-512 : 2013 

SSE Pentium 3 以降
SSE2 Pentium 4 以降
SSE4.1 Core 2 のPenyryn 以降
SSE4.2 Nehalem 以降

Intel Core 2 processor family

for Laptop
Merom  dual (65 nm) July 2006
Penryn dual (45 nm) January 2008

swift Arrayでwhereを使う

swiftはモダンな言語なので、C言語風の書き方は極力排除されている。
Arrayでwhereがついているメソッドを使い条件式を表すクロージャを指定して結果を取得するケースは多い。

public struct Array<Element> : RandomAccessCollection, MutableCollection {

    // 条件を満たす最初の要素インデックス
    // 条件を満たす要素がない場合はnilを返す
    public func index(where predicate: (Element) throws -> Bool) rethrows -> Int?

    // 条件を満たす要素が存在する
    // 存在が確定した時点で以降の判定は行われない
    public func contains(where predicate: (Element) throws -> Bool) rethrows -> Bool

    // 条件を満たす最初の要素
    // 条件を満たす要素がない場合はnilを返す
    public func first(where predicate: (Element) throws -> Bool) rethrows -> Element?

    // 条件を満たす要素の配列を返す
    public func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> [Element]
}

extension Array where Element == String {

    /// Returns a new string by concatenating the elements of the sequence,
    /// adding the given separator between each element.
    ///
    /// The following example shows how an array of strings can be joined to a
    /// single, comma-separated string:
    ///
    ///     let cast = ["Vivien", "Marlon", "Kim", "Karl"]
    ///     let list = cast.joined(separator: ", ")
    ///     print(list)
    ///     // Prints "Vivien, Marlon, Kim, Karl"
    ///
    /// - Parameter separator: A string to insert between each of the elements
    ///   in this sequence. The default separator is an empty string.
    /// - Returns: A single, concatenated string.
    public func joined(separator: String = default) -> String
}

make_moonsで生成されるものを見てみる(scikit-learn)

macOSXにpipをインストールする

sudo easy_install pip

scikit-learnをインストールする

sudo pip install scikit-learn

make_moonsでデータを生成してみる

bash-3.2$ python
>>> from sklearn import datasets, linear_model
>>> datasets.make_moons(10, noise=0.2)
(array([[ 0.18545934,  0.25338198],
       [ 0.06259625,  0.54178011],
       [ 0.8973431 ,  0.79109458],
       [ 1.01893968, -0.07901291],
       [ 2.05387498, -0.08495323],
       [ 1.51625778,  0.50642223],
       [ 0.8542837 , -0.69981578],
       [-0.97062414, -0.15152809],
       [-0.24370697,  0.96853972],
       [ 0.23027146, -0.16437679]]), array([1, 0, 0, 0, 1, 1, 1, 0, 0, 1]))
>>> 

ここでarrayとなっているのはnumpy.array型のことであって、pythonのlistとは異なるものらしい。

swiftでwavファイル書き込みしてみる(AVAudioFIle)

iOSでWAVファイルを書き出す場合、
以前はAudioToolKitにあるAudioFileCreateWithURLを使っていましたが、
ここでは試しにiOS8,macOS10.10で追加されたAVFoundationにあるAVAudioFileを使ってみます。
まず、AVAudioFileのクラス定義をみてみます。

open class AVAudioFile : NSObject {
    public init(forReading fileURL: URL) throws
    public init(forReading fileURL: URL, commonFormat format: AVAudioCommonFormat, interleaved: Bool) throws
    public init(forWriting fileURL: URL, settings: [String : Any]) throws
    public init(forWriting fileURL: URL, settings: [String : Any], commonFormat format: AVAudioCommonFormat, interleaved: Bool) throws
    open func read(into buffer: AVAudioPCMBuffer) throws
    open func read(into buffer: AVAudioPCMBuffer, frameCount frames: AVAudioFrameCount) throws
    open func write(from buffer: AVAudioPCMBuffer) throws
    open var url: URL { get }
    open var fileFormat: AVAudioFormat { get }
    open var processingFormat: AVAudioFormat { get }
    open var length: AVAudioFramePosition { get }
    open var framePosition: AVAudioFramePosition
}

forWritingというのを使いwriteを呼び出してクラスのメモリを解放すれば良さそうです。
AVAudioPCMBufferの定義を見て見ます。

open class AVAudioPCMBuffer : AVAudioBuffer {
    public init(pcmFormat format: AVAudioFormat, frameCapacity: AVAudioFrameCount)
    open var frameCapacity: AVAudioFrameCount { get }
    open var frameLength: AVAudioFrameCount
    open var stride: Int { get }
    open var floatChannelData: UnsafePointer<UnsafeMutablePointer<Float>>? { get }
    open var int16ChannelData: UnsafePointer<UnsafeMutablePointer<Int16>>? { get }
    open var int32ChannelData: UnsafePointer<UnsafeMutablePointer<Int32>>? { get }
}

フォーマットとキャパシティ(=サンプル数)を指定してインスタンスを作り、データを詰めれば良さそうです。

書き込むフォーマットはWindowsで標準的なInt16、サンプルレート44100,チャネル数2,インターリーブであるWAVファイル形式とします。
書き込むデータはLには440Hzのサイン波、Rには523Hzのサイン波を1024サンプルだけ出力することにします。
音の長さは約0.023秒となります。
以下、実装です。

if let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first {
    let path = documentsPath.appending("/test.wav")
    let format:AVAudioFormat = AVAudioFormat(commonFormat: AVAudioCommonFormat.pcmFormatInt16,
                                             sampleRate: 44100,
                                             channels: 2,
                                             interleaved: true)
    if let url = URL(string:path) {
        do {
            // WAVファイルのフォーマットを指定する
            let file:AVAudioFile = try AVAudioFile(forWriting: url,
                                               settings: format.settings, 
                                               commonFormat: format.commonFormat,
                                               interleaved: true)
            // データ書き込みフォーマットを指定する 
            // ここではWAVファイルと同じフォーマットを使う
            let buffer:AVAudioPCMBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: 1024)
            if let p:UnsafePointer<UnsafeMutablePointer<Int16>> = buffer.int16ChannelData {
                let q:UnsafeMutablePointer<Int16> = p.pointee
                var x:Float = 0
                var y:Float = 0
                let delta_x:Float = Float(440 * 2 * M_PI / 44100) // ラ(440Hz)
                let delta_y:Float = Float(523 * 2 * M_PI / 44100) // ド(523Hz)
                for i:Int in stride(from:0, to:1024*2, by: 2) {
                    q[i]   = Int16(sin(x) * 32767.0) // L
                    q[i+1] = Int16(sin(y) * 32767.0) // R
                    x += delta_x
                    y += delta_y
                }
            } else {
                assert(false)
            }
            // メモリに書き込んだサンプル数をセット
            buffer.frameLength = 1024
            // WAVファイルへ書き込み
            try file.write(from: buffer)
        } catch {
            assert(false)
        }
    }
}

ここでは、WAVファイルのフォーマットとデータを書き込む時のフォーマットを同一にしています。
同じにしておくとコンバートが走らないので効率が良いですが、異なるフォーマットでもある程度の範囲内なら
AVAudioFileが勝手にコンバートしてくれたりします。
経験的にはInterleavedやチャネル数が同じでないと動かないです。

interleaved:trueにした場合AVAudioPCMBufferのInt16の領域が1つになりますのでint16ChannelDataから
サンプル数分LRの順序で詰めていけば良いです。 buffer.frameLengthに書き込む値を毎回セットする必要があります。

AudioToolKitで書くよりソースコードが長くなっている気もしますが、
swiftは型安全性を何より優先しますので、こんな感じになります。
ついでに波形画像も載せておきます。

f:id:pebble8888:20170122004906p:plain

GitHub - pebble8888/AudioFileCreateSample