Alıntı (Salih Dinçer):
> neden trisect()'in süresi pek değişmezken
Bende öyle olmuyor.
Alıntı:
> lowerBound()'ın tıpkı find() gibi logoritmik bir artış sergiliyor?
Yanlış yazdın: find() logaritmik değildir. :) Baştan sona doğur sırayla arar.
Şu dört algoritmayı tekrarlayalım:
-
lowerBound: Aranandan küçük değerler
-
equalRange: Aranana eşit değerler
-
upperBound: Aranandan büyük değerler
-
trisect: Yukarıdakilerin hepsi ama üçünü ayrı ayrı çağırmaktan daha hızlı olarak.
import std.stdio;
import std.range;
import std.random;
import std.datetime;
import std.algorithm;
TickDuration[4] rasgeleÖlçüm(R)(R sayılar)
{
/* Aramanın başarısız olacağı durumlara da düşmek için uzunluktan büyük
* bir değer aralığından seçiyoruz. */
const sınır = sayılar.length * 10 / 9;
const aranan = uniform(0, sınır);
return benchmark!(() => sayılar.lowerBound(aranan),
() => sayılar.equalRange(aranan),
() => sayılar.upperBound(aranan),
() => sayılar.trisect(aranan))
(1_000);
}
struct Rapor
{
size_t uzunluk;
TickDuration[4] ölçüm;
}
void main()
{
enum sınırUzunluk = 100_000;
enum rasgeleAramaAdedi = 1000;
Rapor[] raporlar;
/* Farklı uzunlukta dizilerle deneyler. */
for (size_t N = 1; N <= sınırUzunluk; N *= 2) {
writef("%s ", N);
stdout.flush();
/* N uzunlukta sıralı bir dizi oluştur. (Bazı sayılar tekrarlansın ve
* aralarda boşluklar bulunsun diye garip bir hesap sonucu.) */
auto sayılar = iota(N)
.map!(a => a / 3 * 4)
.array.assumeSorted;
/* Bu dizi üzerinde rasgele aramalar yap. (Bazı aramalar dizide
* bulunacak, bazıları bulunmayacak.) */
auto ölçümler = iota(rasgeleAramaAdedi)
.map!(_ => rasgeleÖlçüm(sayılar));
/* Rasgele ölçümlerin değerlerini topla. */
TickDuration[4] sonuç;
sonuç = reduce!((toplam, a) => toplam[] += a[])(sonuç, ölçümler);
raporlar ~= Rapor(N, sonuç);
}
writeln();
/* Sonuçları bildir. */
writefln("%12s%12s%12s%12s%12s",
"uzunluk", "lowerBound", "equalRange", "upperBound", "trisect");
foreach (rapor; raporlar) {
/* trisect'in lowerBound, equalRange, ve upperBound'ın toplamından az
* olmasını bekliyoruz. Karşılaştırmak için ilk üçünün zamanlarını
* toplayalım. */
const ilkÜçününToplamı = rapor.ölçüm[0..3]
.reduce!((toplam, a) => toplam += a).msecs;
writefln("%12s%(%12s%) (%s değil)",
rapor.uzunluk,
rapor.ölçüm[].map!(a => a.msecs),
ilkÜçününToplamı);
}
}
Bir çıktısı:
'
uzunluk lowerBound equalRange upperBound trisect
1 11 30 16 53 (58 değil)
2 12 21 19 45 (53 değil)
4 13 20 13 45 (47 değil)
8 16 24 16 48 (57 değil)
16 18 27 19 52 (65 değil)
32 21 29 22 54 (73 değil)
64 24 33 24 58 (82 değil)
128 26 38 27 62 (92 değil)
256 29 40 31 64 (101 değil)
512 32 44 33 68 (111 değil)
1024 35 49 37 73 (122 değil)
2048 38 53 39 77 (131 değil)
4096 41 58 43 82 (143 değil)
8192 46 63 46 87 (156 değil)
16384 50 68 51 92 (171 değil)
32768 53 73 54 98 (180 değil)
65536 58 81 58 104 (198 değil)
'
Görüldüğü gibi, dört algoritma da logaritmik olarak gidiyor. (Yani, uzunluk iki katına çıktığında süre iki katına çıkmıyor; çok daha yavaş büyüyor.) Ek olarak, trisect ilk üçünün parantez içinde bildirdiğim toplamındaha daha hızlı işliyor.
Ali
--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]