From 6a8844e2fc1d24596ae67bc970bb7616eec8ea89 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 19 Feb 2026 15:28:12 -0600 Subject: [PATCH] [sensor] Replace powf with pow10_int in sensor filters Add shared pow10_int() helper to helpers.h that computes 10^exp using iterative multiplication/division instead of powf. Replace powf(10, exp) calls in: - sensor/filter.cpp: ValueListFilter and RoundFilter - helpers.cpp: normalize_accuracy_decimals (refactored to use pow10_int for the general case, keeping -1/-2 fast paths) Eliminates powf/__ieee754_powf from builds where sensor filters are the only remaining powf call site. --- esphome/components/sensor/filter.cpp | 5 +++-- esphome/core/helpers.cpp | 19 +++++++------------ esphome/core/helpers.h | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index ea0e2f0d7c..86d99ad2d7 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -2,6 +2,7 @@ #include #include "esphome/core/application.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" #include "sensor.h" @@ -237,7 +238,7 @@ ValueListFilter::ValueListFilter(std::initializer_list> bool ValueListFilter::value_matches_any_(float sensor_value) { int8_t accuracy = this->parent_->get_accuracy_decimals(); - float accuracy_mult = powf(10.0f, accuracy); + float accuracy_mult = pow10_int(accuracy); float rounded_sensor = roundf(accuracy_mult * sensor_value); for (auto &filter_value : this->values_) { @@ -469,7 +470,7 @@ optional ClampFilter::new_value(float value) { RoundFilter::RoundFilter(uint8_t precision) : precision_(precision) {} optional RoundFilter::new_value(float value) { if (std::isfinite(value)) { - float accuracy_mult = powf(10.0f, this->precision_); + float accuracy_mult = pow10_int(this->precision_); return roundf(accuracy_mult * value) / accuracy_mult; } return value; diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index be2cb1b3f0..6e4f5ac1c4 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -468,20 +468,15 @@ ParseOnOffState parse_on_off(const char *str, const char *on, const char *off) { static inline void normalize_accuracy_decimals(float &value, int8_t &accuracy_decimals) { if (accuracy_decimals < 0) { - // Clamp to -9 to keep divisor within uint32_t range (max 10^9 = 1,000,000,000) - int8_t dec = accuracy_decimals < -9 ? (int8_t) -9 : accuracy_decimals; - uint32_t divisor; - if (dec == -1) { - divisor = 10; - } else if (dec == -2) { - divisor = 100; + float divisor; + if (accuracy_decimals == -1) { + divisor = 10.0f; + } else if (accuracy_decimals == -2) { + divisor = 100.0f; } else { - divisor = 1000; - for (int8_t i = dec + 3; i < 0; i++) - divisor *= 10; + divisor = pow10_int(-accuracy_decimals); } - auto divisor_f = static_cast(divisor); - value = roundf(value / divisor_f) * divisor_f; + value = roundf(value / divisor) * divisor; accuracy_decimals = 0; } } diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 298b93fbc4..0185437cc4 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -439,6 +439,21 @@ template class SmallBufferWithHeapFallb /// @name Mathematics ///@{ +/// Compute 10^exp using iterative multiplication/division. +/// Avoids pulling in powf/__ieee754_powf (~2.3KB flash) for small integer exponents. +/// Exact for non-negative exponents up to 10 (powers of 10 up to 10^10 are exact in float). +inline float pow10_int(int8_t exp) { + float result = 1.0f; + if (exp >= 0) { + for (int8_t i = 0; i < exp; i++) + result *= 10.0f; + } else { + for (int8_t i = exp; i < 0; i++) + result /= 10.0f; + } + return result; +} + /// Remap \p value from the range (\p min, \p max) to (\p min_out, \p max_out). template T remap(U value, U min, U max, T min_out, T max_out) { return (value - min) * (max_out - min_out) / (max - min) + min_out;