#ifndef _REAL_FIX_H
#define _REAL_FIX_H
#include <stdint.h>
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