2023/09/30(Sat)値のビット幅を拡縮するとき

はてブ数 2023/09/30 18:44 つーさ
値のビット幅を拡縮するとき

16bitデータを8bitに落としたり、8bitデータを計算のために32bit表現にしたりすることある思考整理メモ。

unsinged

画像データとかはこっちだな。

落とすときはそのまま右shiftする。

落とすときはそのまま右shiftする。まぁ。普通?

拡張するときは2択?

1つは単純に左シフトする方法。
つまり、u8をu16にするとき、8bit左シフトする=256を乗ずる。
この方法は最大値は最大値にならない。
u8をu16にするとき、255*256は65535にならず、65280になる。
u8をu24にするとき、255*65536は16777215にならず、16711680になる。

これは、unsigned型は 0 から 1-(1/2**bit数)までを表現でき 1.0を表現できないとする立場(立場?)とも言える。
65535 は 1.0 ではなく 1.0-1/65536 = 0.9999847412109375 である世界の計算。

色の処理をするときはあんまよくない。
たとえば、255の赤が65535の赤にならないので色がくすむ。
もう1つは、元のビット幅の1を繰り返したものを乗ずる方法。
元のビット幅分左シフトしては元の値を足すことを繰り返す方法とも言う。
これは、当該unsigned型の表現可能な最大値(255とか65535とか) が 1.0 である世界。
最大値が最大値として復元される努力をする感じ。

つまり、u8をu16にするとき、 8bitの1 = 0x01 を、上から16bit分繰り返した 0x0101 = 257を乗ずる。(=8左シフトしてから元の値を足す)
u8をu16にするとき、255*257は65535になる。
u8をu24にするとき、255*0x010101(65537)は16777215になる。
こっちは、255の赤を65535の赤にできる。

ビット数が整数倍じゃないとき丸まってしまう。
たとえば、7bitの値を23bitにするとき
7bitの1 0b0000001 を 23bitになるまで繰り返した 0b00000010000001000000100=66052を乗ずると、
127*66052=8388604 で、23bit unsigned の最大値は 8388607にはならない。

こういうケースで最大値がほしいときは、普通に 8388607/127 (= 約66052.0236220) を掛けないといけない。
割り算を嫌うなら、7bit左シフトしてから元の値を足すを4回繰り返して一旦28bit表現にしてから右5bit落として23bit表現にする、をしてもできる。
7bitの1である 0b0000001を4回繰り返した 0b0000001000000100000010000001=2113665を掛けてから、32で割る(5ビット右シフトする)感じ。

signed

音声波形データとかはこっちで表現されよう。

正負で表現可能な段階数が違うので面倒。

落とすとき

正のs16をs8に落とすとき、32767/127 = 約258.00787で割る
負のs16をs8に落とすとき、32768/128 = 約256.00000で割る
正負によって除数が変わる。

はぁ?

そもそもsigned型では 0から+1の距離と 0から-1の距離が異なるのですか?
0から+1と0から-1の距離は一致するが、負の方にだけ表現できる幅が少し広いと考えるべきでは?
なら、より幅の広い負に配慮して、どっちも256で割りましょうか。。

ただし、s16の絶対値を256で割ってs8にしてはダメ。
負について256で割ったあとfloorしないといけない。
0方向丸めしてしまうと、0付近 s16の[-15,+15]の31要素がs8の0になってしまい歪む。
floorすれば、s16の[0,+15]の16要素がs8の0、[-16,-1]の16要素がs8の-1になる。

s16の世界にあった65536種類の値を256個ずつグループにまとめて、256種類の値に射影したいと考えると、
結果的には、unsignedと同じで、落としたいビット数分だけ右シフトするんでよさそう。

拡張するときは?

拡張するときは?
正負によって表現できる幅が違うので、単純に最大値を最大値にマップすることはできない。
とりあえず、素直に拡張したいビット数分左シフトする方法が1つ。
s8をs16にするとき、
+1は+256に、+127は+32512になる。
-1は-256に、-127は-32512に、-128は-32768になる。
最大値に配慮する方法も考えてみてはおく。
「+127が最大」か「-128が最小」か?
「+127が最大」だよ派
ビット拡張先の正の最大値をビット拡張前の最大値で割ったものを係数にする。
s8をs16にするとき、 32767/127≒258.0078740 なので、試しに 258.008 を掛けてみると、
+127が +32767.016 くらいになる
-127が -32767.016 くらいになる
-128は -33025.024 くらいになって、オーバーフローしちゃう(それはそう)。
うーん、元データの性格にもよるけど、-128 なんてなかった(-127と同値として扱う)と割り切るのは、1つのやり方としてはなくはないか?
変換を何度も行った場合の値の保存性は?
「-128が最小」だよ派
拡張先の負の最小値を拡張前の負の最小値で割ったものを係数にする。
これは、 1<<(拡張したいビット数) になるので、先に書いた単純左シフトと同じになる。
「+127が最大」かつ「-128が最小」だよ派
「正のとき 258.0078740 を掛け、負のとき 256.0を掛ける」条件分岐をする。
[0,+2]の距離と [-1,+1]の距離が変わっちゃう。
これは最初に割る話をしたときと同じであんまり筋がよくないと思う。考えない。

あとは、floatと行き来するとき……

signedは負方向に広い。 「-1.0を-32768とする」か「-1.0を-32767とする」かの2択。
上で書いたけど s16の+32767を+1.0、-32768を-1.0など定義してしまうと0を境界に「1の幅」が変わって歪む。
「-1.0を-32768とする」
とき、変換時 32768 を係数に乗算・除算することになる。
デメリットがあって、s16では、-1.0を-32768として表現できるが+1.0を表現できなくなる。
s16で表現できる範囲は、 1/32768 = 0.000030517578125 を用いて、-1.0 から +0.999969482421875 = (1-1/32768) となる。
「-1.0を-32767とする」
とき、変換時 32767で乗算・除算することになる。
こっちは、+32767で1.0を表現できるので一見よさそうだけど、
その一方で-32768は 1+1/32767 (=約-1.000030518509476) になるので、
係数とかに使うときはちょっと気にしといた方がいいのかしら。
また整数型に戻すときはsaturationするだろうし、まぁそんなに気にしなくてもいい気もする。

「-1.0を-32768とする」よりは「-1.0を-32767とする」こっちの方が素直かしらという感覚になるのが不思議。
signed整数型では +1.0 を表現できないんじゃなかったの?
signed整数型を [-1.0, +1.0-ε] の範囲じゃなくて [-1.0-ε, +1.0] として扱おうとしてるってことね。

unsinged のときは、255とか65535とかで掛けたり割ったりすると思うのでそれと一緒ね。

というか、まず、その整数型の最小値と最大値が [-1.0, +1.0-ε] を表すのか、[-1.0-ε, +1.0] を表すのかを考える方がよさそ。
unsignedでも 最小値と最大値が[0, +1.0-ε]なのか[0, +1.0]なのかを考えるのがよさそ。まぁ、unsignedは普通は後者だけど。

😌

2023/04/01(Sat)C++でJSONを読み書き

はてブ数 2023/04/01 7:04 つーさ
JSON読み書き用の個人的なライブラリとして、
また単純なプログラミングの興味としてC++でJSONをparse/serializeするやつをいじる熱がちょっと再燃して
https://github.com/ttsuki/nanojson などいじっていた。

あんまり巷のライブラリを検索したりはしてなかったんだけど、
ふとC++ JSONでググると、nlohmann/json を解説してくれてるQiita記事とかが出てきた。

nlohmann/jsonは、あー名前は見たことあるかも、と思って、記事読んでみると、
ADLでto_json探すのとか、名前空間汚したくなければシリアライザクラスの特殊化しろとか、
割と同じところにいきついていて、まぁ、普通に考えるとそうなるんだわなぁというconfidenceと引き換えに熱が冷めた。

C++でJSONを読み書きしたかったのだが、
C++でJSONをかっこよく読み書きできるようにしたくなってしまった、のは良くなくて、というかそもそも、
C++でJSONを読み書きしたかったわけではないはずだ。(どういう意味か?)

新年度ですね。新規性のあることをせねばなぁ。

2023/03/03(Fri)CapsLockキーをCtrlにするやつ

はてブ数 2023/03/03 3:55 つーさ
SysInternals Ctrl2cap のかわり capsctrl.reg 自分用。(本編終わり)

なんとなく、メインマシンのWindowsをクリーンインストールした。

最新devチャの Windows11 25300 のISOをとってきて中身をUSBメモリにコピーしてインストール。
Build 25300.rs_prerelease.230210-1451。さっぱり。インストールしたてのWindowsは気持ちさくさく動く感あるね。

SysInternals Ctrl2cap を /install して再起動したらキーボード何にもきかなくなってしまった。
ログインパスワード入れられないー。実際にはもう一度Windows再インストールからやったけど、
On-Screen Keyboard使えば、マウスポチポチして入れた……。

再現検証と思ってもういっかい、Ctrl2cap入れて再起動したら再発したので、一応FeedbackHubに投げた。
もう使えないのかなこれ。まぁ、👆のレジストリの書き換えすれば別にカーネルモードのフィルタドライバなんか入れる必要ないからいいんだけど。

2020/03/02(Mon)Vagrant / CentOS 8 / gcc 9 (Visual Studio からの remote build/debug) / apache / ffmpeg / nginx-rtmp-module 環境構築メモ

はてブ数 2020/02/29 10:05 つーさ

自分のためのメモ

「ffmpegを呼び出してライブストリームをごにょごにょして独自形式のコンテナにMuxしてhttpでストリーミングするアプリケーション」を作りたくなったので、 Visual Studio で、C++ コンソールアプリケーション(Linux) としてプロジェクトを作って、CentOS 8上でリモートビルドしてApache に載せてCGIとして動かしてみるために、 vagrant で VMを用意して、CentOS 8 上に、g++ と apache と ffmpeg を準備します。

WSLは、そのうち……(ずっと、そのうち……って言ってる気がする)

続きを読む

2019/07/13(Sat)Cygwin php + PhpStorm Xdebug で、PHPなWebアプリをブレークポイント仕掛けてデバッグする

はてブ数 2019/07/13 8:21 つーさ

忘れる前にメモ。

まだcygwinなんか使ってるの? WSLにしたら? という心の声も聞こえるが、 postgresもphpも入れるだけで動くし慣れ親しんでいるのもあって、開発環境としては手軽なので。でも、vagrantやdockerが手軽に使えるようになってきて、世の中の人からみたらきっと少数派になりつつあるのだろう。

Cygwin に postgres 入れて、 php アプリの開発環境にしている。

$ php -S localhost:8000

で動く built-in server で、xdebug で PhpStorm から ブレークポイントしたい話。

XdebugのPre-built なバイナリは、PHP公式ビルド向けしかない。

急がば回れ。 PHP公式ビルド入れるかで入れた。ら、pdo_pgsql を有効にするとセグる。うーん、よくわかんない。

急がば回れ。その2。Xdebugソースからcygwin用にソースからビルドすればいいんじゃね?

https://github.com/xdebug/xdebug から、clone して、readmeのとおりに rebuild.sh すると、コンパイルエラーで止まる。ググると、 https://stackoverflow.com/questions/29752441/mac-xdebug-make-warning-incompatible-pointer-types-initializing-jmp-buf-ak が引っかかったので、

#ifdef HAVE_SIGSETJMP
#       define SETJMP(a) sigsetjmp(a, 0)
#       define LONGJMP(a,b) siglongjmp(a, b)
#       define JMP_BUF sigjmp_buf
#else
#       define SETJMP(a) setjmp(a)
#       define LONGJMP(a,b) longjmp(a, b)
#       define JMP_BUF jmp_buf
#endif

を、 xdebug_handler_dbgp.c の上の方に書いて、1032行目を

JMP_BUF          *original_bailout = EG(bailout);

にしたら、makeできた。make installした。

cygwin の php は、 /etc/php.d/ の下にある ini を読んでくれるので、

/etc/php.d/xdebug.iniを作って、

[Xdebug]
zend_extension="xdebug.so"
xdebug.remote_enable=1
xdebug.remote_port="9000"

と書いたら、phpinfo に xdebug 出てきた。

後は、PhpStorm のマニュアル https://pleiades.io/help/phpstorm/creating-php-web-application-debug-configuration.html に書いてあるとおりに進めたら、なんかデバッグブレークできた。

めでたしめでたし。

2019/03/28(Thr)Docker on Ubuntu on Windows Subsystem for Linux で php:apache をなんとか動かすまで

はてブ数 2019/03/28 6:00 つーさ

結論から言うと、
hello-world は docker バージョンを 17.12.1 に下げることで動いたんだけど、

php:apache はちょっと変なことをしないと動かなかった。
どうも docker コンテナ内のfsでsymlinkを追跡できなかったり、
ファイルやディレクトリを消してもゴミが残ってファイルが消えなかったり、
なんか、謎の挙動をする。

# Dockerfile
FROM php:apache
RUN rm /var/lock && mkdir /var/lock  && chmod 1777 /var/lock
RUN rm /var/run  && cp -rp /run /var/run
RUN mkdir /etc/apache2/mods-enabled/mpm_event.conf /etc/apache2/mods-enabled/mpm_event.load

一応、phpinfo を拝むことはできた。

WSLでDockerを開発環境にするのは、まだしんどそう。

dockerに触ったことがなくて、ちょっと勉強しようと思って、環境の作り方を調べていた。

最近、WSLでdockerが動くらしいという。
普通はDocker for Windowsらしいのだけど、マシンが非力なので、Hyper-Vじゃない環境で動かせるならその方がいい。
というか、Hyper-V有効にしたらvagrant動かなくなってしまう。ちょっと困る。

WSLのインストールからUbuntuをWindows上で動かして、その上にdockerを入れてみようと思った。

が、すんなりとは行かなかったので、正しい挙動(?)を見るために、結局途中でDocker for Windowsも入れた。
*1

続きを読む

2019/03/22(Fri)screen から tmux に乗り換えた

はてブ数 2019/03/22 3:04 つーさ
psql内でCtrl+Rして、長い文が履歴に引っかかったときに、カーソル位置とかなんかおかしくなる。
TERMを正しくすればいい気がするけど、よくわからん*1

tmux試してみようかな、で1週間くらい前からお試し中。

ただ、端末は、指先のように使いたいのであって、
新しいキーバインドに慣れたいというモチベーションはもはやない。

なので、主に、screen で自分が使っているキーバインドに近くなるように、
ググっていろんなところから mixture した自分用 .tmux.conf を↓に

続きを読む