Adafruit TrinketのようなROMが数キロバイトしかないマイコンでは、float型を用いると浮動小数点のライブラリがROM容量を圧迫してしまう。そこで固定小数点クラスを作ってみた。
【2019/05/24 追記】
Arduino IDEでビルドしてみたところ、AVRマイコンではfloat使うよりROMサイズが増えてしまった。クラス化はあきらめてCだけで書いたらいちおうfloatよりROM削減にはなったけど、それも思ったほどの効果でもなかった。8ビットマイコンで64ビットの乗算をするためけっこうROMを食うようだ。残念な結果である。
⇒ 固定小数点計算ふたたび - 滴了庵日録
fixed24クラスの仕様
fixed24.h
#ifndef _FIXED24_H #define _FIXED24_H #include<stdint.h> class fixed24 { public: // constructors 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; } // operators 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); } // convert to integer (-128 to +127) // not cast operator because implicit cast is dangerous int toInt() const { return (int)(value >> 24); } #ifdef _DEBUG_FIXED24 // cast to double (for debug) operator double () const { double x = (double)value / (double)(1UL << 24); return x; } #endif // raw value int32_t value; }; #endif
テスト
#include <stdio.h> #define _DEBUG_FIXED24 #include "fixed24.h" int main(void) { fixed24 x = fixed24(10, 1); // 10/1 = 10 fixed24 y = fixed24(20, 100); // 20/100 = 0.20 fixed24 z = fixed24(0x01000000 / 2); // 1/2 = 0.5 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; }