Skip to content

Commit 8ea93d2

Browse files
committed
bisect
1 parent b6d44d9 commit 8ea93d2

File tree

3 files changed

+90
-0
lines changed

3 files changed

+90
-0
lines changed

other_algorithms/bisect.hpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#pragma once
2+
#include <bit>
3+
#include <functional>
4+
#include <numeric>
5+
6+
// Calculate next point to check in floating point "binary" search
7+
double bisect_mid_fp(double a, double b) {
8+
auto encode = [&](double x) -> unsigned long long {
9+
auto tmp = std::bit_cast<unsigned long long>(x);
10+
return x >= 0 ? (tmp ^ (1ULL << 63)) : ~tmp;
11+
};
12+
13+
auto decode = [&](unsigned long long x) -> double {
14+
auto tmp = (x >> 63) ? (x ^ (1ULL << 63)) : ~x;
15+
return std::bit_cast<double>(tmp);
16+
};
17+
18+
unsigned long long tmp = std::midpoint(encode(a), encode(b));
19+
20+
return decode(tmp);
21+
}
22+
23+
// Binary search
24+
// Maintain f(ok) = true and f(ng) = false and return (ok, ng)
25+
// Final (ok, ng) satisfies |ok - ng| <= abs_tol
26+
template <class T> auto bisect(T ok, T ng, const std::function<bool(T)> &f, T abs_tol = T()) {
27+
struct Result {
28+
T ok, ng;
29+
};
30+
31+
while (true) {
32+
T mid = std::is_floating_point<T>::value ? bisect_mid_fp(ok, ng) : std::midpoint(ok, ng);
33+
if (mid == ok or mid == ng) break;
34+
(f(mid) ? ok : ng) = mid;
35+
if (ok - ng <= abs_tol and ng - ok <= abs_tol) break;
36+
}
37+
38+
return Result{ok, ng};
39+
}

other_algorithms/bisect.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
title: Binary search (二分探索)
3+
documentation_of: ./bisect.hpp
4+
---
5+
6+
二分探索を行う.
7+
探索範囲が浮動小数点数で与えられた場合は, IEEE 754 の binary64 形式を 64 bit 整数だと思って上の桁から順に値を定めていくような挙動を示す(よって必ず 64 回以下のループで実行が完了する).
8+
9+
## 使用方法
10+
11+
### `double bisect_mid_fp(double a, double b)`
12+
13+
64 bit 浮動小数点数の区間に対する二分探索で,現在の探索範囲の両端の値をもとに次に探索すべき値を返す.
14+
引数 `a``b` は NaN でなければよい(非正規化数や無限でもよい).
15+
動作のイメージとして `ok``ng` がともに正の場合は幾何平均くらいのオーダーの値を返す.
16+
17+
### `template <class T> auto bisect(T ok, T ng, const std::function<bool(T)> &f, T abs_tol = T())`
18+
19+
二分探索を行い,条件を満たす値を求める関数.
20+
21+
- `ok` : `f(x) == true` を満たすことがわかっている `x` の値.
22+
- `ng` : `f(x) == false` を満たすことがわかっている `x` の値.
23+
- `f` : `T` 型の引数をとり,条件を満たす場合 `true` を返す判定関数.
24+
- `abs_tol` : 許容絶対誤差. `ok``ng` の差がこの値以下になったら探索を打ち切る(デフォルトは `T()` ).
25+
- 戻り値 : `ok` および `ng` の最終値を含む `Result` 構造体.
26+
27+
## 問題例
28+
29+
- [No.2352 Sharpened Knife in Fall - yukicoder](https://yukicoder.me/problems/no/2352)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#define PROBLEM "https://yukicoder.me/problems/no/2352"
2+
#define ERROR 1e-5
3+
#include "../bisect.hpp"
4+
5+
#include <iomanip>
6+
#include <iostream>
7+
using namespace std;
8+
9+
10+
int main() {
11+
cin.tie(nullptr), ios::sync_with_stdio(false), cout << fixed << setprecision(10);
12+
int R, K;
13+
cin >> R >> K;
14+
const double pi = acos(-1);
15+
16+
for (int i = 1; i < K + 1; ++i) {
17+
double tgt = pi / (K + 1) * i;
18+
19+
auto res = bisect<double>(0, pi, [&](double c) { return c - sin(c * 2) / 2 < tgt; });
20+
cout << -cos(res.ng) * R << '\n';
21+
}
22+
}

0 commit comments

Comments
 (0)