// Copyright 2024 Google LLC
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "third_party/highway/hwy/stats.h"
#include <stdio.h>
#include <algorithm>
// std::min
#include <string>
#include "third_party/highway/hwy/base.h" // HWY_ASSERT
namespace hwy {
void Stats::Assimilate(
const Stats& other) {
const int64_t total_n = n_ + other.n_;
if (total_n ==
0)
return;
// Nothing to do; prevents div by zero.
min_ = std::min(min_, other.min_);
max_ = std::max(max_, other.max_);
sum_log_ += other.sum_log_;
const double product_n = n_ * other.n_;
const double n2 = n_ * n_;
const double other_n2 = other.n_ * other.n_;
const int64_t total_n2 = total_n * total_n;
const double total_n3 =
static_cast<
double>(total_n2) * total_n;
// Precompute reciprocal for speed - used at least twice.
const double inv_total_n =
1.
0 / total_n;
const double inv_total_n2 =
1.
0 / total_n2;
const double delta = other.m1_ - m1_;
const double delta2 = delta * delta;
const double delta3 = delta * delta2;
const double delta4 = delta2 * delta2;
m1_ = (n_ * m1_ + other.n_ * other.m1_) * inv_total_n;
const double new_m2 = m2_ + other.m2_ + delta2 * product_n * inv_total_n;
const double new_m3 =
m3_ + other.m3_ + delta3 * product_n * (n_ - other.n_) * inv_total_n2 +
3.
0 * delta * (n_ * other.m2_ - other.n_ * m2_) * inv_total_n;
m4_ += other.m4_ +
delta4 * product_n * (n2 - product_n + other_n2) / total_n3 +
6.
0 * delta2 * (n2 * other.m2_ + other_n2 * m2_) * inv_total_n2 +
4.
0 * delta * (n_ * other.m3_ - other.n_ * m3_) * inv_total_n;
m2_ = new_m2;
m3_ = new_m3;
n_ = total_n;
}
std::string Stats::ToString(int exclude)
const {
if (Count() ==
0)
return std::string(
"(none)");
char buf[
300];
size_t pos =
0;
int ret;
// snprintf - bytes written or negative for error.
if ((exclude & kNoCount) ==
0) {
ret = snprintf(buf + pos,
sizeof(buf) - pos,
"Count=%9zu ",
static_cast<size_t>(Count()));
HWY_ASSERT(ret >
0);
pos += ret;
}
if ((exclude & kNoMeanSD) ==
0) {
const float sd = StandardDeviation();
ret = snprintf(buf + pos,
sizeof(buf) - pos,
"Mean=%10.3e SD=%8.2e ",
Mean(), sd);
HWY_ASSERT(ret >
0);
pos += ret;
}
if ((exclude & kNoMinMax) ==
0) {
ret = snprintf(buf + pos,
sizeof(buf) - pos,
"Min=%10.3e Max=%10.3e ",
static_cast<
double>(Min()),
static_cast<
double>(Max()));
HWY_ASSERT(ret >
0);
pos += ret;
}
if ((exclude & kNoSkewKurt) ==
0) {
ret = snprintf(buf + pos,
sizeof(buf) - pos,
"Skew=%5.2f Kurt=%7.2f ",
Skewness(), Kurtosis());
HWY_ASSERT(ret >
0);
pos += ret;
}
if ((exclude & kNoGeomean) ==
0) {
ret = snprintf(buf + pos,
sizeof(buf) - pos,
"GeoMean=%9.6f ",
GeometricMean());
HWY_ASSERT(ret >
0);
pos += ret;
}
HWY_ASSERT(pos <
sizeof(buf));
return buf;
}
}
// namespace hwy