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

履歴 編集

function template
<numeric>

std::midpoint(C++20)

namespace std {
  template <class T>
  constexpr T midpoint(T a, T b) noexcept; // (1)

  template <class T>
  constexpr T* midpoint(T* a, T* b);       // (2)
}

概要

二点間の中点を求める。

  • (1) : 数値型の中点を求める
  • (2) : ポインタ型の中点を求める

この関数は、単純に計算する場合は(a + b) / 2となるが、オーバーフローが起こりにくいよう計算式に工夫が入る。例として、整数の場合はa + (b - a) / 2、浮動小数点数の場合はa/2 + b/2のように計算できる (実際は負数や非正規化数などをさらに考慮することになる)。

要件

  • (1) : 型Tbool 以外の算術型であること
  • (2) : 型Tは完全型であること
  • (2) : 期待することとして、abはそれぞれ、同じ配列xx[i]x[j]要素を指していること
    • TODO : この項目は規格では契約のExpectsにあたる。本サイトの項目の書き方を考える必要がある
    • 配列要素でないオブジェクトが与えられた場合は、単一要素をもつ配列に属するものとみなす

戻り値

  • (1) : abを合計した値の1/2の数値を返す
    • Tが整数型で合計値が奇数の場合、a側に丸められる
    • Tが浮動小数点数型の場合、最大一回の不正確 (inexact) 操作が発生し、オーバーフローは起こらない
  • (2) : abが同じ配列xx[i]x[j]を指しているとして、x[i + (j - i) / 2]を指すポインタを返す。除算の結果はゼロ方向に丸められる

例外

  • (1) : 投げない

備考

  • 浮動小数点数の文脈では、この関数の動作は平均値 (mean value) という名称を使用するが、それ以外の文脈では中点が使用される。汎用的な用途とするため、この関数の名前として中点 (midpoint) を採用している

基本的な使い方

#include <iostream>
#include <numeric>

int main()
{
  // (1) 整数
  {
    int r1 = std::midpoint(1, 5);
    std::cout << "a : " << r1 << std::endl;

    // 奇数になるケース
    int r2 = std::midpoint(2, 7);
    std::cout << "b : " << r2 << std::endl;

    int r3 = std::midpoint(7, 2);
    std::cout << "c : " << r3 << std::endl;
  }

  // (2) 浮動小数点数
  {
    float r1 = std::midpoint(1.5f, 2.5f);
    std::cout << "d : " << r1 << std::endl;

    float r2 = std::midpoint(1.5f, 3.0f);
    std::cout << "e : " << r2 << std::endl;
  }

  // (3) ポインタ
  {
    int ar[] = {1, 2, 3};
    int* p1 = std::midpoint(ar, ar + 2); // &ar[1]が返る
    std::cout << "f : " << *p1 << std::endl;

    // 配列ではないオブジェクトへのポインタは、単一要素の配列として指定する
    int x = 4;
    int* p2 = std::midpoint(&x, &x + 1);
    std::cout << "g : " << *p2 << std::endl;
  }
}

出力

a : 3
b : 4
c : 5
d : 2
e : 2.25
f : 2
g : 4

2次元の二点間の中点を求める

#include <iostream>
#include <numeric>

// 2次元上の点を表す型
struct Point {
  float x, y;
};

// Point型用に中点を求める関数を定義する
Point midpoint(const Point& a, const Point& b) noexcept
{
  return Point{
    std::midpoint(a.x, b.x),
    std::midpoint(a.y, b.y)
  };
}

int main()
{
  const Point a{1.0f, 2.0f};
  const Point b{5.0f, 3.0f};

  // 点aと点bの中点を求める
  const Point p = midpoint(a, b);
  std::cout << '(' << p.x << ", " << p.y << ')' << std::endl;
}

出力

(3, 2.5)

バージョン

言語

  • C++20

処理系

関連項目

参照