目次: 射的
スピードシューティングを始めてから10か月です。今日は、第一回目の公式記録会に参加したのと、5月には公式大会(アンリミティッド - 一般社団法人日本トイガン射撃協会JTSA)があります。今までの練習会のタイムをまとめておこうかと思います。
以前と変わらず、基本的に練習は週1回のみです。たまに練習以外のシューティング系イベントにも行きますが、記録を見る限りタイム上達とは関係なさそうです。
今回のUnlimitedの個人目標は合計80秒を切ること、です。特にこの数字に意味はありませんが、自分の実力の壁がこの辺りにあるのと、1ラウンド4秒 → 1ステージ16秒 → 合計タイムが80秒ちょうどになるので、暗算でもわかりやすいのです。
記録を見ると当初は順調に早くなり80秒を切るかと思ったら、ここ最近1〜2か月は全然ダメです。ベストタイムは2/19の80.7秒でした。
日付の * は別のエアガン(グロック17 Gen.4)を使った記録ですが、特に早くも遅くもなりませんでした。道具のせいにするな、腕が悪いんだろって?はい、その通りですね……。
タイムが上下してしまう原因は明らかでして、各ステージのベストスコアとワーストスコアのブレが激しすぎるためです。ベストスコアが偶然重なれば合計80秒台前半、ワーストスコアが重れば合計90秒台です。的を外さないよう、ステージにあったリズムで撃つ、というシューティングの基本ができていない証でしょう。精進あるのみです。
いつか週1という練習頻度の限界が来る気はしますが、まだ遠そうな気配です。あと1か月、怪我しない程度にボチボチやっていこうかなと思います。
この記事にコメントする
目次: RISC-V
完全に自分用メモです。自分でlibcを改造しない限りこのエラーに引っかかることはないでしょう。
世の中にCライブラリの実装はいくつかありますが、musl libcというライブラリがあります。MITライセンスで商用利用等の自由度が高く、最近ですとAWSのコンテナイメージで有名になったAlpine Linuxの標準Cライブラリです。Rustのスタティックリンクにも使われていた気がします。
そんなmusl libcですが、1.1.23からRISC-V 64bitに対応しました。しかしRISC-V 32bitはOpen Future Goalsという位置に置かれ(musl libcの公式WikiのRoadmap)、しばらく実装される見込みがありません。
GNU libcならばRISC-V 32bitに対応していますが、ライセンスの特徴(GPL/LGPLを嫌がる界隈にはお勧めしづらい)とメモリ使用量が多い傾向があります。組み込み向けも狙っているので、GNU libc一本だとちょっと厳しい印象です。印象だけじゃなくてちゃんと評価した方が良い?……おっしゃる通りですね。
このような事情でmusl libcのRISC-V 32bitポーティングにトライしています。
基本的にmusl libcは32bit/64bitで完全に実装を分ける(例: arch/arm, arch/aarch64)設計思想のようです。設計思想に従えば既に存在するarch/riscv64の横にarch/riscv32を新規に追加するのが素直でしょう。
しかしRISC-Vのツールチェーンはmultilibという64/32bitをひとまとめにしたツールチェーンを使えるので、muslの設計思想と合いません。64bit専用と32bit専用のツールチェーンに分けても良いですが、するとGNU libcと合わなくなってしまい困りました。
おそらくmusl libc的には邪道ですが、RISC-V 64bitの実装に「32bitだったらこうして」という条件を追記することにします。
やっと本題です、前置きが長い!RISC-V 32bit用の移植をミスると、GCCのビルド(正確に言うとlibstdc++ のビルド)で下記のようなエラーが出ます。
In file included from gcc/libstdc++-v3/src/c++17/floating_from_chars.cc:78:
gcc/libstdc++-v3/src/c++17/fast_float/fast_float.h: In function ‘{anonymous}::fast_float::value128 {anonymous}::fast_float::full_multiplication(uint64_t, uint64_t)’:
gcc/libstdc++-v3/src/c++17/fast_float/fast_float.h:281:3: error: ‘__uint128_t’ was not declared in this scope; did you mean ‘__int128__’?
281 | __uint128_t r = ((__uint128_t)a) * b;
| ^~~~~~~~~~~
| __int128__
直接の原因はGCCの挙動の差です。RISC-V 64bitだと __uint128_tを定義しますが、RISC-V 32bitだと __uint128_tを定義しません(使用すると未定義型エラーになります)。しかしなぜ __uint128_tを使うコードが有効になるのか、一見しても原因がわかりません。
調べてみるとエラーがドミノのように連鎖して起きていました。ビルドエラーを起こしているソースコードから眺めていきましょう。
// gcc/libstdc++-v3/src/c++17/floating_from_chars.cc
#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \
&& __SIZE_WIDTH__ >= 32
# define USE_LIB_FAST_FLOAT 1
# if __LDBL_MANT_DIG__ == __DBL_MANT_DIG__
// No need to use strtold.
# undef USE_STRTOD_FOR_FROM_CHARS
# endif
#endif
#if USE_LIB_FAST_FLOAT //★★RISC-V 64/32bitどちらでも有効になる★★
# define FASTFLOAT_DEBUG_ASSERT __glibcxx_assert
namespace
{
# include "fast_float/fast_float.h" //★★エラーを起こすコードを含んだヘッダ★★
} // anon namespace
#endif
ビルドエラーを起こすfast_float.hのincludeが原因?と思いましたが、64bit/32bitいずれの場合もincludeする条件が成立し、おかしなことは起きていないようです。原因はヘッダの内部でしょう。
// gcc/libstdc++-v3/src/c++17/fast_float/fast_float.h
...
// Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow.
// We can never tell the register width, but the SIZE_MAX is a good approximation.
// UINTPTR_MAX and INTPTR_MAX are optional, so avoid them for max portability.
#if SIZE_MAX == 0xffff
#error Unknown platform (16-bit, unsupported)
#elif SIZE_MAX == 0xffffffff
#define FASTFLOAT_32BIT //★★こちらになるはずでは??★★
#elif SIZE_MAX == 0xffffffffffffffff
#define FASTFLOAT_64BIT //★★こちらが選択されるのはなぜ?★★
#else
#error Unknown platform (not 32-bit, not 64-bit?)
#endif
#endif
...
// compute 64-bit a*b
fastfloat_really_inline value128 full_multiplication(uint64_t a,
uint64_t b) {
value128 answer;
#ifdef _M_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emulate
answer.high = __umulh(a, b);
answer.low = a * b;
#elif defined(FASTFLOAT_32BIT) || (defined(_WIN64) && !defined(__clang__))
answer.low = _umul128(a, b, &answer.high); // _umul128 not available on ARM64
#elif defined(FASTFLOAT_64BIT)
__uint128_t r = ((__uint128_t)a) * b; //★★ビルドエラー発生個所★★
answer.low = uint64_t(r);
answer.high = uint64_t(r >> 64);
#else
#error Not implemented
#endif
return answer;
}
RISC-V 32bit向けなのにFASTFLOAT_64BITが定義されたとき、__uint128_t型が使われるコードがビルドされてエラーになります。ヘッダの上の方を見るとSIZE_MAXに依存しているようで、SIZE_MAXが怪しいです。
// musl/arch/riscv64/bits/stdint.h
typedef int32_t int_fast16_t;
typedef int32_t int_fast32_t;
typedef uint32_t uint_fast16_t;
typedef uint32_t uint_fast32_t;
#define INT_FAST16_MIN INT32_MIN
#define INT_FAST32_MIN INT32_MIN
#define INT_FAST16_MAX INT32_MAX
#define INT_FAST32_MAX INT32_MAX
#define UINT_FAST16_MAX UINT32_MAX
#define UINT_FAST32_MAX UINT32_MAX
#define INTPTR_MIN INT64_MIN
#define INTPTR_MAX INT64_MAX
#define UINTPTR_MAX UINT64_MAX
#define PTRDIFF_MIN INT64_MIN
#define PTRDIFF_MAX INT64_MAX
#define SIZE_MAX UINT64_MAX //★★原因★★
私の移植が適当過ぎてSIZE_MAXの値が64bit向けのままになっていたことが原因でした。先述したようにmusl libc的には邪道ではありますが、32bit向けの分岐を追加します。
#if __riscv_xlen == 64
#define INTPTR_MIN INT64_MIN
#define INTPTR_MAX INT64_MAX
#define UINTPTR_MAX UINT64_MAX
#define PTRDIFF_MIN INT64_MIN
#define PTRDIFF_MAX INT64_MAX
#define SIZE_MAX UINT64_MAX
#elif __riscv_xlen == 32
#define INTPTR_MIN INT32_MIN
#define INTPTR_MAX INT32_MAX
#define UINTPTR_MAX UINT32_MAX
#define PTRDIFF_MIN INT32_MIN
#define PTRDIFF_MAX INT32_MAX
#define SIZE_MAX UINT32_MAX
#endif
分かってしまえば簡単な話ですが、エラーメッセージからこの原因を推測するのはちょっと難しいですね……。
この記事にコメントする
| < | 2023 | > | ||||
| << | < | 03 | > | >> | ||
| 日 | 月 | 火 | 水 | 木 | 金 | 土 |
| - | - | - | 1 | 2 | 3 | 4 |
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 | - |
wiki
Linux JM
Java API
2002年
2003年
2004年
2005年
2006年
2007年
2008年
2009年
2010年
2011年
2012年
2013年
2014年
2015年
2016年
2017年
2018年
2019年
2020年
2021年
2022年
2023年
2024年
2025年
過去日記について
アクセス統計
サーバ一覧
サイトの情報合計:
本日: