| // 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 |