浮動小数点数とビット表現の変換

浮動小数点数をビット表現に変換したり、ビット表現を浮動小数点数に変換したりすることが多いので、コンバータを作ってみました。

github.com

bfloat16以外の浮動小数点数なら、pythonでも以下のように変換できます。

 $ python3
Python 3.8.2 (default, Jul 16 2020, 14:00:26) 
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import struct
>>> hex(struct.unpack('Q', struct.pack('d', 1.0))[0])
'0x3ff0000000000000'
>>> hex(struct.unpack('I', struct.pack('f', 1.0))[0])
'0x3f800000'
>>> hex(struct.unpack('H', struct.pack('e', 1.0))[0])
'0x3c00'
>>> struct.unpack('d', struct.pack('Q', 0x3ff0000000000000))[0]
1.0
>>> struct.unpack('f', struct.pack('I', 0x3f800000))[0]
1.0
>>> struct.unpack('e', struct.pack('H', 0x3c00))[0]
1.0

上から順番に

  • fp64->hex
  • fp32->hex
  • fp16->hex
  • hex->fp64
  • hex->fp32
  • hex->fp16

です。

ハイティング代数の勉強

J. ヨスト著, 清水勇二訳 現代数学の基本概念 上 を読んでいて、p.35 の練習問題が難しかったので、この問題について書いておく。

p.35の練習問題とは、ハイティング代数において以下を示すことだ。

 t \Rightarrow (s \Rightarrow u) = t \land s \Rightarrow u

ハイティング代数は0と1を持つ束で冪対象 u^{s} =  s \Rightarrow uを持つ。

冪対象の記法で書くと示したいことは以下になる。

 (u^{s})^{t} = u^{t \land s}

 xを任意の元として、次の①と②, ②と③は一対一に対応する。ここで \to \leを表す。

 x \land t \land s \to u

 x \land t \to u^{s}

 x \to (u^{s})^{t}

また、 yを任意の元として、次の④と⑤は一対一対応する。

 y \land t \land s \to u

 y \to u^{t \land s}

もし①で x u^{t \land s}とした射があるならば、③の x u^{t \land s}を代入して、射

 u^{t \land s} \to (u^{s})^{t}

が存在する。すなわち以下が成り立つ。

 u^{t \land s} \le (u^{s})^{t}

一方、もし④で y (u^{s})^{t}とした射があるならば、⑤の y (u^{s})^{t}を代入して、射

 (u^{s})^{t} \to u^{t \land s}

が存在する。すなわち以下が成り立つ。

 (u^{s})^{t} \le u^{t \land s}

したがって、 u^{t \land s} \le (u^{s})^{t},  (u^{s})^{t} \le u^{t \land s}, 反対称律より

 (u^{s})^{t} = u^{t \land s}

となる。

あとは、 u^{t \land s} \land t \land s \le u (u^{s})^{t} \land t \land s \le uを示せばよい。

まず、 u^{t \land s} \land t \land s \le uは、 u^{t \land s} \le u^{t \land s}から成り立つことがわかる。

次に、 (u^{s})^{t} \land t \land s \le uは、次のように示す。

 (u^{s})^{t} \le (u^{s})^{t} \Leftrightarrow (u^{s})^{t} \land t \le u^{s} \Leftrightarrow (u^{s})^{t} \land t \land s \le u

Kleisli圏の単位律と結合律

西郷 甲矢人 (著), 能美 十三 (著) 圏論の道案内 ~矢印でえがく数学の世界~ (数学への招待シリーズ) の「第9章モナド」で、モナドから随伴を作るときにKleisli圏という圏が登場した。

この記事では、Kleisli圏の単位律と結合律についてまとめてみる。

まず、圏 C上のモナド Tとは、組 \langle T, \eta, \mu \rangleであり、以下の図式を可換にするものである。

f:id:yabaniyatun:20191014195735p:plain

ここで、 T, \eta, \muは、関手 T: C \to C, 自然変換 \eta: id_C \Rightarrow T, 自然変換 \mu: TT \Rightarrow T

Kleisli圏はモナドに関連して考えられる圏である。 モナド Tに関するKleisli圏 C_{T}の対象 X_{T}は、圏 Cの対象 Xと同じであり、圏 C_{T}の射 f_{T}: X_{T} \to Y_{T}は、圏 Cの射 f: X \to T(Y)に対応する。

対象 X_{T}の恒等射 1_{X_{T}}: X_{T} \to X_{T}は、圏 Cの射 \eta_{X}: X \to T(X)に対応する。

 f_{T}: X_{T} \to Y_{T} g_{T}: Y_{T} \to Z_{T}の合成 g_{T} \circ_{T} f_{T}: X_{T} \to Z_{T}は、圏 Cの射 \mu_{Z} \circ T(g) \circ f: X \to T(Z)に対応する。

ここで、このように定義した恒等射が単位律を満たすこと、それから、このように定義した射および射の合成が結合律を満たすことを示したい。

まずは、恒等射が単位律を満たすこと、すなわち、任意の f_{T}: X_{T} \to Y_{T}に対して、

 f_{T} \circ_{T} 1_{X_{T}} = 1_{Y_{T}} \circ_{T} f_{T} = f_{T}

が成り立つことを示す。

 Cにおいて、

 \mu_{Y} \circ T(f) \circ \eta_{X} = \mu_{Y} \circ T(\eta_{Y}) \circ f = f

が成り立つことを示せばよい。

 \etaの自然性を表す図式とモナド Tの定義に使った2番目の可換図式を組み合わせた以下の図式が可換であることから、上の式が成り立つことがわかる。

f:id:yabaniyatun:20191014203533p:plain

よって、恒等射が単位律を満たすことが示せた。

次に、射および射の合成が結合律を満たすこと、すなわち

 f_{T}: X_{T} \to Y_{T}, g_{T}: Y_{T} \to Z_{T}, h_{T}: Z_{T} \to W_{T}

に対して、

 (h_{T} \circ_{T} g_{T}) \circ_{T} f_{T} = h_{T} \circ_{T} (g_{T} \circ_{T} f_{T})

が成り立つことを示す。

 Cにおいて、

 \mu_{W} \circ T(\mu_{W} \circ T(h) \circ g) \circ f = \mu_{W} \circ T(h) \circ (\mu_{Z} \circ T(g) \circ f)

が成り立つことを示せばよい。

 \mu_{W} \circ T(\mu_{W} \circ T(h) \circ g) \circ f = \mu_{W} \circ T(\mu_{W}) \circ TT(h) \circ T(g) \circ f

ここで、モナド Tの定義の1番目の可換図式から、以下の図式が可換であることがわかる。

f:id:yabaniyatun:20191014205033p:plain

よって、上の式は以下になる。

 \mu_{W} \circ \mu_{T(W)} \circ TT(h) \circ T(g) \circ f

 \muの自然性を表す以下の可換図式が書けるので、

f:id:yabaniyatun:20191014205629p:plain

上の式は以下になる。

 \mu_{W} \circ T(h) \circ \mu_{Z} \circ T(g) \circ f = \mu_{W} \circ T(h) \circ (\mu_{Z} \circ T(g) \circ f)

射および射の合成が結合律を満たすことが示せた。

図式を書くのに使ったTexソース

\documentclass[12pt]{ujarticle}
\usepackage{amsmath,amsfonts,amsthm,amssymb,amscd}
\usepackage[all]{xy}
\def\objectstyle{\displaystyle}
\begin{document}
\[
\xymatrix{
  TTT \ar@{=>}[r]^{T\mu} \ar@{=>}[d]_{\mu T} & TT \ar@{=>}[d]^{\mu} \\
  TT \ar@{=>}[r]_{\mu} & T
}
\]
\[
\xymatrix{
  T \ar@{=>}[r]^{T\eta} \ar@{=>}[rd]_{1_T} & TT \ar@{=>}[d]^{\mu} & T \ar@{=>}[l]_{\eta T} \ar@{=>}[ld]^{1_T} \\
  & T &
}
\]
\[
\xymatrix{
  X \ar[r]^{f} \ar[d]_{\eta_X} & T(Y) \ar[d]^{T(\eta_Y)} \ar[rd]^{1_{T(Y)}} \\
  T(X) \ar[r]_{T(f)} & TT(Y) \ar[r]_{\mu_Y} & T(Y)
}
\]
\[
\xymatrix{
  TTT(W) \ar[r]^{T(\mu_W)} \ar[d]_{\mu_{T(W)}} & TT(W) \ar[d]^{\mu_W} \\
  TT(W) \ar[r]_{\mu_W} & T(W)
}
\]
\[
\xymatrix{
  TT(Z) \ar[r]^{TT(h)} \ar[d]_{\mu_Z} & TTT(W) \ar[d]^{\mu_{T(W)}} \\
  T(Z) \ar[r]_{T(h)} & TT(W)
}
\]
\end{document}

C言語で浮動小数点数をビットパターンに変換する方法

1.0の64bit浮動小数点数、32bit浮動小数点数、16bit浮動小数点数でのビットパターンを求めます。

a.c

#include <stdio.h>
#include <stdint.h>


int main() {
  union A {
    double d;
    float f;
    _Float16 f16;
    uint64_t i64;
  };

  union A a;
  a.d = 1.0;

  printf("64bit 0x%lx\n", a.i64 & 0xFFFFFFFFFFFFFFFF);
  a.f = 1.0;
  printf("32bit 0x%lx\n", a.i64 & 0xFFFFFFFF);
  a.f16 = 1.0;
  printf("16bit 0x%lx\n", a.i64 & 0xFFFF);

}

コンパイルして、実行すると以下になります。

$ clang a.c
$ ./a.out 
64bit 0x3ff0000000000000
32bit 0x3f800000
16bit 0x3c00

Pythonで浮動小数点数をビットパターンに変換する方法

64bit浮動小数点数(1.0の例)

>>> import struct
>>> hex(struct.unpack('<Q', struct.pack('<d', 1.0))[0])
'0x3ff0000000000000'

32bit浮動小数点数(1.0の例)

>>> import struct
>>> hex(struct.unpack('<I', struct.pack('<f', 1.0))[0])
'0x3f800000'

16bit浮動小数点数(1.0の例) Python3.6以上で動く

>>> import struct
>>> hex(struct.unpack('<H', struct.pack('<e', 1.0))[0])
'0x3c00'

Vim練習1

正規表現で検索した文字列を置換する方法

ファイル全体に対して、一括で置換を行うコマンド

:%s/\v<正規表現>/<置換後文字列/g

ドットコマンドを使って置換を行う方法

まず、以下で検索する

/\v<正規表現>

次に1つ目の検索対象を置換する

cgn<置換後文字列>

後は、「n.」を繰り返す

n.の繰り返し

指定の行を現在行の下にコピー/ムーブする方法

例) 6行目を現在行の下にコピーする

:6t.

例) 6行目を現在行の下にムーブする

:6m.

アクティブなディレクトリにあるファイルを開く方法

今、<ディレクトリ>/aaa.txt を編集しているとする。
<C-w>vで画面分割して、隣に<ディレクトリ>/bbb.txt を表示させたい。
<C-w>l で隣の画面に移動して、以下のコマンドでbbb.txtが開ける。

:e <ディレクトリ>/bbb.txt

<ディレクトリ>のパスが長いときは、この方法は面倒だ。

そこで、以下のようにすると<ディレクトリ>/が自動で入力される。

:e %:h<TAB>

自分用メモ ARM64クロスコンパイルとx86_64での実行

参考サイト

qiita.com

環境はx86_64, Ubuntu 18.04.2 LTS。

まず、qemuとg++-aarch64-linux-gnuを以下のようにインストール。

$ sudo apt-get install qemu
$ sudo apt-get install g++-aarch64-linux-gnu

helloworld.c

#include <stdio.h>

int main() {
  printf("hello world\n");
  return 0;
}

ロスコンパイル

$ aarch64-linux-gnu-gcc -o helloworld_arm64 helloworld.c

fileコマンドを実行してみる

$ file helloworld_arm64 
helloworld_arm64: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 3.7.0, BuildID[sha1]=0b7252ec780aca58b8d0d95f117438281433d569, not stripped

実行

$ qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./helloworld_arm64 
hello world

以下のようにスタティックリンクすると、qemu-aarch64を使わなくても実行できるのはなぜ? 勝手に裏でqemu-aarch64が実行される?

$ aarch64-linux-gnu-gcc -o helloworld_arm64_static -static helloworld.c
$ ./helloworld_arm64_static 
hello world