Mode per window via tolerance-bucketed frequency count.
Buckets values at tolerance 1e-10 and returns the mean of the most frequent bucket.
560{
561 std::vector<double> out(n_windows);
562 std::vector<size_t> idx(n_windows);
563 std::iota(idx.begin(), idx.end(), 0);
564
565 constexpr double tol = 1e-10;
566
567 Parallel::for_each(Parallel::par_unseq, idx.begin(), idx.end(),
568 [&](size_t i) {
569 const size_t start = i * hop_size;
570 auto w = data.subspan(start, std::min<size_t>(window_size, data.size() - start));
571 if (w.empty()) {
572 out[i] = 0.0;
573 return;
574 }
575 std::map<int64_t, std::pair<double, size_t>> freq;
576 for (double v : w) {
577 const auto bucket = static_cast<int64_t>(std::round(v / tol));
578 auto& [sum_v, cnt] = freq[bucket];
579 sum_v = (sum_v * static_cast<double>(cnt) + v) / static_cast<double>(cnt + 1);
580 ++cnt;
581 }
582 const auto it = std::ranges::max_element(freq,
583 [](
const auto&
a,
const auto&
b) {
return a.second.second <
b.second.second; });
584 out[i] = it->second.first;
585 });
586
587 return out;
588}