Pebble Coding

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

swift preconditionとassertの違い

swiftにはassertさせる関数がいっぱいあって困ります。

1) assert()

let ary = [1, 2, 3]
let i = 3
assert(i < ary.count)
print("\(ary[i])")

assertion failed: file /develop/aaa/aaa/ViewController.swift, line 18

2) precondition()

let ary = [1, 2, 3]
let i = 3
precondition(i < ary.count)
print("\(ary[i])")

precondition failed: file /develop/aaa/aaa/ViewController.swift, line 18

3) fatalError()

let ary = [1, 2, 3]
let i = 3
if i < ary.count {
} else {
    fatalError()
}
print("\(ary[i])")

fatal error: file /develop/aaa/aaa/ViewController.swift, line 19

1) -> 2) -> 3) の順番で致命的なエラーになっていくようです。 fatalErrorはコンパイラがその部分での戻り値の存在チェックをしなくなるので、仮の戻り値を書かずに済みます。

正直な感想として、preconditionはいらねえと思います。

swfit/rust 負数の除法

swift,C,Javaとruby, python,perlでは、 負数を割り算や剰余に使った場合、結果が異なる。

python 剰余

7 % 3 -> 1
7 % -3 -> -2
-7 % 3 -> 2
-7 & -3 -> -1

swift 剰余

7 % 3    -> 1
7 % -3   -> 1
-7 % 3   -> -1
-7 % -3  -> -1

python 商

7 / 2 -> 3
7 / -2 -> -4
-7 / 2 -> -4
-7 / -2 -> 3

swift 商

7 / 2 -> 3
7 / -2 -> -3 
-7 / 2  -> -3
-7 / -2  -> 3

swiftの除法をユークリッド除法と呼び、 剰余を割られる値のsignに合わせる。

pythonの除法を絶対的最小剰余と呼び、割り切れない場合はマイナス無限大方向に丸める。

除法 - Wikipedia

rust

rustはc/swift/java系統と同じである。

7 % 3    -> 1
7 % -3   -> 1
-7 % 3   -> -1
-7 % -3  -> -1
7 / 2 -> 3
7 / -2 -> -3 
-7 / 2  -> -3
-7 / -2  -> 3

なお、BigIntも同じ。

rustでpython,haskelと同じようにするには、divremクレートのDivFloor,RemFloorを使えばよい。

ios10.3 ファイルパス問題

環境 ios10.3.1
Xcode 8.3.2

        guard let path:String = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first else {
            return
        }
        let filename0 = path + "/" + "a.txt"
        if let fp0 = fopen(filename0, "wb") {
            print("fp0 \(fp0)")
        } else {
            print("fp0 is nil")
        }
        
        let filename1 = path + "/" + "ぱ.txt"
        if let fp1 = fopen(filename1, "wb") {
            print("fp1 \(fp1)")
        } else {
            print("fp1 is nil")
        }
        
        let fm = FileManager.default
        try? fm.createDirectory(atPath: path + "/ぱ", withIntermediateDirectories: true, attributes: nil)
        
        let filename2 = path + "/ぱ/" + "ぴ.txt"
        if let fp2 = fopen(filename2, "wb") {
            print("fp2 \(fp2)")
        } else {
            print("fp2 is nil")
        }
        
        let filename3 = path + "/ぱ/" + "b.txt"
        if let fp3 = fopen(filename3, "wb") {
            print("fp3 \(fp3)")
        } else {
            print("fp3 is nil")
        }
        
        let filename4 = (filename3 as NSString).fileSystemRepresentation
        if let fp4 = fopen(filename4, "wb") {
            print("fp4 \(fp4)")
        } else {
            print("fp4 is nil")
        }
[結果]
fp0 0x0000000100d01c78
fp1 0x0000000100d11808
fp2 is nil
fp3 is nil
fp4 0x0000000100c16da8

fopenでのファイル作成では、濁点、半濁点名を付けたフォルダ名をパスに含むとfopenに失敗するようです。
fopenに渡す場合はNSStringのfileSystemRepresentationで変換すればよいようです。

参考:

https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/APFS_Guide/FAQ/FAQ.html#//apple_ref/doc/uid/TP40016999-CH6-DontLinkElementID_3:Apple APFS Guide

iOS10.3のファイルパス問題について

macOSにSPTKをインストール

macOS 10.12.4

xgrを動かすのに必要なのでconfigure前に入れておきます。

$ brew cask install quartz

あとは、 SPTK-3.10.tar.gzをDLし、

$ configure
$ make
$ make install

したら完了です。

参考

SPTKの使い方 (1) インストール・波形描画・音声再生 - 人工知能に関する断創録

sayコマンドで喋らせたものをwavファイルへ出力する。
句読点を入れた方が、ちゃんとしたイントネーションになります。

$ say "あらゆる現実を、全て、自分のほうへねじ曲げたのだ" -o ~/a.wav --data-format=LEI16@16000

wavファイルをrawに変換(waveヘッダを除去)

$ wav2raw a.wav

C++11 unique_ptrとshared_ptr

unique_ptrは所有者が1人以下のポインタとして利用する。
実装にatomic関数は用いられていないためコピーや破棄はスレッドセーフではないが、それによるオーバーヘッドは存在しない。

shared_ptrは所有者が2人以上のポインタとして利用する。
いったん値を設定した後は、コピーや破棄はスレッドセーフに動作する。
shared_ptr<T>とした場合は、Tのデストラクタは最後に所有を解放したスレッドで一度だけ実行されることが保証される。
実装にはatomic関数が用いられているため、その分のオーバーヘッドがある。
例えば、ThreadAで

shared_ptr<T> a = shared_ptr<T>(new T); // 生成
shared_ptr<T> b = a // コピー

としたとき、同時にThreadAがaのnon-constなメソッドを実行、threadBがbのnon-constなメソッドを実行してもスレッド安全性は保たれる。
各スレッドがそのスレッド専用のshared_ptrにアクセスする分には安全ということである。
同時にThreadAがaのconstなメソッドを実行、ThreadBがnon-constなメソッドを実行した場合、動作は未定義である。

ここまでがネットを漁った結果得た知識である。


以下、ネット上の情報を羅列しておく。

shared_ptrはC++11でのプリミティブな型が持つスレッドセーフ性のみを持つ。
つまり、同一のshared_ptrに対して、
例1) ThreadA : read, ThreadB : read -> スレッドセーフ
例2) ThreadA : read, ThreadB : write -> 動作未定義
例3) ThreadA : write, ThreadB : write -> 動作未定義
となる。

参照1
std::shared_ptr - cppreference.com

“全てのメンバ関数(コピーコンストラクタとコピーアサインメントを含む)は異なるshared_ptrのインスタンスにおいて、複数のスレッドから呼び出せる。 この呼び出しでは、それらのインスタンスがコピーであり、同一のオブジェクトの所有権を共有している場合においてさえも、追加の同期処理は不要である。 複数のスレッドが同じshared_ptrに対して同期処理なしで、shared_ptrにアクセスし、shared_ptrのnon-const関数を使った場合、データレースが起こりうる。 データレースを防ぐには、atomic関数のshared_ptrオーバーロードを使うことにより、データレースの発生を防ぐことができる。”

“All member functions (including copy constructor and copy assignment) can be called by multiple threads on different instances of shared_ptr without additional synchronization even if these instances are copies and share ownership of the same object. If multiple threads of execution access the same shared_ptr without synchronization and any of those accesses uses a non-const member function of shared_ptr then a data race will occur; the shared_ptr overloads of atomic functions can be used to prevent the data race.”

参照2
shared_ptr - 1.53.0

“shared_ptr objects offer the same level of thread safety as built-in types. A shared_ptr instance can be "read” (accessed using only const operations) simultaneously by multiple threads. Different shared_ptr instances can be “written to” (accessed using mutable operations such as operator= or reset) simultaneosly by multiple threads (even when these instances are copies, and share the same reference count underneath.) Any other simultaneous accesses result in undefined behavior."

ここで複数のスレッドから呼び出せると書いてあるが、同時に安全に呼び出せるとは書いていない。
同期処理なしで同時に安全に呼び出せるのは、constのメンバ関数だけであるということである。

メンバ関数でconstとnon-constがあるらしいので、挙げておこう。
constructor : non-const
destructor : non-const
operator= : non-const
reset : non-const
swap : non-const
get : const
operator* : const
operator-> : const
use_count : const
unique : const
operator bool : const
owner_before : const

参照3

Lesson #4: Smart Pointers | Mike's C++11 Blog

“unique_ptrと異なり、shared_ptrは他のshared_ptrへのコピーを可能とし、ポインタは常にただ一度のみdeleteされることが保証される。全てのshared_ptrオブジェクトが保持しているものが破棄された時に。 これにはリファレンスカウントが用いられ、同じポインタを保持するshared_ptrがどのくらいの数あるかを保持する。このリファレンスカウントはアトミック関数が用いられるため、スレッドセーフである。”

“Unlike unique_ptr, it also allows copying of the shared_ptr object to another shared_ptr, and then ensures that the pointer is still guaranteed to always be deleted once (but not before) all shared_ptr objects that were holding it are destroyed (or have released it).

It does this using reference counting – it keeps a shared count of how many shared_ptr objects are holding the same pointer. This reference counting is done using atomic functions and is thus threadsafe."

“どのスレッドが最後にオブジェクトを完了させるのか分からない場合、各スレッドにオブジェクトを参照するshared_ptrを与えればよい。 しかし、各スレッドにそのオブジェクトは一つを与えることをここで注意しておく。shared_ptrクラスは以下の場合においてスレッドセーフではない。 2つのスレッドが同時にただ一つのshared_ptrオブジェクトにアクセスする場合において。 スレッド安全性は各スレッドが自身のshared_ptrオブジェクトにアクセスする場合にのみ保証される。”

“When you’re not sure which thread will finish needing an object last, you can simply give each thread a shared_ptr that references the object. However, note here that I said that you give each thread one such object. The shared_ptr class is not thread-safe for the case that two threads try to access the same shared_ptr object concurrently. Rather, thread-safety is ensured as long as each thread has their own shared_ptr objects (which may in turn all share+reference the same pointer).”