質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

689閲覧

自作の二部探索がstd::binary_search()より遅い

退会済みユーザー

退会済みユーザー

総合スコア0

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

1グッド

1クリップ

投稿2020/04/23 07:08

勉強のために二分探索のコードを書いたのですが、どちらもミリ秒未満とはいえstd::binary_search()と比べると倍近く遅いようです。
これは、STDのコードがカリカリにチューニングされていたり高度な?書き方をしていることに由来するのでしょうか?
それとも、私の下記のコードには何かボトルネックになる要素があるのでしょうか?

C++

1#include <algorithm> 2#include <functional> 3#include <vector> 4typedef std::vector<int>::const_iterator Iterator; 5 6template<class Compare> 7Iterator BinarySearch(Iterator begin, Iterator end, Compare comp) { 8 auto it = begin; 9 auto not_found = end; 10 11 while (std::distance(it, end) > 0) { 12 auto mid = it; 13 std::advance(mid, std::distance(it, end) / 2); 14 auto comp_result = comp(*mid); 15 16 if (comp_result == 0) { 17 return mid; 18 } else if (comp_result < 0) { 19 it = mid; 20 ++it; 21 } else { 22 end = mid; 23 } 24 } 25 return not_found; 26}

コード全文 [Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ
イメージ説明

yumetodo👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

comp が負、ゼロ、正の 3つの値を返しますよね。
そのため、内部で比較が 2回必要な場合があります。

std::binary_search の comp は
comp(const T& a, const T& b) { return a < b; } だから、速いのではありませんか?

もうひとつ。

バイナリサーチでは、結果が求まるまで何回か比較を行います。
comp_result == 0 は最後まで true にならないので、
comp_result == 0 と comp_result < 0 の 2回の比較が常に行われます。

std::binary_search では comp が less なので、
if (key < *mid) end = mid;
else if (*mid < key) it = mid, ++it;
else return mid;
になっていて、比較が 1回で済む場合があるのではないでしょうか?

投稿2020/04/23 09:49

編集2020/04/23 10:31
kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

std::distance(it, end)を何度も呼ぶよりも最初にカウントしたら
あとはその結果から計算していった方が高速です。

投稿2020/04/23 08:16

asm

総合スコア15147

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/04/23 15:38

下記のように試してみると、たまにクラッシュするようになったのですがどこかおかしいでしょうか? コメント欄でのやり取りに相応しくなければ、新たな質問を立てます。 template<class Compare> Iterator BinarySearch(Iterator begin, Iterator end, Compare comp) { auto it = begin; auto not_found = end; auto dist = std::distance(it, end); while (dist > 0) { dist /= 2; auto mid = it; std::advance(mid, dist); auto comp_result = comp(*mid); if (comp_result == 0) { return mid; } else if (comp_result < 0) { it = ++mid; } else { end = mid; } } return not_found; }
yudedako67

2020/04/23 16:45

mid == endになる場合があります。そのときcomp(*mid)を呼び出してるんでしょう。
退会済みユーザー

退会済みユーザー

2020/04/23 17:59

なるほど、その場合auto comp_result = comp(*mid);の前を修正すると思うのですが、どうすれば良いでしょうか?
asm

2020/04/24 00:43

{0,1,2,3}に対して、3を検索した時などがおかしいようです。 > it = ++mid; midが+1されているのに残り要素を減らしていないのが問題ですね。
退会済みユーザー

退会済みユーザー

2020/04/24 02:42

mid, distの加減を試しても上手くいかなかったので、その部分のバグについての質問を挙げました。 もしよろしければそちらも回答していただけると嬉しいです。 https://teratail.com/questions/256050
guest

0

原因を割り出すために吐かれるコードを見てみましたが、比較回数はあまり関係なさそうに見えます。

ところで検証のためにgoogle/benchmarkを使うように書き換えてたんですがなんか実行結果がおかしい。何を見落としているんだろうか・・・
http://quick-bench.com/WgvpPrDFyfr6YYKxLrCFsAqBXPg
イメージ説明


別におかしくなさそう。

http://quick-bench.com/S5EQOuyWmqTIBILOXAO03kxDp-8
https://godbolt.org/z/V5nGSE
イメージ説明

投稿2020/04/23 11:22

編集2020/04/24 03:52
yumetodo

総合スコア5850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

asm

2020/04/24 01:23

my::BinarySearchの返り値を使ってないのでO3で消されてる感じですね benchmark::DoNotOptimizeに返り値渡してやるといいかと思います
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問