| #include "tlbmc/thermal/controller/optimizer/pid/frequency_response_estimation/utils.h" |
| |
| #include <cmath> |
| #include <cstdlib> |
| #include <limits> |
| |
| namespace milotic_tlbmc { |
| namespace thermal { |
| namespace optimizer { |
| |
| double SafeHypotenuse(double u0, double u1) { |
| double a = std::abs(u0); |
| double b = std::abs(u1); |
| if (a < b) { |
| a /= b; |
| return std::sqrt(a * a + 1.0) * b; |
| } |
| if (a > b) { |
| b /= a; |
| return std::sqrt(b * b + 1.0) * a; |
| } |
| return std::isnan(b) ? std::numeric_limits<double>::quiet_NaN() |
| : std::sqrt(2.0) * a; |
| } |
| |
| double SafePow(double base, double exp) { |
| if (std::isnan(base) || std::isnan(exp)) { |
| return std::numeric_limits<double>::quiet_NaN(); |
| } |
| |
| double abs_base = std::abs(base); |
| |
| // Handle `\infty` |
| if (std::isinf(exp)) { |
| // `1 ^ {\infty}` is undefined without a very specific mathematical |
| // context. Examples below: |
| // 1. `\lim_{n \to \infty} (1 + \frac{1}{n})^n = e` |
| // 2. `\lim_{n \to \infty} (1 + \frac{1}{\sqrt{n}})^n = \infty` |
| // 3. `\lim_{n \to \infty} (1 + \frac{k}{n})^n = e^{k}` |
| if (std::abs(abs_base - 1.0) < kEps) { |
| return std::numeric_limits<double>::quiet_NaN(); |
| } |
| if (abs_base > 1.0) { |
| return exp > 0.0 ? std::numeric_limits<double>::infinity() : 0.0; |
| } |
| return exp > 0.0 ? 0.0 : std::numeric_limits<double>::infinity(); |
| } |
| |
| // `b^0 = 1` |
| if (std::abs(exp) < kEps) { |
| return 1.0; |
| } |
| |
| // `b^1 = b`, `b^{-1} = 1/b` |
| double abs_exp = std::abs(exp); |
| if (std::abs(abs_exp - 1.0) < kEps) { |
| return exp > 0.0 ? base : 1.0 / base; |
| } |
| |
| // `b^2 = b * b` |
| if (std::abs(exp - 2.0) < kEps) { |
| return base * base; |
| } |
| |
| // `b^{0.5} = \sqrt{b}` |
| if (std::abs(exp - 0.5) < kEps && base >= 0.0) { |
| return std::sqrt(base); |
| } |
| |
| // A domain error occurs in `std::pow` if the base is negative and the |
| // exp is fractional. |
| return (base < 0.0 && exp != std::floor(exp)) |
| ? std::numeric_limits<double>::quiet_NaN() |
| : std::pow(base, exp); |
| } |
| |
| } // namespace optimizer |
| } // namespace thermal |
| } // namespace milotic_tlbmc |