最終更新日時(UTC):
が更新

履歴 編集

function
<cmath>

std::modf

namespace std {
  float
    modf(float value, float* iptr);     // (1) C++03からC++20まで
  double
    modf(double value, double* iptr);   // (2) C++03からC++20まで
  long double
    modf(long double value,
         long double* iptr);            // (3) C++03からC++20まで

  constexpr floating-point-type
    modf(floating-point-type value,
         floating-point-type* iptr);    // (4) C++23

  double
    modf(Integral value, double* iptr); // (5) C++11
  constexpr double
    modf(Integral value, double* iptr); // (5) C++23

  float
    modff(float value, float* iptr);    // (6) C++17
  constexpr float
    modff(float value, float* iptr);    // (6) C++23

  long double
    modfl(long double value,
          long double* iptr);           // (7) C++17
  constexpr long double
    modfl(long double value,
          long double* iptr);           // (7) C++23
}

概要

浮動小数点数を、整数部と小数部に分解する。

  • (1) : floatに対するオーバーロード
  • (2) : doubleに対するオーバーロード
  • (3) : long doubleに対するオーバーロード
  • (4) : 浮動小数点数型に対するオーバーロード
  • (5) : 整数型に対するオーバーロード (doubleにキャストして計算される)
  • (6) : float型規定
  • (7) : long double型規定

戻り値

引数valueの小数部を符号付きとして返す。また、引数valueの整数部を*iptrに書き込む。

この関数によって返される整数部と小数部は、どちらも引数valueと同じ符号を持つ。

備考

  • C++11 以降では、処理系が IEC 60559 に準拠している場合(std::numeric_limits<T>::is_iec559() != false)、以下の規定が追加される。(複号同順)

    • value = ±∞ の場合、戻り値は ±0 となり、*exp には ±∞ が設定される。
    • value が NaN の場合、戻り値は NaN となり、*exp には NaN が設定される。
    • 戻り値は正確で、現在の丸め方式には依存しない。
  • C++11 で value が整数型のオーバーロードが追加されているが、iptr の型によって呼び出されるオーバーロードが一意に決まるため、存在意義は無いものと思われる。
    value に整数型、iptrnullptr を渡した場合のみ当該オーバーロードによって呼び出しが曖昧ではなくなるが、その場合は未定義動作となってしまうため、本オーバーロードの存在はむしろ有害)

  • C++23では、(1)、(2)、(3)が(4)に統合され、拡張浮動小数点数型を含む浮動小数点数型へのオーバーロードとして定義された

#include <iostream>
#include <cmath>

int main()
{
  // 正の浮動小数点数を、整数部と小数部に分解する
  {
    float x = 1.23f;
    float integral_part = 0;
    float fractional_part = std::modf(x, &integral_part);

    std::cout << integral_part << std::endl;
    std::cout << fractional_part << std::endl;
  }
  std::cout << std::endl;

  // 負の浮動小数点数を、整数部と小数部に分解する
  {
    float x = -1.23f;
    float integral_part = 0;
    float fractional_part = std::modf(x, &integral_part);

    std::cout << integral_part << std::endl;
    std::cout << fractional_part << std::endl;
  }
}

出力

1
0.23

-1
-0.23

備考

  • 特定の環境では、早期に constexpr 対応されている場合がある:
    • GCC 4.6.1 以上
  • GCC、Clang では、C++11 で追加された整数型オーバーロードは存在しない。

実装例

namespace std {
  float modf(float value, float* iptr)
  {
    int save_round = fegetround();
    fesetround(FE_TOWARDZERO);
    *iptr = nearbyint(value);
    fesetround(save_round);
    return copysign(isinf(value) ? 0.0F : value - (*iptr), value);
  }

  double modf(double value, double* iptr)
  {
    int save_round = fegetround();
    fesetround(FE_TOWARDZERO);
    *iptr = nearbyint(value);
    fesetround(save_round);
    return copysign(isinf(value) ? 0.0 : value - (*iptr), value);
  }

  long double modf(long double value, long double* iptr)
  {
    int save_round = fegetround();
    fesetround(FE_TOWARDZERO);
    *iptr = nearbyint(value);
    fesetround(save_round);
    return copysign(isinf(value) ? 0.0L : value - (*iptr), value);
  }

# if __cplusplus >= 201103L
  template<typename T>
  typename enable_if<is_integral<T>::value, double>::type
  modf(T value, double* iptr)
  {
    return modf(static_cast<double>(value), iptr);
  }
# endif

# if __cplusplus > 201402L
  float modff(float value, float* iptr)
  {
    return modf(value, iptr);
  }

  long double modfl(long double value, long double* iptr)
  {
    return modf(value, iptr);
  }
# endif
}

参照