似たような規格として、既存の半精度浮動小数点数があるが、マイコンでのサポートがない(多分)、表現できる範囲が狭い、といった問題がある。
前者に関しては、それっぽい値に変換するライブラリをかけば済む話だが、後者が問題で、IEEE 754の半精度浮動小数点数は10進でたかだか4.8桁程度しか表現できない。int64_tは10進で18.9桁ほどあるので、圧倒的に足りない。
また、一般的な浮動小数点は1未満かつ-1より大きい値を表現できるが、あくまで整数の中間表現がほしいだけなので、1未満の分解能は必要ない。ということで、符号1bit、指数6bit、仮数9bit、の16bit浮動小数点を考えた次第。
これにより、8バイトの64bit整数を2バイトで表現できるようになったので、4分の1のメモリサイズで済む。
値が小さい時(<1024)は少し特殊な処理をしている。
たぶん最小値(-2^63)を与えるとバグる。
今回はそんな端っこまで使う予定はなかったので省いた。というかint32でも足りるんじゃないか、程度の範囲しか使っていないんだよなぁ。浮動仮数幅浮動小数点、なんてのもありかもしれない。
using original_float_16 = uint16_t; original_float_16 convert_to_BIN(int64_t value) { const bool is_negative(value < 0); if (is_negative) { value = -value; } uint16_t bit_data(0); if (value < 1024) { bit_data = value; } else { uint_fast8_t i(53); while (i > 0) // exit with break { if (value & ((uint64_t)1 << (i + 9))) { bit_data = ((i + 1) << 9) | ((value >> i) & 0x01FF); break; } i--; } } if (is_negative) { bit_data |= 0x8000; } return (bit_data); } int64_t convert_from_BIN(original_float_16 BIN) { const uint_fast8_t sign((BIN >> 15) & 0x01); const uint_fast8_t exponent((BIN >> 9) & 0x3F); const uint_fast16_t fraction(BIN & 0x01FF); const int64_t result(exponent ? (uint64_t)(fraction | 0x0200) << (exponent - 1) : fraction); return (!sign ? result : -result); }
もうちょっとうまくかけそうな気もするけど、とりあえず動いてるので。
fp→intは各ビットを取り出してビットシフトするだけなので比較的簡単。
int→fpは最上位ビットの位置を探す必要があるのでループしてる。最上位ビットの位置を1クロックで返す命令とか無いものか。
0 件のコメント:
コメントを投稿