2024/05/10(金)自宅鯖りぷれーす
最近(※1年以上前) ノートPCを買い換えたので、
それまで使ってたの*1を自宅鯖その2にしてみることにしました。
QNAP TS-219P+ | ASUS TAICHI 21 | ||
---|---|---|---|
CPU | Marvell 6282 1.6GHz 2C2T | → | Intel Core i5-3337U 1.8GHz (TB 2.7GHz) 2C4T |
メモリ | 512MB | → | 4GB |
ストレージ | HDD 8TB | → | SSD 128GB |
ディストロ的にも、ARM系組み込みLinuxから素直な x64 Ubuntu に変わって、apt と唱えたら大体何でもそろうようになった点が、構築が楽でいいですね() *3
SSDは容量に若干の手狭さを感じつつ、かつ、普通に長期常用してた後なので寿命面も些か心許ないですが、まぁ壊れたらまた考える……。
あとは、Webサーバ機能を載せ替えるのにあわせて、前々から思ってたワイルドカードTLS証明書化とか、そのためにDNSとリバプロをCloudflareに移してみたり *4。
JOYSOUND全国GP.xls を夏色仕様にしてみたり*5。
風邪を引いてゴールデンウィークを2日延長してみたり*6。
今週もお疲れ様でした。
2023/09/30(土)値のビット幅を拡縮するとき
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/08/27(日)自宅鯖その後
浅はかに光クロスを引いたらインターネットから到達可能なIPv4アドレスを失ってしまいました の続き(実際やったのは6月なかごろですが)。
v4からv6 onlyの自宅鯖への繋ぎ方は、L2TPとかNAT46とかいろいろ考えましたが、そも私自身が宅鯖に用がある場合IPv6経由で到達できる環境が(きっと)あるはずで、IPv4からはWEBサーバだけ見えればいい という要件に絞って、普通にHTTPのリバプロを立てる方向でいきます。とりあえず。他の方法は勉強するのはともかく、ちゃんと運用できる自信がない、というのもある……。
肝心の、IPv4を手に入れる方法としては、まぁ普段お仕事で使ってるGCPとかありますけど、GCPはなんか変なトラフィック流されるとパケ死[^1]しちゃう(さもなくばサービス停止)ので、非営利個人が使うにはいまいち怖いんですよね……。そんなにでかいファイルを置いているわけでもないけど、普段の流量を把握しているわけでもなし。今回は他の選択肢、というかまぁレンタルVPSかなぁ……。
[^1]: そういえば全然関係ないですが、パケ死って我々の世代(?)だと、もちろん「高額請求が来る」こと言うと思うんですが、現代では、月あたりの契約容量使い切って低速に制限されることをパケ死って言うらしいですね。(その意味でパケ死が使われてるところを観測したことはないけど)ちょっと面白い。
自宅サーバやる前にレンタルサーバでお世話になっていたさくらと迷いましたが、今回は 清楚かわいいVPS ←クーポン付きアフィリンク を借りてみることにしました。(1回くらい使ってみたかったのと、あとさくらより単に安かった……)
借りたらすぐ使える。管理コンソールがちょっと重い。
とりあえず従量制でRocky Linux鯖を立ててnginxを入れてproxy_passしただけだけど、とりあえずv4からでもこのブログが見えるようになりましたので、まぁこれでいくかということにして、長期クーポンを買って適用。(従量制部分は、利用料17円とかだったかしら)
再び IPv4 環境からも見えるようになりましたー。おわり。
作業内容備忘メモ
2023/08/12(土)C++20のコルーチンでタスクシステム(?)作ってみた
夏休みの自由研究じゃないけど、ふと思い立ってC++20のコルーチンでタスクシステムっぽいものを書いたらどうなるかやってみた。タスクシステムっていうかつまるところファイバーコンテナだけど。
それなりうまくいった
2023/06/08(木)フレッツ光クロスを今すぐに契約すべきではない2つの理由
2023/05/08(月)JavaScript 非同期処理
今まで、fetchとかthenとか、他のコードみて雰囲気で使ってたけど、つまるところ、何がどうなってるのか、ざっくりわかっておきたくなったので、今更ながらちょっと勉強した、その備忘メモ。
JavaScript 非同期処理
JavaScriptはシングルスレッドだけど非同期実行の仕組みがある。古くは setTimeout
だけど、今はPromise
とThenable
なる概念があって、 fetch()
とかがこれで実装されている。
Promise
と Thenable
MDNでは、ある非同期処理Promise
は「待機 (pending) 」「履行 (fulfilled)」「拒否(rejected)」のいずれかの状態を持つと説明される。
意味がとりにくいので、ここではそれぞれを「未完了」「完了:成功」「完了:失敗」とよびかえることにする。
「完了:成功」「完了:失敗」の状態においては、付随して値を持てる。成功時は処理結果を表す実際の値(計算結果など)、失敗時は失敗理由(例外オブジェクトなど)を持たせるのが一般的な使い方と思われる。
C++だと、Promise
は std::promise<T>
、Thenable
が std::future<T>
、
C# だと、 Promise
が Task<T>
、Thenable
が IAsyncResult<T>
に対応する感じ。
2023/04/01(土)C++で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を読み書きしたかったわけではないはずだ。(どういう意味か?)
新年度ですね。新規性のあることをせねばなぁ。