Adafruit TrinketのようなROMが数キロバイトしかないマイコンでは、float型を用いると浮動小数点のライブラリがROM容量を圧迫してしまう。そこで固定小数点クラスを作ってみた。
【2019/05/24 追記】
Arduino IDEでビルドしてみたところ、AVRマイコンではfloat使うよりROMサイズが増えてしまった。クラス化はあきらめてCだけで書いたらいちおうfloatよりROM削減にはなったけど、それも思ったほどの効果でもなかった。8ビットマイコンで64ビットの乗算をするためけっこうROMを食うようだ。残念な結果である。
⇒ 固定小数点計算ふたたび - 滴了庵日録
fixed24クラスの仕様
- 内部表現は符号1ビット、整数部7ビット、小数部24ビットの全32ビット。
- 代入(=)、比較(==, != , >, <, >=, <=)、四則演算(+, -, *, /) の演算子が使える。
- +=のような糖衣な演算子はサポートしない。
- 生値(32ビットの内部表現) または (分子, 分母) からインスタンス生成する。
- 整数への変換にはtoInt()メソッドを用いる。(キャスト演算子は暗黙のキャストが危険なため)
- デバッグ用にdoubleへのキャスト演算子を用意。(通常は無効)
- 生値(32ビットの内部表現)へのアクセスを許す。(どうせこんなクラス使うのは泥臭い世界)
fixed24.h
#ifndef _FIXED24_H
#define _FIXED24_H
#include<stdint.h>
class fixed24
{
public:
fixed24(void) {
value = 0;
}
fixed24(int32_t rawval){
value = rawval;
}
fixed24(int32_t numer, int32_t denom){
int64_t x = ((int64_t)numer << 24) / (int64_t)denom;
value = (int32_t)x;
}
void operator = (fixed24 x){ value = x.value; }
bool operator == (fixed24 x) const { return (value == x.value); }
bool operator != (fixed24 x) const { return (value != x.value); }
bool operator > (fixed24 x) const { return (value > x.value); }
bool operator < (fixed24 x) const { return (value < x.value); }
bool operator >= (fixed24 x) const { return (value >= x.value); }
bool operator <= (fixed24 x) const { return (value <= x.value); }
fixed24 operator + (fixed24 x) const { return fixed24(value + x.value); }
fixed24 operator - (fixed24 x) const { return fixed24(value - x.value); }
fixed24 operator * (fixed24 x) const {
int64_t a = (int64_t)value;
int64_t b = (int64_t)x.value;
a *= b;
a >>= 24;
return fixed24((int32_t)a);
}
fixed24 operator * (int32_t x) const {
int32_t y = value * x;
return fixed24((int32_t)y);
}
fixed24 operator / (fixed24 x) const {
int64_t a = (int64_t)value << 32;
int64_t b = (int64_t)x.value;
a /= b;
a >>= 8;
return fixed24((int32_t)a);
}
fixed24 operator / (int32_t x) const {
int32_t y = value / x;
return fixed24((int32_t)y);
}
int toInt() const { return (int)(value >> 24); }
#ifdef _DEBUG_FIXED24
operator double () const {
double x = (double)value / (double)(1UL << 24);
return x;
}
#endif
int32_t value;
};
#endif
テスト
#include <stdio.h>
#define _DEBUG_FIXED24
#include "fixed24.h"
int main(void)
{
fixed24 x = fixed24(10, 1);
fixed24 y = fixed24(20, 100);
fixed24 z = fixed24(0x01000000 / 2);
printf("x = %d (%08X)\n", x.toInt(), x.value);
printf("y = %f (%08X)\n", (double)y, y.value);
printf("z = %f (%08X)\n", (double)z, z.value);
z = x + y;
printf("%f + %f = %f (%08X)\n", (double)x, (double)y, (double)z, z.value);
z = x - y;
printf("%f - %f = %f (%08X)\n", (double)x, (double)y, (double)z, z.value);
z = x * y;
printf("%f * %f = %f (%08X)\n", (double)x, (double)y, (double)z, z.value);
z = x / y;
printf("%f / %f = %f (%08X)\n", (double)x, (double)y, (double)z, z.value);
z = x * 2;
printf("%f * 2 = %f (%08X)\n", (double)x, (double)z, z.value);
z = x / 2;
printf("%f / 2 = %f (%08X)\n", (double)x, (double)z, z.value);
x = fixed24(1, 1);
y = fixed24(1, 1);
printf("%f == %f : %s\n", (double)x, (double)y, (x == y) ? "TRUE" : "FALSE");
printf("%f != %f : %s\n", (double)x, (double)y, (x != y) ? "TRUE" : "FALSE");
y = fixed24(2, 1);
printf("%f == %f : %s\n", (double)x, (double)y, (x == y) ? "TRUE" : "FALSE");
printf("%f != %f : %s\n", (double)x, (double)y, (x != y) ? "TRUE" : "FALSE");
return 0;
}