#ifndef _REAL_FIX_H #define _REAL_FIX_H #include namespace FIX { static constexpr int iround (const double d) { return d > 0.0 ? int (d + 0.5) : int (d - 0.5); } /** * @class real * @brief Aritmetika v pevné řádové čárce. * * Není to moc přesné, ale bez float koprocesoru to postačí. * A není to kompletní, jen pro výpočet polynomu, zde to stačí. */ struct real { int32_t x; // necháme veřejné /** * @brief Konstruktor z double * @param _x double */ explicit constexpr real (const double _x) : x (iround (_x)) {} /** * @brief Konstruktor z celého čísla, přímo nepoužívat - explicitní převod from_int() * Ono se to trochu pere s tím double. * @param _x integer */ explicit constexpr real (const int32_t _x) : x (_x) {} /** * @brief Kopírovací konstruktor */ explicit constexpr real () : x (0) {} // stačí přetížit jen některé operátory, výpočet je dělán poměrně úsporně real operator+ (const real & r) const { return real (x + r.x); } real operator- (const real & r) const { return real (x - r.x); } bool operator< (const real & r) const { return x < r.x; } bool operator>= (const real & r) const { return x >= r.x; } real & operator+= (const real & r) { x += r.x; return * this; } // Pouze pro výpisy - zachová formátovou specifikaci pro FLT double operator+ () const { return double (x); } }; // Násobení s posunem zde používá "plovoucí" posun, jinak to nejde. static void mull (real & res, const real & r, const int sl = 0) { const int64_t result = (int64_t)(res.x) * (int64_t)(r.x); #ifdef __linux__ // Check overflow const uint64_t u = result < 0 ? -result : +result; const uint32_t o = u >> (sl + 32); if (o) {fprintf (stderr, "Overflow 0x%X\n", o); // Není to dokonalé, ale alespoň něco // Šla by vyhodit výjimka a backtrace zjistit proč a hlavně kde. throw ("overflow exception"); } #endif res.x = result >> sl; } //! Vytvoří double z real static constexpr double from_real (const real & r) { const double a = 1.0 / double (1ull << 16); return a * double(r.x); } static constexpr real to_real (const double x, const int sh) { const double a = double (1ull << sh); return real (a * x); } }; // end of namespace FIX #endif // _REAL_FIX_H