Hello, Rust world!

Rustを使ってみました
今回の目標はHello, Rust world!という出力を得ることです

まず、Rustの環境構築を行います OSはWindows10 1809です

rustup.rs

このサイトよりRustツールチェインのインストーラをダウンロードしインストールします(リンクのためにVisual Studio等をインストールする必要があるかも)

インストールが完了したら、rustuprustupcargoコマンドが使えるようになります

ここで、適当なディレクトリに行き、

cargo new helloworld

とコマンドを打ちます すると、helloworldディレクトリが自動で生成されます
中身はこんな感じです

.
└── helloworld
    ├── Cargo.toml
    ├── .git
    │   ├── config
    │   ├── description
    │   ├── HEAD
    │   ├── hooks
    │   │   └── README.sample
    │   ├── info
    │   │   └── exclude
    │   ├── objects
    │   │   ├── info
    │   │   └── pack
    │   └── refs
    │       ├── heads
    │       └── tags
    ├── .gitignore
    └── src
        └── main.rs

main.rsがRustのソースファイルです
一緒にgitのイニシャライズもされてますね
.gitignoreも自動で生成されていますが、出力結果のディレクトリが書いてあったりして便利です
main.rsの中身はこうなっています

fn main() {
    println!("Hello, world!");
}

Hello,Worldのコードは自動で生成されているので、カレントディレクトリをhelloworldディレクトリにして

cargo run

というコマンドでコンパイル、リンク、実行がされます

  Compiling helloworld v0.1.0 (適当なディレクトリ\helloworld)
    Finished dev [unoptimized + debuginfo] target(s) in 2.30s
     Running `target\debug\helloworld.exe`
Hello, world!

ちゃんとHello,world!と出力されていますね
RustでのHello,Worldは以上になります。

fn main() {
    println!("Hello, Rust world!");
}

内容を書き換えて

   Compiling helloworld v0.1.0 (適当なディレクトリ\helloworld)
    Finished dev [unoptimized + debuginfo] target(s) in 1.88s
     Running `target\debug\helloworld.exe`
Hello, Rust world!

これにて目標達成です。

今回のソースをGitHubにあげました(この程度だと必要なさそう)

github.com

高速フーリエ変換の計算量解析

高速フーリエ変換とは、離散フーリエ変換を高速に行うアルゴリズムです。 具体的にどのくらい高速なのか気になったので解析してみます。

まず、離散フーリエ変換について
素数nの入力ベクトルをx、同じく出力の周波数ベクトルをfとすると、離散フーリエ変換は次のような行列積で表されます。

w_n=e^{-\frac{2 \pi}{n}i}とし、
$$ \begin{pmatrix} f_0 \\ f_1 \\ f_2 \\ \vdots \\ f_{n-1} \end{pmatrix} = \begin{pmatrix} w_n^0 & w_n^0 & w_n^0 & \cdots & w_n^0 \\ w_n^0 & w_n^1 & w_n^2 & \cdots & w_n^{n-1} \\ w_n^0 & w_n^2 & w_n^4 & \cdots & w_n^{2(n-1)} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ w_n^0 & w_n^{n-1} & w_n^{2(n-1)} & \cdots & w_n^{(n-1)^2} \end{pmatrix} \begin{pmatrix} x_0 \\ x_1 \\ x_2 \\ \vdots \\ x_{n-1} \end{pmatrix} $$
この行列式は、n^2回の掛け算とn(n-1)回の足し算を必要とするため、計算量は明らかに\Theta(n^2)です。
後々のことを考えて、この真ん中の正方行列に名前をつけておきます $$ M_n= \begin{pmatrix} w_n^0 & w_n^0 & w_n^0 & \cdots & w_n^0 \\ w_n^0 & w_n^1 & w_n^2 & \cdots & w_n^{n-1} \\ w_n^0 & w_n^2 & w_n^4 & \cdots & w_n^{2(n-1)} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ w_n^0 & w_n^{n-1} & w_n^{2(n-1)} & \cdots & w_n^{(n-1)^2} \end{pmatrix} $$ そして、nが2の倍数のとき(仮にn=8の場合)、離散フーリエ変換の式はこのようになります。

$$ \begin{pmatrix} f_0 \\ f_1 \\ f_2 \\ f_3 \\ f_4 \\ f_5 \\ f_6 \\ f_7 \end{pmatrix} = \begin{pmatrix} w_8^0 & w_8^0 & w_8^0 & w_8^0 & w_8^0 & w_8^0 & w_8^0 & w_8^0 \\ w_8^0 & w_8^1 & w_8^2 & w_8^3 & w_8^4 & w_8^5 & w_8^6 & w_8^7 \\ w_8^0 & w_8^2 & w_8^4 & w_8^6 & w_8^8 & w_8^{10} & w_8^{12} & w_8^{14} \\ w_8^0 & w_8^3 & w_8^6 & w_8^9 & w_8^{12} & w_8^{15} & w_8^{18} & w_8^{21} \\ w_8^0 & w_8^4 & w_8^8 & w_8^{12} & w_8^{16} & w_8^{20} & w_8^{24} & w_8^{28} \\ w_8^0 & w_8^5 & w_8^{10} & w_8^{15} & w_8^{20} & w_8^{25} & w_8^{30} & w_8^{35} \\ w_8^0 & w_8^6 & w_8^{12} & w_8^{18} & w_8^{24} & w_8^{30} & w_8^{36} & w_8^{42} \\ w_8^0 & w_8^7 & w_8^{14} & w_8^{21} & w_8^{28} & w_8^{35} & w_8^{42} & w_8^{49} \\ \end{pmatrix} \begin{pmatrix} x_0 \\ x_1 \\ x_2 \\ x_3 \\ x_4 \\ x_5 \\ x_6 \\ x_7 \end{pmatrix} $$ w_8^8=e^{-8\frac{2 \pi}{8}i}=e^{-2 \pi i}=1よりこの式は次の式と等価です。 $$ \begin{pmatrix} f_0 \\ f_1 \\ f_2 \\ f_3 \\ f_4 \\ f_5 \\ f_6 \\ f_7 \end{pmatrix} = \begin{pmatrix} w_8^0 & w_8^0 & w_8^0 & w_8^0 & w_8^0 & w_8^0 & w_8^0 & w_8^0 \\ w_8^0 & w_8^1 & w_8^2 & w_8^3 & w_8^4 & w_8^5 & w_8^6 & w_8^7 \\ w_8^0 & w_8^2 & w_8^4 & w_8^6 & w_8^0 & w_8^2 & w_8^4 & w_8^6 \\ w_8^0 & w_8^3 & w_8^6 & w_8^1 & w_8^4 & w_8^7 & w_8^2 & w_8^5 \\ w_8^0 & w_8^4 & w_8^0 & w_8^4 & w_8^0 & w_8^4 & w_8^0 & w_8^4 \\ w_8^0 & w_8^5 & w_8^2 & w_8^7 & w_8^4 & w_8^1 & w_8^6 & w_8^3 \\ w_8^0 & w_8^6 & w_8^4 & w_8^2 & w_8^0 & w_8^6 & w_8^4 & w_8^2 \\ w_8^0 & w_8^7 & w_8^6 & w_8^5 & w_8^4 & w_8^3 & w_8^2 & w_8^1 \\ \end{pmatrix} \begin{pmatrix} x_0 \\ x_1 \\ x_2 \\ x_3 \\ x_4 \\ x_5 \\ x_6 \\ x_7 \end{pmatrix} $$ そしてこれをこのように変形します(添え字の順番が入れ替わってることに注意) $$ \begin{pmatrix} f_0 \\ f_2 \\ f_4 \\ f_6 \\ f_1 \\ f_3 \\ f_5 \\ f_7 \end{pmatrix} = \begin{pmatrix} w_8^0 & w_8^0 & w_8^0 & w_8^0 & w_8^0 & w_8^0 & w_8^0 & w_8^0 \\ w_8^0 & w_8^2 & w_8^4 & w_8^6 & w_8^1 & w_8^3 & w_8^5 & w_8^7 \\ w_8^0 & w_8^4 & w_8^0 & w_8^4 & w_8^2 & w_8^6 & w_8^2 & w_8^6 \\ w_8^0 & w_8^6 & w_8^4 & w_8^2 & w_8^3 & w_8^1 & w_8^7 & w_8^5 \\ w_8^0 & w_8^0 & w_8^0 & w_8^0 & w_8^4 & w_8^4 & w_8^4 & w_8^4 \\ w_8^0 & w_8^2 & w_8^4 & w_8^6 & w_8^5 & w_8^7 & w_8^1 & w_8^3 \\ w_8^0 & w_8^4 & w_8^0 & w_8^4 & w_8^6 & w_8^2 & w_8^6 & w_8^2 \\ w_8^0 & w_8^6 & w_8^4 & w_8^2 & w_8^7 & w_8^5 & w_8^3 & w_8^1 \\ \end{pmatrix} \begin{pmatrix} x_0 \\ x_2 \\ x_4 \\ x_6 \\ x_1 \\ x_3 \\ x_5 \\ x_7 \end{pmatrix} $$ ここで、 $$ A= \begin{pmatrix} x_0 \\ x_2 \\ x_4 \\ x_6 \end{pmatrix} , B= \begin{pmatrix} x_1 \\ x_3 \\ x_5 \\ x_7 \end{pmatrix} , D_n = \begin{pmatrix} w_{2n}^0 & 0 & 0 & \cdots & 0 \\ 0 & w_{2n}^1 & 0 & \cdots & 0 \\ 0 & 0 & w_{2n}^2 & \cdots & 0 \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & 0 & \cdots & w_{2n}^{n-1} \end{pmatrix} $$ とおくと、w_8^4=-1なので $$ \begin{pmatrix} f_0 \\ f_2 \\ f_4 \\ f_6 \\ f_1 \\ f_3 \\ f_5 \\ f_7 \end{pmatrix} = \begin{pmatrix} M_4 A + D_4 M_4 B \\ M_4 A - D_4 M_4 B \end{pmatrix} $$ これを一般に拡張すると、入力ベクトルをX_n、その半分のベクトルをA_n,B_n (\frac{n}{2}次元のベクトル)、出力ベクトルをF_nとして $$ F_n=M_n X_n = \begin{pmatrix} M_{\frac{n}{2}} A_n + D_{\frac{n}{2}} M_{\frac{n}{2}} B_n \\ M_{\frac{n}{2}} A_n - D_{\frac{n}{2}} M_{\frac{n}{2}} B_n \end{pmatrix} $$ ここで、M_{\frac{n}{2}} A_nM_{\frac{n}{2}} B_nはそれぞれ要素数\frac{n}{2}の離散フーリエ変換であり、1度計算すれば2度使いまわすことができます。
よって、要素数nフーリエ変換の計算量をf(n)で表すとき、 $$ f(n)=f(\frac{n}{2})+f(\frac{n}{2})+\frac{n}{2}+n $$ 回の計算が必要なので、 $$ f(n)=2 f(\frac{n}{2})+\frac{3}{2}n $$ 初期値f(1)=1 (掛け算1回で変換終わり)を考えると $$ f(n)=\frac{3}{2}n \log_2 n+n $$ となります。
よって、高速フーリエ変換の計算量は\Theta(n \log n)です。

【Xamarin.Forms】10分でVisual Studio App Centerを使い始める

1.Visual Studio App Center | iOS, Android, Xamarin & React NativeにアクセスしてSIGN INする

f:id:White_Green:20190317011344p:plain

2.Add new appする

f:id:White_Green:20190317012303p:plain
赤枠の部分は設定が必要です
ほかの部分はよしなに...

3.アプリにSDKを追加する

f:id:White_Green:20190317012813p:plain
Microsoft.AppCenter.*なNuGetパッケージから必要なものをインストールします

4.OnCreate()内にAppCenter.Start()を追加する

f:id:White_Green:20190317013144p:plain
それぞれのプラットフォームごとのトークン(的なの)を設定します
トークンは2.で作ったアプリ管理画面にあります

----------ここまで10分----------

【C#】Dictionary内で最小(最大)のValueをもつアイテムのKeyが知りたい

まとめ

ソートして、最初のやつ
よりも
最大値求めて、foreach
のほうが早そう

コード

最小のValueをもつアイテムのKeyを取得するサンプル

Dictionary<int,int> dict=new Dictionary<int,int>();

//ここでいろいろアイテムを追加する

int maxKey=dict.OrderBy(val=>val.Value).First().Key;

最大のValueのものが欲しい場合は適当に.OrderBy().OrderByDescending()にするなどしてください

書いてて思ったんですけど.Max()で求めた最大値を.Where()foreachかでその値を持つインデックス探すほうが早い気がする

実装にもよるけど
.Max()のオーダーは多分O(n)なので
.OrderBy()のオーダーがO(n \log n)だとしても.Max()のほうが早いかと

ただまあ.OrderBy()のほうは1行で簡単に書けるという利点(?)があるので要素数が少なくて速度を気にしなくていい場合などは使い道があるかも

【C#】nullableの挙動を確認する

int? nullable;
int nonNullable;

とりあえずこんな感じの変数を使います

代入

nonNullable = 10;
nullable = nonNullable;

nullable = 20;
nonNullable = nullable;  //←コンパイルエラー
nonNullable = (int)nullable;

nullable = null;
nonNullable = (int) nullable;  //←System.InvalidOperationException

null非許容型からnull許容型への代入:問題なし
null許容型からnull非許容型への代入:キャストが必要
みたいですね ちなみにnull許容型からnull非許容型へのキャスト時にはちゃんと値が入ってないとExceptionでるのでちゃんとnullチェックするとか??演算子使うとかしましょう

関数

オーバロード

static void Func(int? arg)
{
    Console.WriteLine("Func-nullable");
}

static void Func(int arg)
{
    Console.WriteLine("Func-nonNullable");
}

こんな感じの関数の定義は問題なくできました

実際にこの関数を呼んだ時の動作ですが

nullable = nonNullable = 10;
Func(nullable);             //Func-nullable
Func(nonNullable);          //Func-nonNullable
Func((int?)nonNullable);    //Func-nullable
Func((int)nullable);        //Func-nonNullable

コメントで記述しているように、int?型とint型は別の型と認識されて関数が呼ばれています
キャストすれば型が変わったものと認識されるようです(当たり前か)

別の関数は呼べるのか

関数定義を変更しました

static void Func_Nullable(int? arg)
{
    Console.WriteLine("Func_Nullable");
}

static void Func_NonNullable(int arg)
{
    Console.WriteLine("Func_NonNullable");
}

そして呼び出し側ですが

nullable = nonNullable = 10;
Func_Nullable(nonNullable);
Func_NonNullable(nullable);  //←コンパイルエラー

nullable型の関数にnonNullableを渡すのは問題ないようです
ただ逆はエラーですね キャストしましょう

拡張関数

オーバロード

static class Extensions
{
    public static void ExFunc(this int? arg)
    {
        Console.WriteLine("ExFunc-nullable");
    }

    public static void ExFunc(this int arg)
    {
        Console.WriteLine("ExFunc-nonNullable");
    }
}

定義は問題なくできました
そしてこれを呼び出します

nullable = nonNullable = 10;
nullable.ExFunc();              //ExFunc-nullable
nonNullable.ExFunc();           //ExFunc-nonNullable
((int?)nonNullable).ExFunc();   //ExFunc-nullable
((int)nullable).ExFunc();       //ExFunc-nonNullable
nullable?.ExFunc();             //ExFunc-nonNullable ☆

nullable = null;
nullable.ExFunc();              //ExFunc-nullable
nullable?.ExFunc();             //←関数が呼ばれない   ☆

注目すべきは☆マークのある2つですね nullablenullでないときはint型の関数が呼ばれ、nullのときは関数が呼び出されません この動作は拡張関数でも使えるようです

まとめ

  • キャストすればなんとかなる
  • null許容型変数?.関数名()の構文は拡張関数でも使える

(実は確認したかったのは拡張関数の挙動だけだったりする)

以上

【C#】stringをBASE64エンコードする(ためにstringをbyte[]に変換する)

主題はBASE64エンコードです

BASE64エンコード

バイナリをBASE64エンコードするにはSystem.Security.Cryptography.ToBase64Transformクラス内のTransformBlockTransformFinalBlockメソッドを使います
それぞれ定義はこうです

public int TransformBlock(  //―Blockメソッド
        byte[] inputBuffer,
        int inputOffset,
        int inputCount,
        byte[] outputBuffer,
        int outputOffset
);
public byte[] TransformFinalBlock(  //―FinalBlockメソッド
        byte[] inputBuffer,
        int inputOffset,
        int inputCount
);

引数の上3つは両方同じですね
順に入力データとオフセット(配列のどこから入力を始めるか)と入力のサイズ
―Blockメソッドの引数下二つはエンコード結果の受け取り用配列とその サイズ オフセット
―FinalBlockメソッドのほうは結果の受け取りを戻り値でやる感じでしょうか

さてここで気づくことが一つ
「これ入力も出力もstringじゃなくてbyte[]だ」ですね
ということでstringbyte[]の相互変換です

string⇔byte[]

stringbyte[]間の変換をするにはSystem.Text.Encodingクラス内のGetBytesGetStringメソッドを使います
それぞれ定義は

public virtual byte[] GetBytes(string s);
public virtual string GetString(byte[] bytes);

見ればわかる簡単なやつです
入れれば、変換されて、帰ってくる
わかりずらいのがEncodingクラスのインスタンスの取得ですね
Encodingクラス内にstaticインスタンスがあるのでそれを適当に使うか、同じくstaticGetEncodingメソッドを使います

public static Encoding UTF8 { get; }
public static Encoding UTF7 { get; }
public static Encoding UTF32 { get; }
public static Encoding Unicode { get; }
public static Encoding BigEndianUnicode { get; }
public static Encoding ASCII { get; }
public static Encoding Default { get; }
public static Encoding GetEncoding(string name);

ちなみにBASE64からのデコードはSystem.Security.Cryptography.FromBase64Transform内の同名メソッドが同じ方法で使えるので説明は省略します