2016年6月16日木曜日

固定小数点クラス

ずっと昔64ビット長の固定小数点クラスがほしくて、書いたやつ。 今なら、8ビット長の固定小数点クラスなんですかねー。
#pragma once
/*!
 @file fixed_float.hpp
 @brief 固定精度浮動小数点クラス・ヘッダ
*/

#include <boost/assert.hpp>
#include <boost/operators.hpp>
#include <limits>


//! 64ビット長固定精度浮動小数点クラス
class fixed64 :
 private boost::addable<fixed64>,
 private boost::subtractable<fixed64>,
 private boost::multipliable<fixed64>,
 private boost::dividable<fixed64>,
 private boost::equivalent<fixed64>,
 private boost::partially_ordered<fixed64>
{
public:
 static const int exponent_ = 16; //!< 指数部長
private:
 int64_t value_; //!< 値
public:
 //! コンストラクタ
 inline fixed64() : value_() {}
 //! コンストラクタ
 inline explicit fixed64( 
  int64_t value //!< [in] 値
 ) : value_(value << exponent_) {
  BOOST_ASSERT( value <= (std::numeric_limits<int64_t>::max() >> exponent_) );
  BOOST_ASSERT( (std::numeric_limits<int64_t>::min() >> exponent_) <= value );
 }
 //! コンストラクタ
 inline explicit fixed64( 
  double value //!< [in] 値
// ) : value_(static_cast<int64_t>(value * (1LU << exponent_))) {
 ) : value_(static_cast<int64_t>(value * pow(2.0,exponent_))) { 
  //BOOST_ASSERT( value <= (static_cast<double>(std::numeric_limits<int64_t>::max() >> exponent_) );
  //BOOST_ASSERT( (static_cast<double>(std::numeric_limits<int64_t>::min()) >> exponent_) <= value );
 }
 //! コピーコンストラクタ
 inline fixed64( 
  const fixed64& value //!< [in] 値
 ) : value_(value.value_) {}

 //! オペレータ +=
 inline fixed64& operator += (const fixed64& rhs) {
  value_ += rhs.value_;
  return *this;
 }
 //! オペレータ -=
 inline fixed64& operator -= (const fixed64& rhs) {
  value_ -= rhs.value_;
  return *this;
 }

 //! オペレータ *=
 inline fixed64& operator *= (const fixed64& rhs) {
  value_ = static_cast<int64_t>( 
   (
    (
     ((static_cast<int64_t>(value_)) * (static_cast<int64_t>(rhs.value_)))
     // 切り上げを行う
     //& pow( 2.0, exponent_ - 1 )
    )
    >> exponent_
   )
  );
  return *this;
 }
 //! オペレータ /=
 inline fixed64& operator /= (const fixed64& rhs) {
  value_ = static_cast<int64_t>(
   (static_cast<int64_t>(value_) << exponent_) / static_cast<int64_t>(rhs.value_)
  );
  return *this;
 }
 //! オペレータ =
 inline fixed64& operator = (const fixed64& rhs) { value_ = rhs.value_; return *this; }
 //! オペレータ ==
 inline bool operator == (const fixed64& rhs) const { return value_ == rhs.value_; }
 //! オペレータ <
 inline bool operator < (const fixed64& rhs) const { return value_ < rhs.value_; }

 inline double get(){
  return static_cast<double>(value_ / pow(2.0, exponent_));
 }

 inline operator double() const 
  { 
    //return double(value_ * (1 >> exponent_)) ; 
  return double(value_ / pow(2.0, exponent_));
  //return double(value_ * (static_cast<int64_t>(1) >> exponent_)) ;
  } 
 //! オペレータ =
 inline fixed64& operator = (const double& rhs) {
  value_ = static_cast<int64_t>(rhs * pow(2.0, exponent_));
  return *this; 
 }
};

1 件のコメント:

Egtra さんのコメント...

operator double()の実装、return std::ldexp(value, -exponent_)とするともっと簡単だと思います。逆に、doubleから変換するほうもfrexp関数が使えるはずですが、こちらはもう少し面倒そうです。