似たような規格として、既存の半精度浮動小数点数があるが、マイコンでのサポートがない(多分)、表現できる範囲が狭い、といった問題がある。
前者に関しては、それっぽい値に変換するライブラリをかけば済む話だが、後者が問題で、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 件のコメント:
コメントを投稿