[libc-commits] [libc] [libc][math] Add code size optimized float-only options for exp*f funtions. (PR #224735)

via libc-commits libc-commits at lists.llvm.org
Sat Sep 19 06:14:35 PDT 2026


https://github.com/lntue updated https://github.com/llvm/llvm-project/pull/224735

>From c667643248c839e9b5900ec1ab7bacfdead623a9 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Fri, 18 Sep 2026 20:13:19 +0000
Subject: [PATCH 1/3] [libc][math] Add code size optimized float-only options
 for exp*f functions.

---
 libc/src/__support/math/CMakeLists.txt        | 120 +++++++-
 libc/src/__support/math/exp10f.h              | 147 ++--------
 libc/src/__support/math/exp10f_double_eval.h  | 155 ++++++++++
 libc/src/__support/math/exp10f_float_eval.h   | 153 ++++++++++
 libc/src/__support/math/exp2f.h               | 171 ++----------
 libc/src/__support/math/exp2f_double_eval.h   | 178 ++++++++++++
 libc/src/__support/math/exp2f_float_eval.h    |  96 +++++++
 libc/src/__support/math/exp2f_float_utils.h   | 107 +++++++
 libc/src/__support/math/expf.h                | 122 ++------
 libc/src/__support/math/expf_double_eval.h    | 125 +++++++++
 libc/src/__support/math/expf_float_eval.h     | 126 +++++++++
 libc/src/__support/math/expf_integer_eval.h   |  19 +-
 libc/src/math/generic/expf.cpp                |  12 +-
 libc/test/src/math/CMakeLists.txt             |  24 +-
 libc/test/src/math/exhaustive/CMakeLists.txt  |  21 +-
 .../src/math/exhaustive/exhaustive_test.h     |  67 +++++
 .../exhaustive_test_static_rounding.h         |   7 +-
 libc/test/src/math/exhaustive/exp10f_test.cpp |  37 ++-
 libc/test/src/math/exhaustive/exp2f_test.cpp  |  37 ++-
 .../exhaustive/expf_static_rounding_test.cpp  |  39 ---
 libc/test/src/math/exhaustive/expf_test.cpp   |  55 +++-
 libc/test/src/math/exp10f_test.cpp            | 264 +++++++++++-------
 libc/test/src/math/exp2f_test.cpp             | 254 ++++++++++-------
 .../src/math/expf_static_rounding_test.cpp    | 133 ---------
 libc/test/src/math/expf_test.cpp              | 250 +++++++++++------
 libc/test/src/math/smoke/CMakeLists.txt       |  22 +-
 libc/test/src/math/smoke/exp10f_test.cpp      | 158 ++++++-----
 libc/test/src/math/smoke/exp2f_test.cpp       | 160 ++++++-----
 .../math/smoke/expf_static_rounding_test.cpp  |  62 ----
 libc/test/src/math/smoke/expf_test.cpp        | 172 ++++++++----
 30 files changed, 2122 insertions(+), 1171 deletions(-)
 create mode 100644 libc/src/__support/math/exp10f_double_eval.h
 create mode 100644 libc/src/__support/math/exp10f_float_eval.h
 create mode 100644 libc/src/__support/math/exp2f_double_eval.h
 create mode 100644 libc/src/__support/math/exp2f_float_eval.h
 create mode 100644 libc/src/__support/math/exp2f_float_utils.h
 create mode 100644 libc/src/__support/math/expf_double_eval.h
 create mode 100644 libc/src/__support/math/expf_float_eval.h
 delete mode 100644 libc/test/src/math/exhaustive/expf_static_rounding_test.cpp
 delete mode 100644 libc/test/src/math/expf_static_rounding_test.cpp
 delete mode 100644 libc/test/src/math/smoke/expf_static_rounding_test.cpp

diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index 0871a5bf229b6..08017d264a300 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -3072,20 +3072,64 @@ add_header_library(
 )
 
 add_header_library(
-  expf
+  exp2f_float_utils
   HDRS
-    expf.h
+    exp2f_float_utils.h
+  DEPENDS
+    libc.src.__support.CPP.bit
+    libc.src.__support.FPUtil.multiply_add
+    libc.src.__support.macros.config
+    libc.src.__support.macros.optimization
+)
+
+add_header_library(
+  expf_double_eval
+  HDRS
+    expf_double_eval.h
   DEPENDS
     .exp_float_constants
-    libc.src.__support.common
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
     libc.src.__support.FPUtil.multiply_add
     libc.src.__support.FPUtil.nearest_integer
     libc.src.__support.FPUtil.polyeval
     libc.src.__support.FPUtil.rounding_mode
+    libc.src.__support.common
+    libc.src.__support.macros.config
+    libc.src.__support.macros.optimization
+)
+
+add_header_library(
+  expf_float_eval
+  HDRS
+    expf_float_eval.h
+  DEPENDS
+    .exp2f_float_utils
+    libc.src.__support.FPUtil.double_double
+    libc.src.__support.FPUtil.fenv_impl
+    libc.src.__support.FPUtil.fp_bits
+    libc.src.__support.FPUtil.multiply_add
+    libc.src.__support.FPUtil.nearest_integer
+    libc.src.__support.FPUtil.rounding_mode
+    libc.src.__support.common
+    libc.src.__support.macros.config
+    libc.src.__support.macros.optimization
+    libc.src.__support.macros.properties.cpu_features
+)
+
+add_header_library(
+  expf
+  HDRS
+    expf.h
+  DEPENDS
+    .expf_double_eval
+    .expf_float_eval
+    .expf_integer_eval
+    libc.hdr.fenv_macros
+    libc.src.__support.common
     libc.src.__support.macros.config
     libc.src.__support.macros.optimization
+    libc.src.__support.macros.properties.cpu_features
 )
 
 add_header_library(
@@ -4178,9 +4222,9 @@ add_header_library(
 )
 
 add_header_library(
-  exp2f
+  exp2f_double_eval
   HDRS
-    exp2f.h
+    exp2f_double_eval.h
   DEPENDS
     .exp10f_utils
     libc.src.__support.FPUtil.except_value_utils
@@ -4190,9 +4234,38 @@ add_header_library(
     libc.src.__support.FPUtil.nearest_integer
     libc.src.__support.FPUtil.polyeval
     libc.src.__support.FPUtil.rounding_mode
+    libc.src.__support.common
+    libc.src.__support.macros.config
+    libc.src.__support.macros.optimization
+    libc.src.__support.macros.properties.cpu_features
+)
+
+add_header_library(
+  exp2f_float_eval
+  HDRS
+    exp2f_float_eval.h
+  DEPENDS
+    .exp2f_float_utils
+    libc.src.__support.FPUtil.fenv_impl
+    libc.src.__support.FPUtil.fp_bits
+    libc.src.__support.FPUtil.multiply_add
+    libc.src.__support.FPUtil.nearest_integer
+    libc.src.__support.FPUtil.rounding_mode
+    libc.src.__support.common
+    libc.src.__support.macros.config
     libc.src.__support.macros.optimization
+)
+
+add_header_library(
+  exp2f
+  HDRS
+    exp2f.h
+  DEPENDS
+    .exp2f_double_eval
+    .exp2f_float_eval
     libc.src.__support.common
-    libc.src.errno.errno
+    libc.src.__support.macros.config
+    libc.src.__support.macros.optimization
 )
 
 add_header_library(
@@ -4281,16 +4354,47 @@ add_header_library(
 )
 
 add_header_library(
-  exp10f
+  exp10f_double_eval
   HDRS
-    exp10f.h
+    exp10f_double_eval.h
   DEPENDS
     .exp10f_utils
+    libc.src.__support.FPUtil.fenv_impl
+    libc.src.__support.FPUtil.fp_bits
+    libc.src.__support.FPUtil.multiply_add
+    libc.src.__support.FPUtil.nearest_integer
+    libc.src.__support.FPUtil.rounding_mode
     libc.src.__support.macros.config
+    libc.src.__support.macros.optimization
+)
+
+add_header_library(
+  exp10f_float_eval
+  HDRS
+    exp10f_float_eval.h
+  DEPENDS
+    .exp2f_float_utils
+    libc.src.__support.FPUtil.double_double
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
     libc.src.__support.FPUtil.multiply_add
+    libc.src.__support.FPUtil.nearest_integer
     libc.src.__support.FPUtil.rounding_mode
+    libc.src.__support.common
+    libc.src.__support.macros.config
+    libc.src.__support.macros.optimization
+    libc.src.__support.macros.properties.cpu_features
+)
+
+add_header_library(
+  exp10f
+  HDRS
+    exp10f.h
+  DEPENDS
+    .exp10f_double_eval
+    .exp10f_float_eval
+    libc.src.__support.common
+    libc.src.__support.macros.config
     libc.src.__support.macros.optimization
 )
 
diff --git a/libc/src/__support/math/exp10f.h b/libc/src/__support/math/exp10f.h
index 642370a3d2aa3..67a9d24a5a2c2 100644
--- a/libc/src/__support/math/exp10f.h
+++ b/libc/src/__support/math/exp10f.h
@@ -1,147 +1,44 @@
-//===-- Implementation header for exp10f ------------------------*- C++ -*-===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for exp10f.
+///
+//===----------------------------------------------------------------------===//
 
 #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP10F_H
 #define LLVM_LIBC_SRC___SUPPORT_MATH_EXP10F_H
 
-#include "exp10f_utils.h"
-#include "src/__support/FPUtil/FEnvImpl.h"
-#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/FPUtil/multiply_add.h"
-#include "src/__support/FPUtil/rounding_mode.h"
+#include "src/__support/common.h"
 #include "src/__support/macros/config.h"
-#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
-
-namespace LIBC_NAMESPACE_DECL {
-namespace math {
-
-LIBC_INLINE float exp10f(float x) {
-  using FPBits = typename fputil::FPBits<float>;
-  FPBits xbits(x);
+#include "src/__support/macros/optimization.h"
 
-  uint32_t x_u = xbits.uintval();
-  uint32_t x_abs = x_u & 0x7fff'ffffU;
+#if defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) &&                               \
+    (defined(LIBC_MATH_HAS_SMALL_TABLES) ||                                    \
+     defined(LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT))
 
-  // When |x| >= log10(2^128), or x is nan
-  if (LIBC_UNLIKELY(x_abs >= 0x421a'209bU)) {
-    // When x < log10(2^-150) or nan
-    if (x_u > 0xc234'9e35U) {
-      // exp(-Inf) = 0
-      if (xbits.is_inf())
-        return 0.0f;
-      // exp(nan) = nan
-      if (xbits.is_nan())
-        return x;
-#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
-      if (fputil::fenv_is_round_up())
-        return FPBits::min_subnormal().get_val();
-#endif
-      fputil::set_errno_if_required(ERANGE);
-      fputil::raise_except_if_required(FE_UNDERFLOW);
-      return 0.0f;
-    }
-    // x >= log10(2^128) or nan
-    if (xbits.is_pos() && (x_u >= 0x421a'209bU)) {
-      // x is finite
-      if (x_u < 0x7f80'0000U) {
-#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
-        int rounding = fputil::quick_get_round();
-        if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
-          return FPBits::max_normal().get_val();
-#endif
+#include "src/__support/math/exp10f_float_eval.h"
+#define LIBC_MATH_EXP10F_IMPL float_eval
 
-        fputil::set_errno_if_required(ERANGE);
-        fputil::raise_except_if_required(FE_OVERFLOW);
-      }
-      // x is +inf or nan
-      return x + FPBits::inf().get_val();
-    }
-  }
+#else // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+#include "src/__support/math/exp10f_double_eval.h"
+#define LIBC_MATH_EXP10F_IMPL double_eval
 
-  // When |x| <= log10(2)*2^-6
-  if (LIBC_UNLIKELY(x_abs <= 0x3b9a'209bU)) {
-    if (LIBC_UNLIKELY(x_u == 0xb25e'5bd9U)) { // x = -0x1.bcb7b2p-27f
-#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
-      return 0x1.fffffep-1f;
-#else
-      if (fputil::fenv_is_round_to_nearest())
-        return 0x1.fffffep-1f;
-#endif
-    }
-    // |x| < 2^-25
-    // 10^x ~ 1 + log(10) * x
-    if (LIBC_UNLIKELY(x_abs <= 0x3280'0000U)) {
-      return fputil::multiply_add(x, 0x1.26bb1cp+1f, 1.0f);
-    }
+#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
 
-    return static_cast<float>(Exp10Base::powb_lo(x));
-  }
-
-  // Exceptional value.
-  if (LIBC_UNLIKELY(x_u == 0x3d14'd956U)) { // x = 0x1.29b2acp-5f
-#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
-    if (fputil::fenv_is_round_up())
-      return 0x1.1657c4p+0f;
-#endif
-  }
-
-  // Exact outputs when x = 1, 2, ..., 10.
-  // Quick check mask: 0x800f'ffffU = ~(bits of 1.0f | ... | bits of 10.0f)
-  if (LIBC_UNLIKELY((x_u & 0x800f'ffffU) == 0)) {
-    switch (x_u) {
-    case 0x3f800000U: // x = 1.0f
-      return 10.0f;
-    case 0x40000000U: // x = 2.0f
-      return 100.0f;
-    case 0x40400000U: // x = 3.0f
-      return 1'000.0f;
-    case 0x40800000U: // x = 4.0f
-      return 10'000.0f;
-    case 0x40a00000U: // x = 5.0f
-      return 100'000.0f;
-    case 0x40c00000U: // x = 6.0f
-      return 1'000'000.0f;
-    case 0x40e00000U: // x = 7.0f
-      return 10'000'000.0f;
-    case 0x41000000U: // x = 8.0f
-      return 100'000'000.0f;
-    case 0x41100000U: // x = 9.0f
-      return 1'000'000'000.0f;
-    case 0x41200000U: // x = 10.0f
-      return 10'000'000'000.0f;
-    }
-  }
-
-  // Range reduction: 10^x = 2^(mid + hi) * 10^lo
-  //   rr = (2^(mid + hi), lo)
-  auto rr = exp_b_range_reduc<Exp10Base>(x);
+namespace LIBC_NAMESPACE_DECL {
+namespace math {
 
-  // The low part is approximated by a degree-5 minimax polynomial.
-  // 10^lo ~ 1 + COEFFS[0] * lo + ... + COEFFS[4] * lo^5
-  using fputil::multiply_add;
-  double lo2 = rr.lo * rr.lo;
-  // c0 = 1 + COEFFS[0] * lo
-  double c0 = multiply_add(rr.lo, Exp10Base::COEFFS[0], 1.0);
-  // c1 = COEFFS[1] + COEFFS[2] * lo
-  double c1 = multiply_add(rr.lo, Exp10Base::COEFFS[2], Exp10Base::COEFFS[1]);
-  // c2 = COEFFS[3] + COEFFS[4] * lo
-  double c2 = multiply_add(rr.lo, Exp10Base::COEFFS[4], Exp10Base::COEFFS[3]);
-  // p = c1 + c2 * lo^2
-  //   = COEFFS[1] + COEFFS[2] * lo + COEFFS[3] * lo^2 + COEFFS[4] * lo^3
-  double p = multiply_add(lo2, c2, c1);
-  // 10^lo ~ c0 + p * lo^2
-  // 10^x = 2^(mid + hi) * 10^lo
-  //      ~ mh * (c0 + p * lo^2)
-  //      = (mh * c0) + p * (mh * lo^2)
-  return static_cast<float>(multiply_add(p, lo2 * rr.mh, c0 * rr.mh));
-}
+using LIBC_MATH_EXP10F_IMPL::exp10f;
 
 } // namespace math
 } // namespace LIBC_NAMESPACE_DECL
 
+#undef LIBC_MATH_EXP10F_IMPL
+
 #endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP10F_H
diff --git a/libc/src/__support/math/exp10f_double_eval.h b/libc/src/__support/math/exp10f_double_eval.h
new file mode 100644
index 0000000000000..03e3790c87e70
--- /dev/null
+++ b/libc/src/__support/math/exp10f_double_eval.h
@@ -0,0 +1,155 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Double-precision implementation of exp10f.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP10F_DOUBLE_EVAL_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP10F_DOUBLE_EVAL_H
+
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/FPUtil/nearest_integer.h"
+#include "src/__support/FPUtil/rounding_mode.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/math/exp10f_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace math {
+namespace double_eval {
+
+LIBC_INLINE float exp10f(float x) {
+  using FPBits = typename fputil::FPBits<float>;
+  FPBits xbits(x);
+
+  uint32_t x_u = xbits.uintval();
+  uint32_t x_abs = x_u & 0x7fff'ffffU;
+
+  // When |x| >= log10(2^128), or x is nan
+  if (LIBC_UNLIKELY(x_abs >= 0x421a'209bU)) {
+    // When x < log10(2^-150) or nan
+    if (x_u > 0xc234'9e35U) {
+      // exp(-Inf) = 0
+      if (xbits.is_inf())
+        return 0.0f;
+      // exp(nan) = nan
+      if (xbits.is_nan())
+        return x;
+#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+      if (fputil::fenv_is_round_up())
+        return FPBits::min_subnormal().get_val();
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+      fputil::set_errno_if_required(ERANGE);
+      fputil::raise_except_if_required(FE_UNDERFLOW);
+      return 0.0f;
+    }
+    // x >= log10(2^128) or nan
+    if (xbits.is_pos() && (x_u >= 0x421a'209bU)) {
+      // x is finite
+      if (x_u < 0x7f80'0000U) {
+#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+        int rounding = fputil::quick_get_round();
+        if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
+          return FPBits::max_normal().get_val();
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+
+        fputil::set_errno_if_required(ERANGE);
+        fputil::raise_except_if_required(FE_OVERFLOW);
+      }
+      // x is +inf or nan
+      return x + FPBits::inf().get_val();
+    }
+  }
+
+  // When |x| <= log10(2)*2^-6
+  if (LIBC_UNLIKELY(x_abs <= 0x3b9a'209bU)) {
+    if (LIBC_UNLIKELY(x_u == 0xb25e'5bd9U)) { // x = -0x1.bcb7b2p-27f
+#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+      return 0x1.fffffep-1f;
+#else  // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+      if (fputil::fenv_is_round_to_nearest())
+        return 0x1.fffffep-1f;
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+    }
+    // |x| < 2^-25
+    // 10^x ~ 1 + log(10) * x
+    if (LIBC_UNLIKELY(x_abs <= 0x3280'0000U)) {
+      return fputil::multiply_add(x, 0x1.26bb1cp+1f, 1.0f);
+    }
+
+    return static_cast<float>(Exp10Base::powb_lo(x));
+  }
+
+  // Exceptional value.
+  if (LIBC_UNLIKELY(x_u == 0x3d14'd956U)) { // x = 0x1.29b2acp-5f
+#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+    if (fputil::fenv_is_round_up())
+      return 0x1.1657c4p+0f;
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+  }
+
+  // Exact outputs when x = 1, 2, ..., 10.
+  // Quick check mask: 0x800f'ffffU = ~(bits of 1.0f | ... | bits of 10.0f)
+  if (LIBC_UNLIKELY((x_u & 0x800f'ffffU) == 0)) {
+    switch (x_u) {
+    case 0x3f800000U: // x = 1.0f
+      return 10.0f;
+    case 0x40000000U: // x = 2.0f
+      return 100.0f;
+    case 0x40400000U: // x = 3.0f
+      return 1'000.0f;
+    case 0x40800000U: // x = 4.0f
+      return 10'000.0f;
+    case 0x40a00000U: // x = 5.0f
+      return 100'000.0f;
+    case 0x40c00000U: // x = 6.0f
+      return 1'000'000.0f;
+    case 0x40e00000U: // x = 7.0f
+      return 10'000'000.0f;
+    case 0x41000000U: // x = 8.0f
+      return 100'000'000.0f;
+    case 0x41100000U: // x = 9.0f
+      return 1'000'000'000.0f;
+    case 0x41200000U: // x = 10.0f
+      return 10'000'000'000.0f;
+    }
+  }
+
+  // Range reduction: 10^x = 2^(mid + hi) * 10^lo
+  //   rr = (2^(mid + hi), lo)
+  auto rr = exp_b_range_reduc<Exp10Base>(x);
+
+  // The low part is approximated by a degree-5 minimax polynomial.
+  // 10^lo ~ 1 + COEFFS[0] * lo + ... + COEFFS[4] * lo^5
+  using fputil::multiply_add;
+  double lo2 = rr.lo * rr.lo;
+  // c0 = 1 + COEFFS[0] * lo
+  double c0 = multiply_add(rr.lo, Exp10Base::COEFFS[0], 1.0);
+  // c1 = COEFFS[1] + COEFFS[2] * lo
+  double c1 = multiply_add(rr.lo, Exp10Base::COEFFS[2], Exp10Base::COEFFS[1]);
+  // c2 = COEFFS[3] + COEFFS[4] * lo
+  double c2 = multiply_add(rr.lo, Exp10Base::COEFFS[4], Exp10Base::COEFFS[3]);
+  // p = c1 + c2 * lo^2
+  //   = COEFFS[1] + COEFFS[2] * lo + COEFFS[3] * lo^2 + COEFFS[4] * lo^3
+  double p = multiply_add(lo2, c2, c1);
+  // 10^lo ~ c0 + p * lo^2
+  // 10^x = 2^(mid + hi) * 10^lo
+  //      ~ mh * (c0 + p * lo^2)
+  //      = (mh * c0) + p * (mh * lo^2)
+  return static_cast<float>(multiply_add(p, lo2 * rr.mh, c0 * rr.mh));
+}
+
+} // namespace double_eval
+} // namespace math
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP10F_DOUBLE_EVAL_H
diff --git a/libc/src/__support/math/exp10f_float_eval.h b/libc/src/__support/math/exp10f_float_eval.h
new file mode 100644
index 0000000000000..19bbfb93a509e
--- /dev/null
+++ b/libc/src/__support/math/exp10f_float_eval.h
@@ -0,0 +1,153 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Float-only implementation of exp10f.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP10F_FLOAT_EVAL_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP10F_FLOAT_EVAL_H
+
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/double_double.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/FPUtil/nearest_integer.h"
+#include "src/__support/FPUtil/rounding_mode.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/macros/properties/cpu_features.h"
+#include "src/__support/math/exp2f_float_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace math {
+namespace float_eval {
+
+LIBC_INLINE float exp10f(float x) {
+  using FPBits = typename fputil::FPBits<float>;
+  FPBits xbits(x);
+
+  uint32_t x_u = xbits.uintval();
+  uint32_t x_abs = x_u & 0x7fff'ffffU;
+
+  // When |x| >= log10(2^128), or x is nan
+  if (LIBC_UNLIKELY(x_abs >= 0x421a'209bU)) {
+    // When x < log10(2^-150) or nan
+    if (x_u > 0xc234'9e35U) {
+      // exp(-Inf) = 0
+      if (xbits.is_inf())
+        return 0.0f;
+      // exp(nan) = nan
+      if (xbits.is_nan())
+        return x;
+#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+      if (fputil::fenv_is_round_up())
+        return FPBits::min_subnormal().get_val();
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+      fputil::set_errno_if_required(ERANGE);
+      fputil::raise_except_if_required(FE_UNDERFLOW);
+      return 0.0f;
+    }
+    // x >= log10(2^128) or nan
+    if (xbits.is_pos() && (x_u >= 0x421a'209bU)) {
+      // x is finite
+      if (x_u < 0x7f80'0000U) {
+#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+        int rounding = fputil::quick_get_round();
+        if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
+          return FPBits::max_normal().get_val();
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+
+        fputil::set_errno_if_required(ERANGE);
+        fputil::raise_except_if_required(FE_OVERFLOW);
+      }
+      // x is +inf or nan
+      return x + FPBits::inf().get_val();
+    }
+  }
+
+  // |x| <= 2^-25
+  // 10^x ~ 1 + log(10) * x
+  if (LIBC_UNLIKELY(x_abs <= 0x3280'0000U)) {
+    return fputil::multiply_add(x, 0x1.26bb1cp+1f, 1.0f);
+  }
+
+  // Exact outputs when x = 1, 2, ..., 10.
+  // Quick check mask: 0x800f'ffffU = ~(bits of 1.0f | ... | bits of 10.0f)
+  if (LIBC_UNLIKELY((x_u & 0x800f'ffffU) == 0)) {
+    switch (x_u) {
+    case 0x3f800000U: // x = 1.0f
+      return 10.0f;
+    case 0x40000000U: // x = 2.0f
+      return 100.0f;
+    case 0x40400000U: // x = 3.0f
+      return 1'000.0f;
+    case 0x40800000U: // x = 4.0f
+      return 10'000.0f;
+    case 0x40a00000U: // x = 5.0f
+      return 100'000.0f;
+    case 0x40c00000U: // x = 6.0f
+      return 1'000'000.0f;
+    case 0x40e00000U: // x = 7.0f
+      return 10'000'000.0f;
+    case 0x41000000U: // x = 8.0f
+      return 100'000'000.0f;
+    case 0x41100000U: // x = 9.0f
+      return 1'000'000'000.0f;
+    case 0x41200000U: // x = 10.0f
+      return 10'000'000'000.0f;
+    }
+  }
+
+  // Range reduction:
+  //   k = round(x * log2(10))
+  //   x * log2(10) = k + u, with |u| <= 0.5
+  //   10^x = 2^(k + u) = 2^k * 2^u
+#if defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT)
+  // Constants generated by Sollya with:
+  // > display = hexadecimal;
+  // > hi = round(log2(10), SG, RN);
+  // > lo = round(log2(10) - hi, SG, RN);
+  constexpr fputil::FloatFloat LOG2_10 = {0x1.2f346ep-24f, 0x1.a934fp+1f};
+
+  float kf = fputil::nearest_integer(x * LOG2_10.hi);
+  int k = static_cast<int>(kf);
+
+  float u_hi = fputil::multiply_add(x, LOG2_10.hi, -kf);
+  float u = fputil::multiply_add(x, LOG2_10.lo, u_hi);
+#else  // !LIBC_TARGET_CPU_HAS_FMA_FLOAT
+  // Cody-Waite reduction for non-FMA targets:
+  // Constants generated by Sollya with:
+  // > display = hexadecimal;
+  // > LOG2_10 = round(log2(10), SG, RN);
+  // > LOG10_2_HI = round(log10(2), 12, RN);
+  // > LOG10_2_LO = round(log10(2) - LOG10_2_HI, SG, RN);
+  constexpr float LOG2_10 = 0x1.a934fp+1f;
+  constexpr float LOG10_2_HI = 0x1.344p-2f;
+  constexpr float LOG10_2_LO = 0x1.3509f8p-18f;
+
+  float kf = fputil::nearest_integer(x * LOG2_10);
+  int k = static_cast<int>(kf);
+
+  float v_hi = fputil::multiply_add(-kf, LOG10_2_HI, x);
+  float v = fputil::multiply_add(-kf, LOG10_2_LO, v_hi);
+
+  // Convert reduced argument to base-2: u = v * log2(10)
+  float u = v * LOG2_10;
+#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT
+
+  return exp2f_eval(u, k);
+}
+
+} // namespace float_eval
+} // namespace math
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP10F_FLOAT_EVAL_H
diff --git a/libc/src/__support/math/exp2f.h b/libc/src/__support/math/exp2f.h
index 1fa24c2013ede..e7ce1ec29c03b 100644
--- a/libc/src/__support/math/exp2f.h
+++ b/libc/src/__support/math/exp2f.h
@@ -1,173 +1,44 @@
-//===-- Implementation header for exp2f -------------------------*- C++ -*-===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for exp2f.
+///
+//===----------------------------------------------------------------------===//
 
 #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_H
 #define LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_H
 
-#include "exp10f_utils.h"
-#include "src/__support/FPUtil/FEnvImpl.h"
-#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/FPUtil/PolyEval.h"
-#include "src/__support/FPUtil/except_value_utils.h"
-#include "src/__support/FPUtil/multiply_add.h"
-#include "src/__support/FPUtil/nearest_integer.h"
-#include "src/__support/FPUtil/rounding_mode.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
-#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
-#include "src/__support/macros/properties/cpu_features.h"
-
-namespace LIBC_NAMESPACE_DECL {
-
-namespace math {
-
-LIBC_INLINE float exp2f(float x) {
-  using FPBits = typename fputil::FPBits<float>;
-  FPBits xbits(x);
-
-  uint32_t x_u = xbits.uintval();
-  uint32_t x_abs = x_u & 0x7fff'ffffU;
-
-  // When |x| >= 128, or x is nan, or |x| <= 2^-5
-  if (LIBC_UNLIKELY(x_abs >= 0x4300'0000U || x_abs <= 0x3d00'0000U)) {
-    // |x| <= 2^-5
-    if (x_abs <= 0x3d00'0000) {
-      // |x| < 2^-25
-      if (LIBC_UNLIKELY(x_abs <= 0x3280'0000U)) {
-        return 1.0f + x;
-      }
+#include "src/__support/macros/optimization.h"
 
-#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-      constexpr uint32_t EXVAL1 = 0x3b42'9d37U;
-      constexpr uint32_t EXVAL2 = 0xbcf3'a937U;
-      constexpr uint32_t EXVAL_MASK = EXVAL1 & EXVAL2;
+#if defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) &&                               \
+    (defined(LIBC_MATH_HAS_SMALL_TABLES) ||                                    \
+     defined(LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT))
 
-      // Check exceptional values.
-      if (LIBC_UNLIKELY((x_u & EXVAL_MASK) == EXVAL_MASK)) {
-        if (LIBC_UNLIKELY(x_u == EXVAL1)) { // x = 0x1.853a6ep-9f
-          return fputil::round_result_slightly_down(0x1.00870ap+0f);
-        } else if (LIBC_UNLIKELY(x_u == EXVAL2)) { // x = -0x1.e7526ep-6f
-          return fputil::round_result_slightly_down(0x1.f58d62p-1f);
-        }
-      }
-#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+#include "src/__support/math/exp2f_float_eval.h"
+#define LIBC_MATH_EXP2F_IMPL float_eval
 
-      // Minimax polynomial generated by Sollya with:
-      // > P = fpminimax((2^x - 1)/x, 5, [|D...|], [-2^-5, 2^-5]);
-      constexpr double COEFFS[] = {
-          0x1.62e42fefa39f3p-1, 0x1.ebfbdff82c57bp-3,  0x1.c6b08d6f2d7aap-5,
-          0x1.3b2ab6fc92f5dp-7, 0x1.5d897cfe27125p-10, 0x1.43090e61e6af1p-13};
-      double xd = static_cast<double>(x);
-      double xsq = xd * xd;
-      double c0 = fputil::multiply_add(xd, COEFFS[1], COEFFS[0]);
-      double c1 = fputil::multiply_add(xd, COEFFS[3], COEFFS[2]);
-      double c2 = fputil::multiply_add(xd, COEFFS[5], COEFFS[4]);
-      double p = fputil::polyeval(xsq, c0, c1, c2);
-      double r = fputil::multiply_add(p, xd, 1.0);
-      return static_cast<float>(r);
-    }
+#else // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+#include "src/__support/math/exp2f_double_eval.h"
+#define LIBC_MATH_EXP2F_IMPL double_eval
 
-    // x >= 128
-    if (xbits.is_pos()) {
-      // x is finite
-      if (x_u < 0x7f80'0000U) {
-#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
-        int rounding = fputil::quick_get_round();
-        if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
-          return FPBits::max_normal().get_val();
-#endif
+#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
 
-        fputil::set_errno_if_required(ERANGE);
-        fputil::raise_except_if_required(FE_OVERFLOW);
-      }
-      // x is +inf or nan
-      return x + FPBits::inf().get_val();
-    }
-    // x <= -150
-    if (x_u >= 0xc316'0000U) {
-      // exp(-Inf) = 0
-      if (xbits.is_inf())
-        return 0.0f;
-      // exp(nan) = nan
-      if (xbits.is_nan())
-        return x;
-#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
-      if (fputil::fenv_is_round_up())
-        return FPBits::min_subnormal().get_val();
-#endif
-      if (x != 0.0f) {
-        fputil::set_errno_if_required(ERANGE);
-        fputil::raise_except_if_required(FE_UNDERFLOW);
-      }
-      return 0.0f;
-    }
-  }
-
-  // For -150 < x < 128, to compute 2^x, we perform the following range
-  // reduction: find hi, mid, lo such that:
-  //   x = hi + mid + lo, in which
-  //     hi is an integer,
-  //     0 <= mid * 2^5 < 32 is an integer
-  //     -2^(-6) <= lo <= 2^-6.
-  // In particular,
-  //   hi + mid = round(x * 2^5) * 2^(-5).
-  // Then,
-  //   2^x = 2^(hi + mid + lo) = 2^hi * 2^mid * 2^lo.
-  // 2^mid is stored in the lookup table of 32 elements.
-  // 2^lo is computed using a degree-5 minimax polynomial
-  // generated by Sollya.
-  // We perform 2^hi * 2^mid by simply add hi to the exponent field
-  // of 2^mid.
-
-  // kf = (hi + mid) * 2^5 = round(x * 2^5)
-  float kf = 0;
-  int k = 0;
-#ifdef LIBC_TARGET_CPU_HAS_NEAREST_INT
-  kf = fputil::nearest_integer(x * 32.0f);
-  k = static_cast<int>(kf);
-#else
-  constexpr float HALF[2] = {0.5f, -0.5f};
-  k = static_cast<int>(fputil::multiply_add(x, 32.0f, HALF[x < 0.0f]));
-  kf = static_cast<float>(k);
-#endif // LIBC_TARGET_CPU_HAS_NEAREST_INT
-
-  // dx = lo = x - (hi + mid) = x - kf * 2^(-5)
-  double dx = fputil::multiply_add(-0x1.0p-5f, kf, x);
-
-  // hi = floor(kf * 2^(-4))
-  // exp_hi = shift hi to the exponent field of double precision.
-  int64_t exp_hi =
-      static_cast<int64_t>(static_cast<uint64_t>(k >> ExpBase::MID_BITS)
-                           << fputil::FPBits<double>::FRACTION_LEN);
-  // mh = 2^hi * 2^mid
-  // mh_bits = bit field of mh
-  int64_t mh_bits = ExpBase::EXP_2_MID[k & ExpBase::MID_MASK] + exp_hi;
-  double mh = fputil::FPBits<double>(uint64_t(mh_bits)).get_val();
+namespace LIBC_NAMESPACE_DECL {
+namespace math {
 
-  // Degree-5 polynomial approximating (2^x - 1)/x generating by Sollya with:
-  // > P = fpminimax((2^x - 1)/x, 5, [|D...|], [-1/32. 1/32]);
-  constexpr double COEFFS[5] = {0x1.62e42fefa39efp-1, 0x1.ebfbdff8131c4p-3,
-                                0x1.c6b08d7061695p-5, 0x1.3b2b1bee74b2ap-7,
-                                0x1.5d88091198529p-10};
-  double dx_sq = dx * dx;
-  double c1 = fputil::multiply_add(dx, COEFFS[0], 1.0);
-  double c2 = fputil::multiply_add(dx, COEFFS[2], COEFFS[1]);
-  double c3 = fputil::multiply_add(dx, COEFFS[4], COEFFS[3]);
-  double p = fputil::multiply_add(dx_sq, c3, c2);
-  // 2^x = 2^(hi + mid + lo)
-  //     = 2^(hi + mid) * 2^lo
-  //     ~ mh * (1 + lo * P(lo))
-  //     = mh + (mh*lo) * P(lo)
-  return static_cast<float>(fputil::multiply_add(p, dx_sq * mh, c1 * mh));
-}
+using LIBC_MATH_EXP2F_IMPL::exp2f;
 
 } // namespace math
-
 } // namespace LIBC_NAMESPACE_DECL
 
+#undef LIBC_MATH_EXP2F_IMPL
+
 #endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_H
diff --git a/libc/src/__support/math/exp2f_double_eval.h b/libc/src/__support/math/exp2f_double_eval.h
new file mode 100644
index 0000000000000..821e726d012d3
--- /dev/null
+++ b/libc/src/__support/math/exp2f_double_eval.h
@@ -0,0 +1,178 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Double-precision implementation of exp2f.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_DOUBLE_EVAL_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_DOUBLE_EVAL_H
+
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/PolyEval.h"
+#include "src/__support/FPUtil/except_value_utils.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/FPUtil/nearest_integer.h"
+#include "src/__support/FPUtil/rounding_mode.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/macros/properties/cpu_features.h"
+#include "src/__support/math/exp10f_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace math {
+namespace double_eval {
+
+LIBC_INLINE float exp2f(float x) {
+  using FPBits = typename fputil::FPBits<float>;
+  FPBits xbits(x);
+
+  uint32_t x_u = xbits.uintval();
+  uint32_t x_abs = x_u & 0x7fff'ffffU;
+
+  // When |x| >= 128, or x is nan, or |x| <= 2^-5
+  if (LIBC_UNLIKELY(x_abs >= 0x4300'0000U || x_abs <= 0x3d00'0000U)) {
+    // |x| <= 2^-5
+    if (x_abs <= 0x3d00'0000) {
+      // |x| < 2^-25
+      if (LIBC_UNLIKELY(x_abs <= 0x3280'0000U)) {
+        return 1.0f + x;
+      }
+
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+      constexpr uint32_t EXVAL1 = 0x3b42'9d37U;
+      constexpr uint32_t EXVAL2 = 0xbcf3'a937U;
+      constexpr uint32_t EXVAL_MASK = EXVAL1 & EXVAL2;
+
+      // Check exceptional values.
+      if (LIBC_UNLIKELY((x_u & EXVAL_MASK) == EXVAL_MASK)) {
+        if (LIBC_UNLIKELY(x_u == EXVAL1)) { // x = 0x1.853a6ep-9f
+          return fputil::round_result_slightly_down(0x1.00870ap+0f);
+        } else if (LIBC_UNLIKELY(x_u == EXVAL2)) { // x = -0x1.e7526ep-6f
+          return fputil::round_result_slightly_down(0x1.f58d62p-1f);
+        }
+      }
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+      // Minimax polynomial generated by Sollya with:
+      // > P = fpminimax((2^x - 1)/x, 5, [|D...|], [-2^-5, 2^-5]);
+      constexpr double COEFFS[] = {
+          0x1.62e42fefa39f3p-1, 0x1.ebfbdff82c57bp-3,  0x1.c6b08d6f2d7aap-5,
+          0x1.3b2ab6fc92f5dp-7, 0x1.5d897cfe27125p-10, 0x1.43090e61e6af1p-13};
+      double xd = static_cast<double>(x);
+      double xsq = xd * xd;
+      double c0 = fputil::multiply_add(xd, COEFFS[1], COEFFS[0]);
+      double c1 = fputil::multiply_add(xd, COEFFS[3], COEFFS[2]);
+      double c2 = fputil::multiply_add(xd, COEFFS[5], COEFFS[4]);
+      double p = fputil::polyeval(xsq, c0, c1, c2);
+      double r = fputil::multiply_add(p, xd, 1.0);
+      return static_cast<float>(r);
+    }
+
+    // x >= 128
+    if (xbits.is_pos()) {
+      // x is finite
+      if (x_u < 0x7f80'0000U) {
+#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+        int rounding = fputil::quick_get_round();
+        if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
+          return FPBits::max_normal().get_val();
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+
+        fputil::set_errno_if_required(ERANGE);
+        fputil::raise_except_if_required(FE_OVERFLOW);
+      }
+      // x is +inf or nan
+      return x + FPBits::inf().get_val();
+    }
+    // x <= -150
+    if (x_u >= 0xc316'0000U) {
+      // exp(-Inf) = 0
+      if (xbits.is_inf())
+        return 0.0f;
+      // exp(nan) = nan
+      if (xbits.is_nan())
+        return x;
+#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+      if (fputil::fenv_is_round_up())
+        return FPBits::min_subnormal().get_val();
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+      if (x != 0.0f) {
+        fputil::set_errno_if_required(ERANGE);
+        fputil::raise_except_if_required(FE_UNDERFLOW);
+      }
+      return 0.0f;
+    }
+  }
+
+  // For -150 < x < 128, to compute 2^x, we perform the following range
+  // reduction: find hi, mid, lo such that:
+  //   x = hi + mid + lo, in which
+  //     hi is an integer,
+  //     0 <= mid * 2^5 < 32 is an integer
+  //     -2^(-6) <= lo <= 2^-6.
+  // In particular,
+  //   hi + mid = round(x * 2^5) * 2^(-5).
+  // Then,
+  //   2^x = 2^(hi + mid + lo) = 2^hi * 2^mid * 2^lo.
+  // 2^mid is stored in the lookup table of 32 elements.
+  // 2^lo is computed using a degree-5 minimax polynomial
+  // generated by Sollya.
+  // We perform 2^hi * 2^mid by simply add hi to the exponent field
+  // of 2^mid.
+
+  // kf = (hi + mid) * 2^5 = round(x * 2^5)
+  float kf = 0;
+  int k = 0;
+#ifdef LIBC_TARGET_CPU_HAS_NEAREST_INT
+  kf = fputil::nearest_integer(x * 32.0f);
+  k = static_cast<int>(kf);
+#else  // !LIBC_TARGET_CPU_HAS_NEAREST_INT
+  constexpr float HALF[2] = {0.5f, -0.5f};
+  k = static_cast<int>(fputil::multiply_add(x, 32.0f, HALF[x < 0.0f]));
+  kf = static_cast<float>(k);
+#endif // LIBC_TARGET_CPU_HAS_NEAREST_INT
+
+  // dx = lo = x - (hi + mid) = x - kf * 2^(-5)
+  double dx = fputil::multiply_add(-0x1.0p-5f, kf, x);
+
+  // hi = floor(kf * 2^(-4))
+  // exp_hi = shift hi to the exponent field of double precision.
+  int64_t exp_hi =
+      static_cast<int64_t>(static_cast<uint64_t>(k >> ExpBase::MID_BITS)
+                           << fputil::FPBits<double>::FRACTION_LEN);
+  // mh = 2^hi * 2^mid
+  // mh_bits = bit field of mh
+  int64_t mh_bits = ExpBase::EXP_2_MID[k & ExpBase::MID_MASK] + exp_hi;
+  double mh = fputil::FPBits<double>(uint64_t(mh_bits)).get_val();
+
+  // Degree-5 polynomial approximating (2^x - 1)/x generating by Sollya with:
+  // > P = fpminimax((2^x - 1)/x, 5, [|D...|], [-1/32. 1/32]);
+  constexpr double COEFFS[5] = {0x1.62e42fefa39efp-1, 0x1.ebfbdff8131c4p-3,
+                                0x1.c6b08d7061695p-5, 0x1.3b2b1bee74b2ap-7,
+                                0x1.5d88091198529p-10};
+  double dx_sq = dx * dx;
+  double c1 = fputil::multiply_add(dx, COEFFS[0], 1.0);
+  double c2 = fputil::multiply_add(dx, COEFFS[2], COEFFS[1]);
+  double c3 = fputil::multiply_add(dx, COEFFS[4], COEFFS[3]);
+  double p = fputil::multiply_add(dx_sq, c3, c2);
+  // 2^x = 2^(hi + mid + lo)
+  //     = 2^(hi + mid) * 2^lo
+  //     ~ mh * (1 + lo * P(lo))
+  //     = mh + (mh*lo) * P(lo)
+  return static_cast<float>(fputil::multiply_add(p, dx_sq * mh, c1 * mh));
+}
+
+} // namespace double_eval
+} // namespace math
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_DOUBLE_EVAL_H
diff --git a/libc/src/__support/math/exp2f_float_eval.h b/libc/src/__support/math/exp2f_float_eval.h
new file mode 100644
index 0000000000000..8298ae7b18add
--- /dev/null
+++ b/libc/src/__support/math/exp2f_float_eval.h
@@ -0,0 +1,96 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Float-only implementation of exp2f.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_FLOAT_EVAL_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_FLOAT_EVAL_H
+
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/FPUtil/nearest_integer.h"
+#include "src/__support/FPUtil/rounding_mode.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/math/exp2f_float_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace math {
+namespace float_eval {
+
+LIBC_INLINE float exp2f(float x) {
+  using FPBits = typename fputil::FPBits<float>;
+  FPBits xbits(x);
+
+  uint32_t x_u = xbits.uintval();
+  uint32_t x_abs = x_u & 0x7fff'ffffU;
+
+  // When |x| >= 128, or x is nan, or |x| <= 2^-25
+  if (LIBC_UNLIKELY(x_abs >= 0x4300'0000U || x_abs <= 0x3280'0000U)) {
+    // |x| <= 2^-25
+    if (x_abs <= 0x3280'0000U) {
+      return 1.0f + x;
+    }
+
+    // x >= 128
+    if (xbits.is_pos()) {
+      // x is finite
+      if (x_u < 0x7f80'0000U) {
+#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+        int rounding = fputil::quick_get_round();
+        if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
+          return FPBits::max_normal().get_val();
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+
+        fputil::set_errno_if_required(ERANGE);
+        fputil::raise_except_if_required(FE_OVERFLOW);
+      }
+      // x is +inf or nan
+      return x + FPBits::inf().get_val();
+    }
+    // x <= -150
+    if (x_u >= 0xc316'0000U) {
+      // exp(-Inf) = 0
+      if (xbits.is_inf())
+        return 0.0f;
+      // exp(nan) = nan
+      if (xbits.is_nan())
+        return x;
+#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+      if (fputil::fenv_is_round_up())
+        return FPBits::min_subnormal().get_val();
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+      if (x != 0.0f) {
+        fputil::set_errno_if_required(ERANGE);
+        fputil::raise_except_if_required(FE_UNDERFLOW);
+      }
+      return 0.0f;
+    }
+  }
+
+  // Range reduction:
+  //   k = round(x)
+  //   x = k + u, with |u| <= 0.5
+  //   2^x = 2^k * 2^u
+  float kf = fputil::nearest_integer(x);
+  int k = static_cast<int>(kf);
+
+  float u = fputil::multiply_add(kf, -1.0f, x);
+  return exp2f_eval(u, k);
+}
+
+} // namespace float_eval
+} // namespace math
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_FLOAT_EVAL_H
diff --git a/libc/src/__support/math/exp2f_float_utils.h b/libc/src/__support/math/exp2f_float_utils.h
new file mode 100644
index 0000000000000..1c96050bea37f
--- /dev/null
+++ b/libc/src/__support/math/exp2f_float_utils.h
@@ -0,0 +1,107 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Shared utilities and constants for single-precision exponential functions.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_FLOAT_UTILS_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_FLOAT_UTILS_H
+
+#include "src/__support/CPP/bit.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace math {
+namespace float_eval {
+
+// Compute y * 2^m for y in [0.5, 2.0) and m in [-150, 128].
+//
+// We divide into three cases depending on m:
+// 1. -126 <= m <= 127:
+//    2^m is a normal float (exponent field m + 127 in [1, 254]).
+//    We can directly compute y * 2^m with a single multiplication.
+//    The condition is checked using unsigned comparison: (m + 126) <= 253.
+//
+// 2. m > 127 (i.e., m = 128):
+//    2^m cannot be represented as a finite normal float (exponent field
+//    128 + 127 = 255 is inf). Instead, we compute:
+//      y * 2^m = (2 * y) * 2^(m - 1).
+//    Since y < 2.0, 2 * y is exact (simply increments the exponent of y),
+//    and 2^(m - 1) = 2^127 is a normal float.
+//
+// 3. m < -126 (i.e., m in [-150, -127]):
+//    The result is in the subnormal range (or underflows to 0).
+//    To avoid double-rounding errors, we scale in two steps:
+//      y * 2^m = (y * 2^(m + 25)) * 2^-25.
+//    Since m >= -150, m + 25 >= -125, so 2^(m + 25) is a normal float.
+//    The intermediate product (y * 2^(m + 25)) is normal and computed with
+//    full precision. Then the final multiplication by 2^-25 rounds directly
+//    to the target subnormal precision in a single rounding step.
+LIBC_INLINE float scale_exp2f(float y, int m) {
+  // -126 <= m <= 127: 2^m is a normal float.
+  if (LIBC_LIKELY(static_cast<uint32_t>(m + 126) <= 253)) {
+    uint32_t scale_bits = static_cast<uint32_t>(m + 127) << 23;
+    float scale = cpp::bit_cast<float>(scale_bits);
+    return y * scale;
+  }
+
+  // m = 128: 2^m cannot be represented as a normal float.
+  // Compute (2 * y) * 2^(m - 1), where 2 * y is exact and 2^(m - 1) is normal.
+  if (m > 127) {
+    uint32_t scale_bits = static_cast<uint32_t>(m - 1 + 127) << 23;
+    float scale = cpp::bit_cast<float>(scale_bits);
+    return (y * 2.0f) * scale;
+  }
+
+  // Subnormal result: m in [-150, -127].
+  // Compute (y * 2^(m + 25)) * 2^-25 so that the first product is normal and
+  // the second multiplication rounds directly to the subnormal result.
+  uint32_t scale_bits = static_cast<uint32_t>(m + 25 + 127) << 23;
+  float scale = cpp::bit_cast<float>(scale_bits);
+  return (y * scale) * 0x1.0p-25f;
+}
+
+// Degree-6 polynomial approximating 2^u - 1 = u * P(u) on [-0.5, 0.5] using
+// Estrin's scheme and exponent scaling.
+// Evaluates 2^x = 2^m * 2^u.
+// Generated by Sollya with:
+// > display = hexadecimal;
+// > P = fpminimax((2^x - 1)/x, 5, [|SG...|], [-0.5, 0.5]);
+// > dirtyinfnorm(1 + x * P - 2^x, [-0.5, 0.5]);
+//   0x1.68cb...p-28
+// > dirtyinfnorm((1 + x * P - 2^x) / 2^x, [-0.5, 0.5]);
+//   0x1.5109...p-28
+LIBC_INLINE float exp2f_eval(float u, int m) {
+  constexpr float COEFFS[6] = {0x1.62e430p-1f,  0x1.ebfbdep-3f,
+                               0x1.c6af9ep-5f,  0x1.3b2c58p-7f,
+                               0x1.5ef4a2p-10f, 0x1.427918p-13f};
+
+  float u2 = u * u;
+  float u4 = u2 * u2;
+
+  float p0 = fputil::multiply_add(u, COEFFS[1], COEFFS[0]);
+  float p1 = fputil::multiply_add(u, COEFFS[3], COEFFS[2]);
+  float p2 = fputil::multiply_add(u, COEFFS[5], COEFFS[4]);
+
+  float q0 = fputil::multiply_add(u2, p1, p0);
+  float p = fputil::multiply_add(u4, p2, q0);
+
+  float y = fputil::multiply_add(u, p, 1.0f);
+
+  return scale_exp2f(y, m);
+}
+
+} // namespace float_eval
+} // namespace math
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_FLOAT_UTILS_H
diff --git a/libc/src/__support/math/expf.h b/libc/src/__support/math/expf.h
index f2c2c5319d221..a64b323e08b2d 100644
--- a/libc/src/__support/math/expf.h
+++ b/libc/src/__support/math/expf.h
@@ -1,120 +1,52 @@
-//===-- Implementation header for expf --------------------------*- C++ -*-===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for expf.
+///
+//===----------------------------------------------------------------------===//
 
 #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_H
 #define LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_H
 
-#include "exp_float_constants.h" // Lookup tables EXP_M1 and EXP_M2.
-#include "src/__support/FPUtil/FEnvImpl.h"
-#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/FPUtil/PolyEval.h"
-#include "src/__support/FPUtil/multiply_add.h"
-#include "src/__support/FPUtil/nearest_integer.h"
-#include "src/__support/FPUtil/rounding_mode.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
-#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
+#include "src/__support/macros/optimization.h"
+#include "src/__support/macros/properties/cpu_features.h"
 
-namespace LIBC_NAMESPACE_DECL {
-
-namespace math {
+#if defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) &&                               \
+    (defined(LIBC_MATH_HAS_SMALL_TABLES) ||                                    \
+     defined(LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT))
 
-LIBC_INLINE float expf(float x) {
-  using FPBits = typename fputil::FPBits<float>;
-  FPBits xbits(x);
+#include "src/__support/math/expf_float_eval.h"
+#define LIBC_MATH_EXPF_IMPL float_eval
 
-  uint32_t x_u = xbits.uintval();
-  uint32_t x_abs = x_u & 0x7fff'ffffU;
+#elif !defined(LIBC_TARGET_CPU_HAS_FPU_DOUBLE) &&                              \
+    defined(LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY) &&                        \
+    defined(LIBC_MATH_HAS_NO_EXCEPT) && defined(LIBC_MATH_HAS_NO_ERRNO)
 
-#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-  // Exceptional values
-  if (LIBC_UNLIKELY(x_u == 0xc236'bd8cU)) { // x = -0x1.6d7b18p+5f
-    return 0x1.108a58p-66f - x * 0x1.0p-95f;
-  }
-#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+#include "src/__support/math/expf_integer_eval.h"
+#define LIBC_MATH_EXPF_IMPL integer_eval
 
-  // When |x| >= 89, |x| < 2^-25, or x is nan
-  if (LIBC_UNLIKELY(x_abs >= 0x42b2'0000U || x_abs <= 0x3280'0000U)) {
-    // |x| < 2^-25
-    if (xbits.get_biased_exponent() <= 101) {
-      return 1.0f + x;
-    }
+#else
+#include "src/__support/math/expf_double_eval.h"
+#define LIBC_MATH_EXPF_IMPL double_eval
 
-    // When x < log(2^-150) or nan
-    if (xbits.uintval() >= 0xc2cf'f1b5U) {
-      // exp(-Inf) = 0
-      if (xbits.is_inf())
-        return 0.0f;
-      // exp(nan) = nan
-      if (xbits.is_nan())
-        return x;
-#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
-      if (fputil::fenv_is_round_up())
-        return FPBits::min_subnormal().get_val();
-#endif
-      fputil::set_errno_if_required(ERANGE);
-      fputil::raise_except_if_required(FE_UNDERFLOW);
-      return 0.0f;
-    }
-    // x >= 89 or nan
-    if (xbits.is_pos() && (xbits.uintval() >= 0x42b2'0000)) {
-      // x is finite
-      if (xbits.uintval() < 0x7f80'0000U) {
-#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
-        int rounding = fputil::quick_get_round();
-        if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
-          return FPBits::max_normal().get_val();
-#endif
+#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
 
-        fputil::set_errno_if_required(ERANGE);
-        fputil::raise_except_if_required(FE_OVERFLOW);
-      }
-      // x is +inf or nan
-      return x + FPBits::inf().get_val();
-    }
-  }
-  // For -104 < x < 89, to compute exp(x), we perform the following range
-  // reduction: find hi, mid, lo such that:
-  //   x = hi + mid + lo, in which
-  //     hi is an integer,
-  //     mid * 2^7 is an integer
-  //     -2^(-8) <= lo < 2^-8.
-  // In particular,
-  //   hi + mid = round(x * 2^7) * 2^(-7).
-  // Then,
-  //   exp(x) = exp(hi + mid + lo) = exp(hi) * exp(mid) * exp(lo).
-  // We store exp(hi) and exp(mid) in the lookup tables EXP_M1 and EXP_M2
-  // respectively.  exp(lo) is computed using a degree-4 minimax polynomial
-  // generated by Sollya.
+namespace LIBC_NAMESPACE_DECL {
+namespace math {
 
-  // x_hi = (hi + mid) * 2^7 = round(x * 2^7).
-  float kf = fputil::nearest_integer(x * 0x1.0p7f);
-  // Subtract (hi + mid) from x to get lo.
-  double xd = static_cast<double>(fputil::multiply_add(kf, -0x1.0p-7f, x));
-  int x_hi = static_cast<int>(kf);
-  x_hi += 104 << 7;
-  // hi = x_hi >> 7
-  double exp_hi = EXP_M1[x_hi >> 7];
-  // mid * 2^7 = x_hi & 0x0000'007fU;
-  double exp_mid = EXP_M2[x_hi & 0x7f];
-  // Degree-4 minimax polynomial generated by Sollya with the following
-  // commands:
-  //   > display = hexadecimal;
-  //   > Q = fpminimax(expm1(x)/x, 3, [|D...|], [-2^-8, 2^-8]);
-  //   > Q;
-  double exp_lo =
-      fputil::polyeval(xd, 0x1p0, 0x1.ffffffffff777p-1, 0x1.000000000071cp-1,
-                       0x1.555566668e5e7p-3, 0x1.55555555ef243p-5);
-  return static_cast<float>(exp_hi * exp_mid * exp_lo);
-}
+using LIBC_MATH_EXPF_IMPL::expf;
 
 } // namespace math
-
 } // namespace LIBC_NAMESPACE_DECL
 
+#undef LIBC_MATH_EXPF_IMPL
+
 #endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_H
diff --git a/libc/src/__support/math/expf_double_eval.h b/libc/src/__support/math/expf_double_eval.h
new file mode 100644
index 0000000000000..8a990bd67c265
--- /dev/null
+++ b/libc/src/__support/math/expf_double_eval.h
@@ -0,0 +1,125 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Double-precision implementation of expf.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_DOUBLE_EVAL_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_DOUBLE_EVAL_H
+
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/PolyEval.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/FPUtil/nearest_integer.h"
+#include "src/__support/FPUtil/rounding_mode.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/math/exp_float_constants.h" // Lookup tables EXP_M1 and EXP_M2.
+
+namespace LIBC_NAMESPACE_DECL {
+namespace math {
+namespace double_eval {
+
+LIBC_INLINE float expf(float x) {
+  using FPBits = typename fputil::FPBits<float>;
+  FPBits xbits(x);
+
+  uint32_t x_u = xbits.uintval();
+  uint32_t x_abs = x_u & 0x7fff'ffffU;
+
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+  // Exceptional values
+  if (LIBC_UNLIKELY(x_u == 0xc236'bd8cU)) { // x = -0x1.6d7b18p+5f
+    return 0x1.108a58p-66f - x * 0x1.0p-95f;
+  }
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+  // When |x| >= 89, |x| < 2^-25, or x is nan
+  if (LIBC_UNLIKELY(x_abs >= 0x42b2'0000U || x_abs <= 0x3280'0000U)) {
+    // |x| < 2^-25
+    if (xbits.get_biased_exponent() <= 101) {
+      return 1.0f + x;
+    }
+
+    // When x < log(2^-150) or nan
+    if (xbits.uintval() >= 0xc2cf'f1b5U) {
+      // exp(-Inf) = 0
+      if (xbits.is_inf())
+        return 0.0f;
+      // exp(nan) = nan
+      if (xbits.is_nan())
+        return x;
+#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+      if (fputil::fenv_is_round_up())
+        return FPBits::min_subnormal().get_val();
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+      fputil::set_errno_if_required(ERANGE);
+      fputil::raise_except_if_required(FE_UNDERFLOW);
+      return 0.0f;
+    }
+    // x >= 89 or nan
+    if (xbits.is_pos() && (xbits.uintval() >= 0x42b2'0000)) {
+      // x is finite
+      if (xbits.uintval() < 0x7f80'0000U) {
+#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+        int rounding = fputil::quick_get_round();
+        if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
+          return FPBits::max_normal().get_val();
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+
+        fputil::set_errno_if_required(ERANGE);
+        fputil::raise_except_if_required(FE_OVERFLOW);
+      }
+      // x is +inf or nan
+      return x + FPBits::inf().get_val();
+    }
+  }
+  // For -104 < x < 89, to compute exp(x), we perform the following range
+  // reduction: find hi, mid, lo such that:
+  //   x = hi + mid + lo, in which
+  //     hi is an integer,
+  //     mid * 2^7 is an integer
+  //     -2^(-8) <= lo < 2^-8.
+  // In particular,
+  //   hi + mid = round(x * 2^7) * 2^(-7).
+  // Then,
+  //   exp(x) = exp(hi + mid + lo) = exp(hi) * exp(mid) * exp(lo).
+  // We store exp(hi) and exp(mid) in the lookup tables EXP_M1 and EXP_M2
+  // respectively.  exp(lo) is computed using a degree-4 minimax polynomial
+  // generated by Sollya.
+
+  // x_hi = (hi + mid) * 2^7 = round(x * 2^7).
+  float kf = fputil::nearest_integer(x * 0x1.0p7f);
+  // Subtract (hi + mid) from x to get lo.
+  double xd = static_cast<double>(fputil::multiply_add(kf, -0x1.0p-7f, x));
+  int x_hi = static_cast<int>(kf);
+  x_hi += 104 << 7;
+  // hi = x_hi >> 7
+  double exp_hi = EXP_M1[x_hi >> 7];
+  // mid * 2^7 = x_hi & 0x0000'007fU;
+  double exp_mid = EXP_M2[x_hi & 0x7f];
+  // Degree-4 minimax polynomial generated by Sollya with the following
+  // commands:
+  //   > display = hexadecimal;
+  //   > Q = fpminimax(expm1(x)/x, 3, [|D...|], [-2^-8, 2^-8]);
+  //   > Q;
+  double exp_lo =
+      fputil::polyeval(xd, 0x1p0, 0x1.ffffffffff777p-1, 0x1.000000000071cp-1,
+                       0x1.555566668e5e7p-3, 0x1.55555555ef243p-5);
+  return static_cast<float>(exp_hi * exp_mid * exp_lo);
+}
+
+} // namespace double_eval
+} // namespace math
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_DOUBLE_EVAL_H
diff --git a/libc/src/__support/math/expf_float_eval.h b/libc/src/__support/math/expf_float_eval.h
new file mode 100644
index 0000000000000..5561e9d8e06f8
--- /dev/null
+++ b/libc/src/__support/math/expf_float_eval.h
@@ -0,0 +1,126 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Float-only implementation of expf.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_FLOAT_EVAL_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_FLOAT_EVAL_H
+
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/double_double.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/FPUtil/nearest_integer.h"
+#include "src/__support/FPUtil/rounding_mode.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/macros/properties/cpu_features.h"
+#include "src/__support/math/exp2f_float_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace math {
+namespace float_eval {
+
+LIBC_INLINE float expf(float x) {
+  using FPBits = typename fputil::FPBits<float>;
+  FPBits xbits(x);
+
+  uint32_t x_u = xbits.uintval();
+  uint32_t x_abs = x_u & 0x7fff'ffffU;
+
+  // When |x| >= 89, |x| < 2^-25, or x is nan
+  if (LIBC_UNLIKELY(x_abs >= 0x42b2'0000U || x_abs <= 0x3280'0000U)) {
+    // |x| < 2^-25
+    if (xbits.get_biased_exponent() <= 101) {
+      return 1.0f + x;
+    }
+
+    // When x < log(2^-150) or nan
+    if (xbits.uintval() >= 0xc2cf'f1b5U) {
+      // exp(-Inf) = 0
+      if (xbits.is_inf())
+        return 0.0f;
+      // exp(nan) = nan
+      if (xbits.is_nan())
+        return x;
+#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+      if (fputil::fenv_is_round_up())
+        return FPBits::min_subnormal().get_val();
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+      fputil::set_errno_if_required(ERANGE);
+      fputil::raise_except_if_required(FE_UNDERFLOW);
+      return 0.0f;
+    }
+    // x >= 89 or nan
+    if (xbits.is_pos() && (xbits.uintval() >= 0x42b2'0000)) {
+      // x is finite
+      if (xbits.uintval() < 0x7f80'0000U) {
+#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+        int rounding = fputil::quick_get_round();
+        if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
+          return FPBits::max_normal().get_val();
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+
+        fputil::set_errno_if_required(ERANGE);
+        fputil::raise_except_if_required(FE_OVERFLOW);
+      }
+      // x is +inf or nan
+      return x + FPBits::inf().get_val();
+    }
+  }
+
+  // Range reduction:
+  //   k = round(x * log2(e))
+  //   x * log2(e) = k + u, with |u| <= 0.5
+  //   e^x = 2^(k + u) = 2^k * 2^u
+#if defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT)
+  // Constants generated by Sollya with:
+  // > display = hexadecimal;
+  // > hi = round(log2(exp(1)), SG, RN);
+  // > lo = round(log2(exp(1)) - hi, SG, RN);
+  constexpr fputil::FloatFloat LOG2_E = {/*lo=*/0x1.4ae0cp-26f,
+                                         /*hi=*/0x1.715476p+0f};
+
+  float kf = fputil::nearest_integer(x * LOG2_E.hi);
+  int k = static_cast<int>(kf);
+
+  float u_hi = fputil::multiply_add(x, LOG2_E.hi, -kf);
+  float u = fputil::multiply_add(x, LOG2_E.lo, u_hi);
+#else  // !LIBC_TARGET_CPU_HAS_FMA_FLOAT
+  // Cody-Waite reduction for non-FMA targets:
+  // Constants generated by Sollya with:
+  // > display = hexadecimal;
+  // > LOG2_E = round(log2(exp(1)), SG, RN);
+  // > LOG_2_HI = round(log(2), 12, RN);
+  // > LOG_2_LO = round(log(2) - LOG_2_HI, SG, RN);
+  constexpr float LOG2_E = 0x1.715476p+0f;
+  constexpr float LOG_2_HI = 0x1.62ep-1f;
+  constexpr float LOG_2_LO = 0x1.0bfbe8p-15f;
+
+  float kf = fputil::nearest_integer(x * LOG2_E);
+  int k = static_cast<int>(kf);
+
+  float v_hi = fputil::multiply_add(-kf, LOG_2_HI, x);
+  float v = fputil::multiply_add(-kf, LOG_2_LO, v_hi);
+
+  // Convert reduced argument to base-2: u = v * log2(e)
+  float u = v * LOG2_E;
+#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT
+
+  return exp2f_eval(u, k);
+}
+
+} // namespace float_eval
+} // namespace math
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_FLOAT_EVAL_H
diff --git a/libc/src/__support/math/expf_integer_eval.h b/libc/src/__support/math/expf_integer_eval.h
index e48b459f880b1..c072abaf96955 100644
--- a/libc/src/__support/math/expf_integer_eval.h
+++ b/libc/src/__support/math/expf_integer_eval.h
@@ -15,6 +15,7 @@
 #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_INTEGER_EVAL_H
 #define LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_INTEGER_EVAL_H
 
+#include "hdr/fenv_macros.h"
 #include "src/__support/CPP/bit.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/FPUtil/PolyEval.h"
@@ -74,7 +75,7 @@ LIBC_INLINE float expf(float x, [[maybe_unused]] int rounding) {
     if (x_val_abs <= 0x3300'0000U) {
 #ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
       return 1.0f;
-#else
+#else  // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
       if (x_val_abs == 0)
         return 1.0f;
 
@@ -113,7 +114,7 @@ LIBC_INLINE float expf(float x, [[maybe_unused]] int rounding) {
         return FPBits::max_normal().get_val();
 
       return FPBits::inf().get_val();
-#else
+#else  // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
       return FPBits::inf().get_val();
 #endif // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
     }
@@ -248,7 +249,7 @@ LIBC_INLINE float expf(float x, [[maybe_unused]] int rounding) {
   result += e_y_unbiased;
 
   return cpp::bit_cast<float>(result);
-#else
+#else  // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
   if (rounding == FE_TONEAREST) {
     uint32_t result =
         (static_cast<uint32_t>(p.val[0] >> shift_length) + (leading_one + 1));
@@ -270,7 +271,7 @@ LIBC_INLINE float expf(float x, [[maybe_unused]] int rounding) {
   result += e_y_unbiased;
 
   return cpp::bit_cast<float>(result);
-#endif // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
 }
 
 } // namespace static_rounding
@@ -279,6 +280,16 @@ LIBC_INLINE float expf(float x, [[maybe_unused]] int rounding) {
 
 } // namespace shared
 
+namespace math {
+namespace integer_eval {
+
+LIBC_INLINE float expf(float x) {
+  return shared::math::static_rounding::expf(x, FE_TONEAREST);
+}
+
+} // namespace integer_eval
+} // namespace math
+
 } // namespace LIBC_NAMESPACE_DECL
 
 #endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_INTEGER_EVAL_H
diff --git a/libc/src/math/generic/expf.cpp b/libc/src/math/generic/expf.cpp
index 1ec621b22677f..83324cb51e7ca 100644
--- a/libc/src/math/generic/expf.cpp
+++ b/libc/src/math/generic/expf.cpp
@@ -7,19 +7,11 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/math/expf.h"
-#include "shared/math/static_rounding/expf.h"
+#include "src/__support/common.h"
 #include "src/__support/math/expf.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(float, expf, (float x)) {
-#if !defined(LIBC_TARGET_CPU_HAS_FPU_DOUBLE) &&                                \
-    defined(LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY) &&                        \
-    defined(LIBC_MATH_HAS_NO_EXCEPT) && defined(LIBC_MATH_HAS_NO_ERRNO)
-  return shared::math::static_rounding::expf(x, FE_TONEAREST);
-#else
-  return math::expf(x);
-#endif
-}
+LLVM_LIBC_FUNCTION(float, expf, (float x)) { return math::expf(x); }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 8f1a543de0a5e..1fd0772aa5031 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -1357,22 +1357,16 @@ add_fp_unittest(
   SRCS
     expf_test.cpp
   DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
     libc.src.errno.errno
     libc.src.math.expf
+    libc.src.__support.math.expf_double_eval
+    libc.src.__support.math.expf_float_eval
+    libc.src.__support.math.expf_integer_eval
     libc.src.__support.FPUtil.fp_bits
 )
 
-add_fp_unittest(
-  expf_static_rounding_test
-  NEED_MPFR
-  SUITE
-    libc-math-unittests
-  SRCS
-    expf_static_rounding_test.cpp
-  DEPENDS
-    libc.src.errno.errno
-    libc.src.__support.FPUtil.fp_bits
-)
 
 add_fp_unittest(
   expf16_test
@@ -1417,8 +1411,12 @@ add_fp_unittest(
   SRCS
     exp2f_test.cpp
   DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
     libc.src.errno.errno
     libc.src.math.exp2f
+    libc.src.__support.math.exp2f_double_eval
+    libc.src.__support.math.exp2f_float_eval
     libc.src.__support.FPUtil.fp_bits
 )
 
@@ -1478,8 +1476,12 @@ add_fp_unittest(
   SRCS
     exp10f_test.cpp
   DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
     libc.src.errno.errno
     libc.src.math.exp10f
+    libc.src.__support.math.exp10f_double_eval
+    libc.src.__support.math.exp10f_float_eval
     libc.src.__support.FPUtil.fp_bits
 )
 
diff --git a/libc/test/src/math/exhaustive/CMakeLists.txt b/libc/test/src/math/exhaustive/CMakeLists.txt
index 3d30a96922f69..2d42bee4c6540 100644
--- a/libc/test/src/math/exhaustive/CMakeLists.txt
+++ b/libc/test/src/math/exhaustive/CMakeLists.txt
@@ -263,22 +263,10 @@ add_fp_unittest(
     expf_test.cpp
   DEPENDS
     .exhaustive_test
-    libc.src.math.expf
-    libc.src.__support.FPUtil.fp_bits
-  LINK_LIBRARIES
-    -lpthread
-)
-
-add_fp_unittest(
-  expf_static_rounding_test
-  NO_RUN_POSTBUILD
-  SUITE
-    libc_math_exhaustive_tests
-  SRCS
-    expf_static_rounding_test.cpp
-  DEPENDS
     .exhaustive_test_static_rounding
-    libc.src.__support.math.expf
+    libc.src.math.expf
+    libc.src.__support.math.expf_double_eval
+    libc.src.__support.math.expf_float_eval
     libc.src.__support.math.expf_integer_eval
     libc.src.__support.FPUtil.fp_bits
   LINK_LIBRARIES
@@ -296,6 +284,7 @@ add_fp_unittest(
   DEPENDS
     .exhaustive_test
     libc.src.math.exp2f
+    libc.src.__support.math.exp2f_float_eval
     libc.src.__support.FPUtil.fp_bits
   LINK_LIBRARIES
     -lpthread
@@ -327,6 +316,7 @@ add_fp_unittest(
   DEPENDS
     .exhaustive_test
     libc.src.math.exp10f
+    libc.src.__support.math.exp10f_float_eval
     libc.src.__support.FPUtil.fp_bits
   LINK_LIBRARIES
     -lpthread
@@ -720,6 +710,7 @@ add_fp_unittest(
     libc.src.__support.math.atanf
 )
 
+
 add_fp_unittest(
   asinf_test
   NO_RUN_POSTBUILD
diff --git a/libc/test/src/math/exhaustive/exhaustive_test.h b/libc/test/src/math/exhaustive/exhaustive_test.h
index 9bf0c407219f1..85c0e07e3417f 100644
--- a/libc/test/src/math/exhaustive/exhaustive_test.h
+++ b/libc/test/src/math/exhaustive/exhaustive_test.h
@@ -11,6 +11,9 @@
 ///
 //===----------------------------------------------------------------------===//
 
+#ifndef LLVM_LIBC_TEST_SRC_MATH_EXHAUSTIVE_EXHAUSTIVE_TEST_H
+#define LLVM_LIBC_TEST_SRC_MATH_EXHAUSTIVE_EXHAUSTIVE_TEST_H
+
 #include "src/__support/CPP/type_traits.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/macros/properties/types.h"
@@ -74,6 +77,62 @@ struct UnaryOpChecker : public virtual LIBC_NAMESPACE::testing::Test {
   }
 };
 
+template <typename OutType, typename InType,
+          UnaryOp<OutType, InType> BaselineFunc, UnaryOp<OutType, InType> Func,
+          unsigned Tolerance = 0>
+struct UnaryOpAgainstBaselineChecker
+    : public virtual LIBC_NAMESPACE::testing::Test {
+  using FloatType = InType;
+  using FPBits = LIBC_NAMESPACE::fputil::FPBits<FloatType>;
+  using StorageType = typename FPBits::StorageType;
+
+  // Check in a range, return the number of failures.
+  uint64_t check(StorageType start, StorageType stop,
+                 mpfr::RoundingMode rounding) {
+    mpfr::ForceRoundingMode r(rounding);
+    if (!r.success)
+      return (stop > start);
+    StorageType bits = start;
+    uint64_t failed = 0;
+    do {
+      FPBits xbits(bits);
+      FloatType x = xbits.get_val();
+      OutType result = Func(x);
+      OutType expected = BaselineFunc(x);
+      using OutFPBits = LIBC_NAMESPACE::fputil::FPBits<OutType>;
+      using OutStorageType = typename OutFPBits::StorageType;
+      OutFPBits result_bits(result);
+      OutFPBits expected_bits(expected);
+
+      bool correct = false;
+      if (expected_bits.is_nan()) {
+        correct = result_bits.is_nan();
+      } else if (result_bits.is_nan()) {
+        correct = false;
+      } else if (Tolerance == 0) {
+        correct = (result_bits.uintval() == expected_bits.uintval());
+      } else {
+        OutStorageType diff = 0;
+        if (expected_bits.sign() == result_bits.sign()) {
+          OutStorageType u1 = expected_bits.uintval();
+          OutStorageType u2 = result_bits.uintval();
+          diff = (u1 > u2) ? (u1 - u2) : (u2 - u1);
+        } else {
+          diff = (expected_bits.uintval() & OutFPBits::EXP_SIG_MASK) +
+                 (result_bits.uintval() & OutFPBits::EXP_SIG_MASK);
+        }
+        correct = (diff <= Tolerance);
+      }
+      failed += (!correct);
+      // Uncomment to print out failed values.
+      if (!correct) {
+        EXPECT_FP_EQ(expected, result);
+      }
+    } while (bits++ < stop);
+    return failed;
+  }
+};
+
 template <typename OutType, typename InType = OutType>
 using BinaryOp = OutType(InType, InType);
 
@@ -272,6 +331,12 @@ template <typename FloatType, mpfr::Operation Op, UnaryOp<FloatType> Func,
 using LlvmLibcUnaryOpExhaustiveMathTest = LlvmLibcExhaustiveMathTest<
     UnaryOpChecker<FloatType, FloatType, Op, Func, Tolerance>>;
 
+template <typename FloatType, UnaryOp<FloatType> BaselineFunc,
+          UnaryOp<FloatType> Func, unsigned Tolerance = 0>
+using LlvmLibcUnaryOpAgainstBaselineExhaustiveMathTest =
+    LlvmLibcExhaustiveMathTest<UnaryOpAgainstBaselineChecker<
+        FloatType, FloatType, BaselineFunc, Func, Tolerance>>;
+
 template <typename OutType, typename InType, mpfr::Operation Op,
           UnaryOp<OutType, InType> Func>
 using LlvmLibcUnaryNarrowingOpExhaustiveMathTest =
@@ -281,3 +346,5 @@ template <typename FloatType, mpfr::Operation Op, BinaryOp<FloatType> Func>
 using LlvmLibcBinaryOpExhaustiveMathTest =
     LlvmLibcExhaustiveMathTest<BinaryOpChecker<FloatType, FloatType, Op, Func>,
                                1 << 2>;
+
+#endif // LLVM_LIBC_TEST_SRC_MATH_EXHAUSTIVE_EXHAUSTIVE_TEST_H
diff --git a/libc/test/src/math/exhaustive/exhaustive_test_static_rounding.h b/libc/test/src/math/exhaustive/exhaustive_test_static_rounding.h
index d268a6fdfd806..5b135c822e667 100644
--- a/libc/test/src/math/exhaustive/exhaustive_test_static_rounding.h
+++ b/libc/test/src/math/exhaustive/exhaustive_test_static_rounding.h
@@ -12,10 +12,12 @@
 ///
 //===----------------------------------------------------------------------===//
 
+#ifndef LLVM_LIBC_TEST_SRC_MATH_EXHAUSTIVE_EXHAUSTIVE_TEST_STATIC_ROUNDING_H
+#define LLVM_LIBC_TEST_SRC_MATH_EXHAUSTIVE_EXHAUSTIVE_TEST_STATIC_ROUNDING_H
+
 // This file is modeled after exhaustive_test.h, modified for testing statically
 // rounded math functions.
 
-#include "exhaustive_test.h"
 #include "src/__support/CPP/type_traits.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/macros/properties/types.h"
@@ -23,6 +25,7 @@
 #include "test/UnitTest/RoundingModeUtils.h"
 #include "test/UnitTest/Test.h"
 #include "test/UnitTest/TestLogger.h"
+#include "test/src/math/exhaustive/exhaustive_test.h"
 
 #include <atomic>
 #include <iostream>
@@ -234,3 +237,5 @@ template <typename FloatType, UnaryOp<FloatType> BaselineFunc,
 using LlvmLibcStaticallyRoundedUnaryOpExhaustiveMathTest =
     LlvmLibcExhaustiveStaticallyRoundedMathTest<StaticallyRoundedUnaryOpChecker<
         FloatType, FloatType, BaselineFunc, Func>>;
+
+#endif // LLVM_LIBC_TEST_SRC_MATH_EXHAUSTIVE_EXHAUSTIVE_TEST_STATIC_ROUNDING_H
diff --git a/libc/test/src/math/exhaustive/exp10f_test.cpp b/libc/test/src/math/exhaustive/exp10f_test.cpp
index eb1e9164a6cd3..150e3d0812b65 100644
--- a/libc/test/src/math/exhaustive/exp10f_test.cpp
+++ b/libc/test/src/math/exhaustive/exp10f_test.cpp
@@ -6,28 +6,47 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "exhaustive_test.h"
+#include "src/__support/math/exp10f_float_eval.h"
 #include "src/math/exp10f.h"
+#include "test/src/math/exhaustive/exhaustive_test.h"
 #include "utils/MPFRWrapper/MPFRUtils.h"
 
 namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
 
-using LlvmLibcExp10fExhaustiveTest =
-    LlvmLibcUnaryOpExhaustiveMathTest<float, mpfr::Operation::Exp10,
-                                      LIBC_NAMESPACE::exp10f>;
-
 // Range: [0, Inf];
 static constexpr uint32_t POS_START = 0x0000'0000U;
 static constexpr uint32_t POS_STOP = 0x7f80'0000U;
 
+// Range: [-Inf, 0];
+static constexpr uint32_t NEG_START = 0x8000'0000U;
+static constexpr uint32_t NEG_STOP = 0xff80'0000U;
+
+using LlvmLibcExp10fExhaustiveTest =
+    LlvmLibcUnaryOpExhaustiveMathTest<float, mpfr::Operation::Exp10,
+                                      LIBC_NAMESPACE::exp10f>;
+
 TEST_F(LlvmLibcExp10fExhaustiveTest, PositiveRange) {
   test_full_range_all_roundings(POS_START, POS_STOP);
 }
 
-// Range: [-Inf, 0];
-static constexpr uint32_t NEG_START = 0xb000'0000U;
-static constexpr uint32_t NEG_STOP = 0xff80'0000U;
-
 TEST_F(LlvmLibcExp10fExhaustiveTest, NegativeRange) {
   test_full_range_all_roundings(NEG_START, NEG_STOP);
 }
+
+// Float-eval implementation: tested against the correctly rounded double
+// precision version for round-to-nearest with 1 ULP bound.
+static float exp10f_float_eval(float x) {
+  return LIBC_NAMESPACE::math::float_eval::exp10f(x);
+}
+
+using LlvmLibcExp10fFloatExhaustiveTest =
+    LlvmLibcUnaryOpAgainstBaselineExhaustiveMathTest<
+        float, LIBC_NAMESPACE::exp10f, exp10f_float_eval, 1>;
+
+TEST_F(LlvmLibcExp10fFloatExhaustiveTest, PositiveRange) {
+  test_full_range(mpfr::RoundingMode::Nearest, POS_START, POS_STOP);
+}
+
+TEST_F(LlvmLibcExp10fFloatExhaustiveTest, NegativeRange) {
+  test_full_range(mpfr::RoundingMode::Nearest, NEG_START, NEG_STOP);
+}
diff --git a/libc/test/src/math/exhaustive/exp2f_test.cpp b/libc/test/src/math/exhaustive/exp2f_test.cpp
index fcf2a4c0c0e26..33f94adb48455 100644
--- a/libc/test/src/math/exhaustive/exp2f_test.cpp
+++ b/libc/test/src/math/exhaustive/exp2f_test.cpp
@@ -6,28 +6,47 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "exhaustive_test.h"
+#include "src/__support/math/exp2f_float_eval.h"
 #include "src/math/exp2f.h"
+#include "test/src/math/exhaustive/exhaustive_test.h"
 #include "utils/MPFRWrapper/MPFRUtils.h"
 
 namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
 
-using LlvmLibcExp2fExhaustiveTest =
-    LlvmLibcUnaryOpExhaustiveMathTest<float, mpfr::Operation::Exp2,
-                                      LIBC_NAMESPACE::exp2f>;
-
 // Range: [0, Inf];
 static constexpr uint32_t POS_START = 0x0000'0000U;
 static constexpr uint32_t POS_STOP = 0x7f80'0000U;
 
+// Range: [-Inf, 0];
+static constexpr uint32_t NEG_START = 0x8000'0000U;
+static constexpr uint32_t NEG_STOP = 0xff80'0000U;
+
+using LlvmLibcExp2fExhaustiveTest =
+    LlvmLibcUnaryOpExhaustiveMathTest<float, mpfr::Operation::Exp2,
+                                      LIBC_NAMESPACE::exp2f>;
+
 TEST_F(LlvmLibcExp2fExhaustiveTest, PositiveRange) {
   test_full_range_all_roundings(POS_START, POS_STOP);
 }
 
-// Range: [-Inf, 0];
-static constexpr uint32_t NEG_START = 0xb000'0000U;
-static constexpr uint32_t NEG_STOP = 0xff80'0000U;
-
 TEST_F(LlvmLibcExp2fExhaustiveTest, NegativeRange) {
   test_full_range_all_roundings(NEG_START, NEG_STOP);
 }
+
+// Float-eval implementation: tested against the correctly rounded double
+// precision version for round-to-nearest with 1 ULP bound.
+static float exp2f_float_eval(float x) {
+  return LIBC_NAMESPACE::math::float_eval::exp2f(x);
+}
+
+using LlvmLibcExp2fFloatExhaustiveTest =
+    LlvmLibcUnaryOpAgainstBaselineExhaustiveMathTest<
+        float, LIBC_NAMESPACE::exp2f, exp2f_float_eval, 1>;
+
+TEST_F(LlvmLibcExp2fFloatExhaustiveTest, PositiveRange) {
+  test_full_range(mpfr::RoundingMode::Nearest, POS_START, POS_STOP);
+}
+
+TEST_F(LlvmLibcExp2fFloatExhaustiveTest, NegativeRange) {
+  test_full_range(mpfr::RoundingMode::Nearest, NEG_START, NEG_STOP);
+}
diff --git a/libc/test/src/math/exhaustive/expf_static_rounding_test.cpp b/libc/test/src/math/exhaustive/expf_static_rounding_test.cpp
deleted file mode 100644
index 1ab2884a6b29e..0000000000000
--- a/libc/test/src/math/exhaustive/expf_static_rounding_test.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// This file contains the exhaustive tests for statically-rounded
-/// implementation of static_rounding::expf(x)
-///
-//===----------------------------------------------------------------------===//
-
-#include "exhaustive_test_static_rounding.h"
-#include "src/__support/math/expf.h"
-#include "src/__support/math/expf_integer_eval.h"
-
-using LlvmLibcStaticallyRoundedExpfExhaustiveTest =
-    LlvmLibcStaticallyRoundedUnaryOpExhaustiveMathTest<
-        float, LIBC_NAMESPACE::math::expf,
-        LIBC_NAMESPACE::shared::math::static_rounding::expf>;
-
-// Range: [0, Inf];
-static constexpr uint32_t POS_START = 0x0000'0000U;
-static constexpr uint32_t POS_STOP = 0x7f80'0000U;
-
-TEST_F(LlvmLibcStaticallyRoundedExpfExhaustiveTest, PositiveRange) {
-  test_full_range_all_roundings(POS_START, POS_STOP);
-}
-
-// Range: [-Inf, 0];
-static constexpr uint32_t NEG_START = 0xb000'0000U;
-static constexpr uint32_t NEG_STOP = 0xff80'0000U;
-
-TEST_F(LlvmLibcStaticallyRoundedExpfExhaustiveTest, NegativeRange) {
-  test_full_range_all_roundings(NEG_START, NEG_STOP);
-}
diff --git a/libc/test/src/math/exhaustive/expf_test.cpp b/libc/test/src/math/exhaustive/expf_test.cpp
index 90285a1036d8e..27aafd7d9ce7a 100644
--- a/libc/test/src/math/exhaustive/expf_test.cpp
+++ b/libc/test/src/math/exhaustive/expf_test.cpp
@@ -6,28 +6,65 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "exhaustive_test.h"
+#include "src/__support/math/expf_double_eval.h"
+#include "src/__support/math/expf_float_eval.h"
+#include "src/__support/math/expf_integer_eval.h"
 #include "src/math/expf.h"
+#include "test/src/math/exhaustive/exhaustive_test.h"
+#include "test/src/math/exhaustive/exhaustive_test_static_rounding.h"
 #include "utils/MPFRWrapper/MPFRUtils.h"
 
 namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
 
-using LlvmLibcExpfExhaustiveTest =
-    LlvmLibcUnaryOpExhaustiveMathTest<float, mpfr::Operation::Exp,
-                                      LIBC_NAMESPACE::expf>;
-
 // Range: [0, Inf];
 static constexpr uint32_t POS_START = 0x0000'0000U;
 static constexpr uint32_t POS_STOP = 0x7f80'0000U;
 
+// Range: [-Inf, 0];
+static constexpr uint32_t NEG_START = 0x8000'0000U;
+static constexpr uint32_t NEG_STOP = 0xff80'0000U;
+
+using LlvmLibcExpfExhaustiveTest =
+    LlvmLibcUnaryOpExhaustiveMathTest<float, mpfr::Operation::Exp,
+                                      LIBC_NAMESPACE::expf>;
+
 TEST_F(LlvmLibcExpfExhaustiveTest, PositiveRange) {
   test_full_range_all_roundings(POS_START, POS_STOP);
 }
 
-// Range: [-Inf, 0];
-static constexpr uint32_t NEG_START = 0xb000'0000U;
-static constexpr uint32_t NEG_STOP = 0xff80'0000U;
-
 TEST_F(LlvmLibcExpfExhaustiveTest, NegativeRange) {
   test_full_range_all_roundings(NEG_START, NEG_STOP);
 }
+
+// Float-eval implementation: tested against the correctly rounded double
+// precision version for round-to-nearest with 1 ULP bound.
+static float expf_float_eval(float x) {
+  return LIBC_NAMESPACE::math::float_eval::expf(x);
+}
+
+using LlvmLibcExpfFloatExhaustiveTest =
+    LlvmLibcUnaryOpAgainstBaselineExhaustiveMathTest<
+        float, LIBC_NAMESPACE::expf, expf_float_eval, 1>;
+
+TEST_F(LlvmLibcExpfFloatExhaustiveTest, PositiveRange) {
+  test_full_range(mpfr::RoundingMode::Nearest, POS_START, POS_STOP);
+}
+
+TEST_F(LlvmLibcExpfFloatExhaustiveTest, NegativeRange) {
+  test_full_range(mpfr::RoundingMode::Nearest, NEG_START, NEG_STOP);
+}
+
+// Statically rounded implementation: tested against double_eval across all
+// roundings.
+using LlvmLibcExpfStaticRoundingExhaustiveTest =
+    LlvmLibcStaticallyRoundedUnaryOpExhaustiveMathTest<
+        float, LIBC_NAMESPACE::math::double_eval::expf,
+        LIBC_NAMESPACE::shared::math::static_rounding::expf>;
+
+TEST_F(LlvmLibcExpfStaticRoundingExhaustiveTest, PositiveRange) {
+  test_full_range_all_roundings(POS_START, POS_STOP);
+}
+
+TEST_F(LlvmLibcExpfStaticRoundingExhaustiveTest, NegativeRange) {
+  test_full_range_all_roundings(NEG_START, NEG_STOP);
+}
diff --git a/libc/test/src/math/exp10f_test.cpp b/libc/test/src/math/exp10f_test.cpp
index 4dbe04845257e..763c61a1c66c9 100644
--- a/libc/test/src/math/exp10f_test.cpp
+++ b/libc/test/src/math/exp10f_test.cpp
@@ -1,123 +1,181 @@
-//===-- Unittests for exp10f ----------------------------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains unittests for exp10f.
+///
+//===----------------------------------------------------------------------===//
 
+#include "hdr/errno_macros.h"
+#include "hdr/fenv_macros.h"
 #include "hdr/math_macros.h"
+#include "hdr/stdint_proxy.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/libc_errno.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/math/exp10f_double_eval.h"
+#include "src/__support/math/exp10f_float_eval.h"
 #include "src/math/exp10f.h"
 #include "test/UnitTest/FPMatcher.h"
 #include "test/UnitTest/Test.h"
 #include "utils/MPFRWrapper/MPFRUtils.h"
 
-#include "hdr/stdint_proxy.h"
+namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
 
-using LlvmLibcExp10fTest = LIBC_NAMESPACE::testing::FPTest<float>;
+class Exp10fTest : public LIBC_NAMESPACE::testing::FPTest<float> {
+public:
+  void test_special_numbers(float (*func)(float)) {
+    EXPECT_FP_EQ(aNaN, func(aNaN));
+    EXPECT_MATH_ERRNO(0);
 
-namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
+    EXPECT_FP_EQ(inf, func(inf));
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ(0.0f, func(neg_inf));
+    EXPECT_MATH_ERRNO(0);
 
-TEST_F(LlvmLibcExp10fTest, SpecialNumbers) {
-  EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::exp10f(aNaN));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ(inf, LIBC_NAMESPACE::exp10f(inf));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::exp10f(neg_inf));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp10f(0.0f));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp10f(-0.0f));
-  EXPECT_MATH_ERRNO(0);
-}
-
-TEST_F(LlvmLibcExp10fTest, Overflow) {
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::exp10f(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::exp10f(FPBits(0x43000000U).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::exp10f(FPBits(0x43000001U).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-}
-
-TEST_F(LlvmLibcExp10fTest, Underflow) {
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      0.0f, LIBC_NAMESPACE::exp10f(FPBits(0xff7fffffU).get_val()),
-      FE_UNDERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-
-  float x = FPBits(0xc2cffff8U).get_val();
-  EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, x,
-                                 LIBC_NAMESPACE::exp10f(x), 0.5);
-  EXPECT_MATH_ERRNO(ERANGE);
-
-  x = FPBits(0xc2d00008U).get_val();
-  EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, x,
-                                 LIBC_NAMESPACE::exp10f(x), 0.5);
-  EXPECT_MATH_ERRNO(ERANGE);
-}
-
-TEST_F(LlvmLibcExp10fTest, TrickyInputs) {
-  constexpr int N = 20;
-  constexpr uint32_t INPUTS[N] = {
-      0x325e5bd8, // x = 0x1.bcb7bp-27f
-      0x325e5bd9, // x = 0x1.bcb7b2p-27f
-      0x325e5bda, // x = 0x1.bcb7b4p-27f
-      0x3d14d956, // x = 0x1.29b2acp-5f
-      0x4116498a, // x = 0x1.2c9314p3f
-      0x4126f431, // x = 0x1.4de862p3f
-      0x4187d13c, // x = 0x1.0fa278p4f
-      0x4203e9da, // x = 0x1.07d3b4p5f
-      0x420b5f5d, // x = 0x1.16bebap5f
-      0x42349e35, // x = 0x1.693c6ap5f
-      0x3f800000, // x = 1.0f
-      0x40000000, // x = 2.0f
-      0x40400000, // x = 3.0f
-      0x40800000, // x = 4.0f
-      0x40a00000, // x = 5.0f
-      0x40c00000, // x = 6.0f
-      0x40e00000, // x = 7.0f
-      0x41000000, // x = 8.0f
-      0x41100000, // x = 9.0f
-      0x41200000, // x = 10.0f
-  };
-  for (int i = 0; i < N; ++i) {
-    float x = FPBits(INPUTS[i]).get_val();
-    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, x,
-                                   LIBC_NAMESPACE::exp10f(x), 0.5);
-    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, -x,
-                                   LIBC_NAMESPACE::exp10f(-x), 0.5);
+    EXPECT_FP_EQ(1.0f, func(0.0f));
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ(1.0f, func(-0.0f));
+    EXPECT_MATH_ERRNO(0);
   }
-}
-
-TEST_F(LlvmLibcExp10fTest, InFloatRange) {
-  constexpr uint32_t COUNT = 1'231;
-  constexpr uint32_t STEP = UINT32_MAX / COUNT;
-  for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
-    float x = FPBits(v).get_val();
-    if (FPBits(v).is_nan() || FPBits(v).is_inf())
-      continue;
-    libc_errno = 0;
-    float result = LIBC_NAMESPACE::exp10f(x);
-
-    // If the computation resulted in an error or did not produce valid result
-    // in the single-precision floating point range, then ignore comparing with
-    // MPFR result as MPFR can still produce valid results because of its
-    // wider precision.
-    if (FPBits(result).is_nan() || FPBits(result).is_inf() || libc_errno != 0)
-      continue;
-    ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, x,
-                                   LIBC_NAMESPACE::exp10f(x), 0.5);
+
+  void test_overflow(float (*func)(float),
+                     bool check_exception_and_errno = true) {
+    constexpr float VALUES[] = {
+        FPBits(0x7f7fffffU).get_val(),
+        FPBits(0x43000000U).get_val(),
+        FPBits(0x43000001U).get_val(),
+    };
+    for (float x : VALUES) {
+      if (check_exception_and_errno) {
+        EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(x), FE_OVERFLOW);
+        EXPECT_MATH_ERRNO(ERANGE);
+      } else {
+        EXPECT_FP_EQ(inf, func(x));
+      }
+    }
   }
-}
+
+  void test_underflow(float (*func)(float), double ulp_tolerance = 0.5,
+                      bool all_rounding = true,
+                      bool check_exception_and_errno = true) {
+    if (check_exception_and_errno) {
+      EXPECT_FP_EQ_WITH_EXCEPTION(0.0f, func(FPBits(0xff7fffffU).get_val()),
+                                  FE_UNDERFLOW);
+      EXPECT_MATH_ERRNO(ERANGE);
+    } else {
+      EXPECT_FP_EQ(0.0f, func(FPBits(0xff7fffffU).get_val()));
+    }
+
+    constexpr float VALUES[] = {
+        FPBits(0xc2cffff8U).get_val(),
+        FPBits(0xc2d00008U).get_val(),
+    };
+
+    for (float x : VALUES) {
+      if (all_rounding) {
+        EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, x, func(x),
+                                       ulp_tolerance);
+      } else {
+        EXPECT_MPFR_MATCH(mpfr::Operation::Exp10, x, func(x), ulp_tolerance);
+      }
+      if (check_exception_and_errno) {
+        EXPECT_MATH_ERRNO(ERANGE);
+      }
+    }
+  }
+
+  void test_tricky_inputs(float (*func)(float), double ulp_tolerance = 0.5,
+                          bool all_rounding = true) {
+    constexpr int N = 20;
+    constexpr uint32_t INPUTS[N] = {
+        0x325e5bd8, // x = 0x1.bcb7bp-27f
+        0x325e5bd9, // x = 0x1.bcb7b2p-27f
+        0x325e5bda, // x = 0x1.bcb7b4p-27f
+        0x3d14d956, // x = 0x1.29b2acp-5f
+        0x4116498a, // x = 0x1.2c9314p3f
+        0x4126f431, // x = 0x1.4de862p3f
+        0x4187d13c, // x = 0x1.0fa278p4f
+        0x4203e9da, // x = 0x1.07d3b4p5f
+        0x420b5f5d, // x = 0x1.16bebap5f
+        0x42349e35, // x = 0x1.693c6ap5f
+        0x3f800000, // x = 1.0f
+        0x40000000, // x = 2.0f
+        0x40400000, // x = 3.0f
+        0x40800000, // x = 4.0f
+        0x40a00000, // x = 5.0f
+        0x40c00000, // x = 6.0f
+        0x40e00000, // x = 7.0f
+        0x41000000, // x = 8.0f
+        0x41100000, // x = 9.0f
+        0x41200000, // x = 10.0f
+    };
+    for (int i = 0; i < N; ++i) {
+      float x = FPBits(INPUTS[i]).get_val();
+      if (all_rounding) {
+        EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, x, func(x),
+                                       ulp_tolerance);
+        EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, -x, func(-x),
+                                       ulp_tolerance);
+      } else {
+        EXPECT_MPFR_MATCH(mpfr::Operation::Exp10, x, func(x), ulp_tolerance);
+        EXPECT_MPFR_MATCH(mpfr::Operation::Exp10, -x, func(-x), ulp_tolerance);
+      }
+    }
+  }
+
+  void test_in_range(float (*func)(float), double ulp_tolerance = 0.5,
+                     bool all_rounding = true, bool check_errno = true) {
+    constexpr uint32_t COUNT = 1'231;
+    constexpr uint32_t STEP = UINT32_MAX / COUNT;
+    for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
+      float x = FPBits(v).get_val();
+      if (FPBits(v).is_nan() || FPBits(v).is_inf())
+        continue;
+
+      libc_errno = 0;
+      float result = func(x);
+      if (FPBits(result).is_nan() || FPBits(result).is_inf())
+        continue;
+      if (check_errno && libc_errno != 0)
+        continue;
+
+      if (all_rounding) {
+        EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, x, func(x),
+                                       ulp_tolerance);
+      } else {
+        EXPECT_MPFR_MATCH(mpfr::Operation::Exp10, x, result, ulp_tolerance);
+      }
+    }
+  }
+};
+
+#define LIST_EXP10F_TESTS(suffix, func, ulp_tolerance, all_rounding)           \
+  using LlvmLibcExp10fTest##suffix = Exp10fTest;                               \
+  TEST_F(LlvmLibcExp10fTest##suffix, SpecialNumbers) {                         \
+    test_special_numbers(&func);                                               \
+  }                                                                            \
+  TEST_F(LlvmLibcExp10fTest##suffix, Overflow) { test_overflow(&func); }       \
+  TEST_F(LlvmLibcExp10fTest##suffix, Underflow) {                              \
+    test_underflow(&func, ulp_tolerance, all_rounding);                        \
+  }                                                                            \
+  TEST_F(LlvmLibcExp10fTest##suffix, TrickyInputs) {                           \
+    test_tricky_inputs(&func, ulp_tolerance, all_rounding);                    \
+  }                                                                            \
+  TEST_F(LlvmLibcExp10fTest##suffix, InFloatRange) {                           \
+    test_in_range(&func, ulp_tolerance, all_rounding);                         \
+  }
+
+LIST_EXP10F_TESTS(Default, LIBC_NAMESPACE::exp10f, /*ulp_tolerance=*/0.5,
+                  /*all_rounding=*/true)
+LIST_EXP10F_TESTS(DoubleEval, LIBC_NAMESPACE::math::double_eval::exp10f,
+                  /*ulp_tolerance=*/0.5, /*all_rounding=*/true)
+LIST_EXP10F_TESTS(FloatEval, LIBC_NAMESPACE::math::float_eval::exp10f,
+                  /*ulp_tolerance=*/1.5, /*all_rounding=*/false)
diff --git a/libc/test/src/math/exp2f_test.cpp b/libc/test/src/math/exp2f_test.cpp
index 7f54fbce31505..d5ed25b8aa092 100644
--- a/libc/test/src/math/exp2f_test.cpp
+++ b/libc/test/src/math/exp2f_test.cpp
@@ -1,16 +1,25 @@
-//===-- Unittests for exp2f -----------------------------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains unittests for exp2f.
+///
+//===----------------------------------------------------------------------===//
 
+#include "hdr/errno_macros.h"
+#include "hdr/fenv_macros.h"
 #include "hdr/math_macros.h"
 #include "hdr/stdint_proxy.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/libc_errno.h"
 #include "src/__support/macros/optimization.h"
+#include "src/__support/math/exp2f_double_eval.h"
+#include "src/__support/math/exp2f_float_eval.h"
 #include "src/math/exp2f.h"
 #include "test/UnitTest/FPMatcher.h"
 #include "test/UnitTest/Test.h"
@@ -18,108 +27,157 @@
 
 #ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
 #define TOLERANCE 1
-#else
+#else // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
 #define TOLERANCE 0
 #endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
 
-using LlvmLibcExp2fTest = LIBC_NAMESPACE::testing::FPTest<float>;
-
 namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
 
-TEST_F(LlvmLibcExp2fTest, SpecialNumbers) {
-  EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::exp2f(aNaN));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ(inf, LIBC_NAMESPACE::exp2f(inf));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::exp2f(neg_inf));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp2f(0.0f));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp2f(-0.0f));
-  EXPECT_MATH_ERRNO(0);
-}
-
-TEST_F(LlvmLibcExp2fTest, Overflow) {
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::exp2f(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::exp2f(FPBits(0x43000000U).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::exp2f(FPBits(0x43000001U).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-}
-
-TEST_F(LlvmLibcExp2fTest, TrickyInputs) {
-  constexpr int N = 12;
-  constexpr uint32_t INPUTS[N] = {
-      0x3b429d37U, /*0x1.853a6ep-9f*/
-      0x3c02a9adU, /*0x1.05535ap-7f*/
-      0x3ca66e26U, /*0x1.4cdc4cp-6f*/
-      0x3d92a282U, /*0x1.254504p-4f*/
-      0x42fa0001U, /*0x1.f40002p+6f*/
-      0x42ffffffU, /*0x1.fffffep+6f*/
-      0xb8d3d026U, /*-0x1.a7a04cp-14f*/
-      0xbcf3a937U, /*-0x1.e7526ep-6f*/
-      0xc2fa0001U, /*-0x1.f40002p+6f*/
-      0xc2fc0000U, /*-0x1.f8p+6f*/
-      0xc2fc0001U, /*-0x1.f80002p+6f*/
-      0xc3150000U, /*-0x1.2ap+7f*/
-  };
-  for (int i = 0; i < N; ++i) {
-    libc_errno = 0;
-    float x = FPBits(INPUTS[i]).get_val();
-    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2, x,
-                                   LIBC_NAMESPACE::exp2f(x), TOLERANCE + 0.5);
+class Exp2fTest : public LIBC_NAMESPACE::testing::FPTest<float> {
+public:
+  void test_special_numbers(float (*func)(float)) {
+    EXPECT_FP_EQ(aNaN, func(aNaN));
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ(inf, func(inf));
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ(0.0f, func(neg_inf));
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ(1.0f, func(0.0f));
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ(1.0f, func(-0.0f));
     EXPECT_MATH_ERRNO(0);
   }
-}
-
-TEST_F(LlvmLibcExp2fTest, Underflow) {
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      0.0f, LIBC_NAMESPACE::exp2f(FPBits(0xff7fffffU).get_val()), FE_UNDERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-
-  float x = FPBits(0xc3158000U).get_val();
-  EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2, x,
-                                 LIBC_NAMESPACE::exp2f(x), 0.5);
-  EXPECT_MATH_ERRNO(0);
-
-  x = FPBits(0xc3160000U).get_val();
-  EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2, x,
-                                 LIBC_NAMESPACE::exp2f(x), 0.5);
-  EXPECT_MATH_ERRNO(ERANGE);
-
-  x = FPBits(0xc3165432U).get_val();
-  EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2, x,
-                                 LIBC_NAMESPACE::exp2f(x), 0.5);
-  EXPECT_MATH_ERRNO(ERANGE);
-}
-
-TEST_F(LlvmLibcExp2fTest, InFloatRange) {
-  constexpr uint32_t COUNT = 1'231;
-  constexpr uint32_t STEP = UINT32_MAX / COUNT;
-  for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
-    float x = FPBits(v).get_val();
-    if (FPBits(v).is_nan() || FPBits(v).is_inf())
-      continue;
-    libc_errno = 0;
-    float result = LIBC_NAMESPACE::exp2f(x);
-
-    // If the computation resulted in an error or did not produce valid result
-    // in the single-precision floating point range, then ignore comparing with
-    // MPFR result as MPFR can still produce valid results because of its
-    // wider precision.
-    if (FPBits(result).is_nan() || FPBits(result).is_inf() || libc_errno != 0)
-      continue;
-    ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2, x,
-                                   LIBC_NAMESPACE::exp2f(x), 0.5);
+
+  void test_overflow(float (*func)(float),
+                     bool check_exception_and_errno = true) {
+    constexpr float VALUES[] = {
+        FPBits(0x7f7fffffU).get_val(),
+        FPBits(0x43000000U).get_val(),
+        FPBits(0x43000001U).get_val(),
+    };
+    for (float x : VALUES) {
+      if (check_exception_and_errno) {
+        EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(x), FE_OVERFLOW);
+        EXPECT_MATH_ERRNO(ERANGE);
+      } else {
+        EXPECT_FP_EQ(inf, func(x));
+      }
+    }
+  }
+
+  void test_tricky_inputs(float (*func)(float), double ulp_tolerance = 0.5,
+                          bool all_rounding = true) {
+    constexpr int N = 12;
+    constexpr uint32_t INPUTS[N] = {
+        0x3b429d37U, /*0x1.853a6ep-9f*/
+        0x3c02a9adU, /*0x1.05535ap-7f*/
+        0x3ca66e26U, /*0x1.4cdc4cp-6f*/
+        0x3d92a282U, /*0x1.254504p-4f*/
+        0x42fa0001U, /*0x1.f40002p+6f*/
+        0x42ffffffU, /*0x1.fffffep+6f*/
+        0xb8d3d026U, /*-0x1.a7a04cp-14f*/
+        0xbcf3a937U, /*-0x1.e7526ep-6f*/
+        0xc2fa0001U, /*-0x1.f40002p+6f*/
+        0xc2fc0000U, /*-0x1.f8p+6f*/
+        0xc2fc0001U, /*-0x1.f80002p+6f*/
+        0xc3150000U, /*-0x1.2ap+7f*/
+    };
+    for (int i = 0; i < N; ++i) {
+      float x = FPBits(INPUTS[i]).get_val();
+      libc_errno = 0;
+      if (all_rounding) {
+        EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2, x, func(x),
+                                       ulp_tolerance);
+      } else {
+        EXPECT_MPFR_MATCH(mpfr::Operation::Exp2, x, func(x), ulp_tolerance);
+      }
+      EXPECT_MATH_ERRNO(0);
+    }
+  }
+
+  void test_underflow(float (*func)(float), double ulp_tolerance = 0.5,
+                      bool all_rounding = true,
+                      bool check_exception_and_errno = true) {
+    if (check_exception_and_errno) {
+      EXPECT_FP_EQ_WITH_EXCEPTION(0.0f, func(FPBits(0xff7fffffU).get_val()),
+                                  FE_UNDERFLOW);
+      EXPECT_MATH_ERRNO(ERANGE);
+    } else {
+      EXPECT_FP_EQ(0.0f, func(FPBits(0xff7fffffU).get_val()));
+    }
+
+    struct TestCase {
+      float x;
+      int expected_errno;
+    } cases[] = {
+        {FPBits(0xc3158000U).get_val(), 0},
+        {FPBits(0xc3160000U).get_val(), ERANGE},
+        {FPBits(0xc3165432U).get_val(), ERANGE},
+    };
+
+    for (const auto &c : cases) {
+      libc_errno = 0;
+      if (all_rounding) {
+        EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2, c.x, func(c.x),
+                                       ulp_tolerance);
+      } else {
+        EXPECT_MPFR_MATCH(mpfr::Operation::Exp2, c.x, func(c.x), ulp_tolerance);
+      }
+      if (check_exception_and_errno) {
+        EXPECT_MATH_ERRNO(c.expected_errno);
+      }
+    }
+  }
+
+  void test_in_range(float (*func)(float), double ulp_tolerance = 0.5,
+                     bool all_rounding = true, bool check_errno = true) {
+    constexpr uint32_t COUNT = 1'231;
+    constexpr uint32_t STEP = UINT32_MAX / COUNT;
+    for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
+      float x = FPBits(v).get_val();
+      if (FPBits(v).is_nan() || FPBits(v).is_inf())
+        continue;
+
+      libc_errno = 0;
+      float result = func(x);
+      if (FPBits(result).is_nan() || FPBits(result).is_inf())
+        continue;
+      if (check_errno && libc_errno != 0)
+        continue;
+
+      if (all_rounding) {
+        EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2, x, func(x),
+                                       ulp_tolerance);
+      } else {
+        EXPECT_MPFR_MATCH(mpfr::Operation::Exp2, x, result, ulp_tolerance);
+      }
+    }
   }
-}
+};
+
+#define LIST_EXP2F_TESTS(suffix, func, ulp_tolerance, all_rounding)            \
+  using LlvmLibcExp2fTest##suffix = Exp2fTest;                                 \
+  TEST_F(LlvmLibcExp2fTest##suffix, SpecialNumbers) {                          \
+    test_special_numbers(&func);                                               \
+  }                                                                            \
+  TEST_F(LlvmLibcExp2fTest##suffix, Overflow) { test_overflow(&func); }        \
+  TEST_F(LlvmLibcExp2fTest##suffix, TrickyInputs) {                            \
+    test_tricky_inputs(&func, ulp_tolerance, all_rounding);                    \
+  }                                                                            \
+  TEST_F(LlvmLibcExp2fTest##suffix, Underflow) {                               \
+    test_underflow(&func, ulp_tolerance, all_rounding);                        \
+  }                                                                            \
+  TEST_F(LlvmLibcExp2fTest##suffix, InFloatRange) {                            \
+    test_in_range(&func, ulp_tolerance, all_rounding);                         \
+  }
+
+LIST_EXP2F_TESTS(Default, LIBC_NAMESPACE::exp2f,
+                 /*ulp_tolerance=*/TOLERANCE + 0.5, /*all_rounding=*/true)
+LIST_EXP2F_TESTS(DoubleEval, LIBC_NAMESPACE::math::double_eval::exp2f,
+                 /*ulp_tolerance=*/TOLERANCE + 0.5, /*all_rounding=*/true)
+LIST_EXP2F_TESTS(FloatEval, LIBC_NAMESPACE::math::float_eval::exp2f,
+                 /*ulp_tolerance=*/1.5, /*all_rounding=*/false)
diff --git a/libc/test/src/math/expf_static_rounding_test.cpp b/libc/test/src/math/expf_static_rounding_test.cpp
deleted file mode 100644
index 9befb1de10972..0000000000000
--- a/libc/test/src/math/expf_static_rounding_test.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// This file contains the unit tests for statically-rounded implementation of
-/// static_rounding::expf(x)
-///
-//===----------------------------------------------------------------------===//
-
-#include "hdr/math_macros.h"
-#include "hdr/stdint_proxy.h"
-#include "shared/static_rounding_math.h"
-#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/libc_errno.h"
-#include "src/__support/macros/optimization.h"
-#include "src/__support/math/expf.h"
-#include "test/UnitTest/FPMatcher.h"
-#include "test/UnitTest/RoundingModeUtils.h"
-#include "test/UnitTest/Test.h"
-
-using LlvmLibcExpfStaticRoundingTest = LIBC_NAMESPACE::testing::FPTest<float>;
-using RoundingMode = LIBC_NAMESPACE::fputil::testing::RoundingMode;
-
-namespace static_rounding = LIBC_NAMESPACE::shared::math::static_rounding;
-namespace math = LIBC_NAMESPACE::math;
-
-TEST_F(LlvmLibcExpfStaticRoundingTest, SpecialNumbers) {
-  using LIBC_NAMESPACE::fputil::testing::get_fe_rounding;
-
-  for (auto rounding : ROUNDING_MODES) {
-    const int fenv_rounding = get_fe_rounding(rounding);
-    EXPECT_FP_EQ_ROUNDING_MODE(
-        math::expf(aNaN), static_rounding::expf(aNaN, fenv_rounding), rounding);
-    EXPECT_MATH_ERRNO(0);
-
-    EXPECT_FP_EQ_ROUNDING_MODE(
-        math::expf(inf), static_rounding::expf(inf, fenv_rounding), rounding);
-    EXPECT_MATH_ERRNO(0);
-
-    EXPECT_FP_EQ_ROUNDING_MODE(math::expf(neg_inf),
-                               static_rounding::expf(neg_inf, fenv_rounding),
-                               rounding);
-    EXPECT_MATH_ERRNO(0);
-
-    EXPECT_FP_EQ_ROUNDING_MODE(
-        math::expf(0.0f), static_rounding::expf(0.0f, fenv_rounding), rounding);
-    EXPECT_MATH_ERRNO(0);
-
-    EXPECT_FP_EQ_ROUNDING_MODE(math::expf(-0.0f),
-                               static_rounding::expf(-0.0f, fenv_rounding),
-                               rounding);
-    EXPECT_MATH_ERRNO(0);
-  }
-}
-
-TEST_F(LlvmLibcExpfStaticRoundingTest, Overflow) {
-  constexpr float VALUES[] = {FPBits(0x7f7fffffU).get_val(),
-                              FPBits(0x42cffff8U).get_val(),
-                              FPBits(0x42d00008U).get_val()};
-
-  for (auto rounding : ROUNDING_MODES) {
-    const int fenv_rounding = get_fe_rounding(rounding);
-
-    // Statically rounded expf doesn't raise exceptions
-
-    for (auto x : VALUES) {
-      EXPECT_FP_EQ_ROUNDING_MODE(
-          math::expf(x), static_rounding::expf(x, fenv_rounding), rounding);
-    }
-  }
-}
-
-TEST_F(LlvmLibcExpfStaticRoundingTest, Underflow) {
-  using LIBC_NAMESPACE::fputil::testing::get_fe_rounding;
-
-  constexpr float VALUES[] = {FPBits(0xff7fffffU).get_val(),
-                              FPBits(0xc2cffff8U).get_val(),
-                              FPBits(0xc2d00008U).get_val()};
-
-  for (auto rounding : ROUNDING_MODES) {
-    const int fenv_rounding = get_fe_rounding(rounding);
-
-    // Statically rounded expf doesn't raise exceptions
-    for (auto x : VALUES) {
-      EXPECT_FP_EQ_ROUNDING_MODE(
-          math::expf(x), static_rounding::expf(x, fenv_rounding), rounding);
-    }
-  }
-}
-
-// Test with inputs which are the borders of underflow/overflow but still
-// produce valid results without setting errno.
-TEST_F(LlvmLibcExpfStaticRoundingTest, Borderline) {
-  using LIBC_NAMESPACE::fputil::testing::get_fe_rounding;
-
-  constexpr float VALUES[] = {
-      FPBits(0x42affff8U).get_val(), FPBits(0x42b00008U).get_val(),
-      FPBits(0xc2affff8U).get_val(), FPBits(0xc2b00008U).get_val(),
-      FPBits(0xc236bd8cU).get_val()};
-
-  for (auto rounding : ROUNDING_MODES) {
-    const int fenv_rounding = get_fe_rounding(rounding);
-
-    for (auto x : VALUES) {
-      EXPECT_FP_EQ_ROUNDING_MODE(
-          math::expf(x), static_rounding::expf(x, fenv_rounding), rounding);
-    }
-  }
-}
-
-TEST_F(LlvmLibcExpfStaticRoundingTest, InFloatRange) {
-  using LIBC_NAMESPACE::fputil::testing::get_fe_rounding;
-
-  constexpr uint32_t COUNT = 1'231;
-  constexpr uint32_t STEP = UINT32_MAX / COUNT;
-  for (auto rounding : ROUNDING_MODES) {
-    const int fenv_rounding = get_fe_rounding(rounding);
-
-    for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
-      float x = FPBits(v).get_val();
-      if (FPBits(v).is_nan() || FPBits(v).is_inf())
-        continue;
-      libc_errno = 0;
-      EXPECT_FP_EQ_ROUNDING_MODE(
-          math::expf(x), static_rounding::expf(x, fenv_rounding), rounding);
-    }
-  }
-}
diff --git a/libc/test/src/math/expf_test.cpp b/libc/test/src/math/expf_test.cpp
index b04473d2bfe7a..2cf30559adabb 100644
--- a/libc/test/src/math/expf_test.cpp
+++ b/libc/test/src/math/expf_test.cpp
@@ -1,16 +1,26 @@
-//===-- Unittests for expf ------------------------------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains unittests for expf.
+///
+//===----------------------------------------------------------------------===//
 
+#include "hdr/errno_macros.h"
+#include "hdr/fenv_macros.h"
 #include "hdr/math_macros.h"
 #include "hdr/stdint_proxy.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/libc_errno.h"
 #include "src/__support/macros/optimization.h"
+#include "src/__support/math/expf_double_eval.h"
+#include "src/__support/math/expf_float_eval.h"
+#include "src/__support/math/expf_integer_eval.h"
 #include "src/math/expf.h"
 #include "test/UnitTest/FPMatcher.h"
 #include "test/UnitTest/Test.h"
@@ -18,109 +28,167 @@
 
 #ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
 #define TOLERANCE 1
-#else
+#else // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
 #define TOLERANCE 0
 #endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
 
-using LlvmLibcExpfTest = LIBC_NAMESPACE::testing::FPTest<float>;
-
 namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
 
-TEST_F(LlvmLibcExpfTest, SpecialNumbers) {
-  EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::expf(aNaN));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ(inf, LIBC_NAMESPACE::expf(inf));
-  EXPECT_MATH_ERRNO(0);
+class ExpfTest : public LIBC_NAMESPACE::testing::FPTest<float> {
+public:
+  void test_special_numbers(float (*func)(float), bool check_errno = true) {
+    EXPECT_FP_EQ(aNaN, func(aNaN));
+    if (check_errno)
+      EXPECT_MATH_ERRNO(0);
 
-  EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::expf(neg_inf));
-  EXPECT_MATH_ERRNO(0);
+    EXPECT_FP_EQ(inf, func(inf));
+    if (check_errno)
+      EXPECT_MATH_ERRNO(0);
 
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::expf(0.0f));
-  EXPECT_MATH_ERRNO(0);
+    EXPECT_FP_EQ(0.0f, func(neg_inf));
+    if (check_errno)
+      EXPECT_MATH_ERRNO(0);
 
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::expf(-0.0f));
-  EXPECT_MATH_ERRNO(0);
-}
-
-TEST_F(LlvmLibcExpfTest, Overflow) {
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::expf(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
+    EXPECT_FP_EQ(1.0f, func(0.0f));
+    if (check_errno)
+      EXPECT_MATH_ERRNO(0);
 
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::expf(FPBits(0x42cffff8U).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
+    EXPECT_FP_EQ(1.0f, func(-0.0f));
+    if (check_errno)
+      EXPECT_MATH_ERRNO(0);
+  }
 
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::expf(FPBits(0x42d00008U).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-}
+  void test_overflow(float (*func)(float),
+                     bool check_exception_and_errno = true) {
+    constexpr float VALUES[] = {
+        FPBits(0x7f7fffffU).get_val(),
+        FPBits(0x42cffff8U).get_val(),
+        FPBits(0x42d00008U).get_val(),
+    };
+    for (float x : VALUES) {
+      if (check_exception_and_errno) {
+        EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(x), FE_OVERFLOW);
+        EXPECT_MATH_ERRNO(ERANGE);
+      } else {
+        EXPECT_FP_EQ(inf, func(x));
+      }
+    }
+  }
 
-TEST_F(LlvmLibcExpfTest, Underflow) {
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      0.0f, LIBC_NAMESPACE::expf(FPBits(0xff7fffffU).get_val()), FE_UNDERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
+  void test_underflow(float (*func)(float), double ulp_tolerance = 0.5,
+                      bool all_rounding = true,
+                      bool check_exception_and_errno = true) {
+    if (check_exception_and_errno) {
+      EXPECT_FP_EQ_WITH_EXCEPTION(0.0f, func(FPBits(0xff7fffffU).get_val()),
+                                  FE_UNDERFLOW);
+      EXPECT_MATH_ERRNO(ERANGE);
+    } else {
+      EXPECT_FP_EQ(0.0f, func(FPBits(0xff7fffffU).get_val()));
+    }
+
+    constexpr float VALUES[] = {
+        FPBits(0xc2cffff8U).get_val(),
+        FPBits(0xc2d00008U).get_val(),
+    };
+
+    for (float x : VALUES) {
+      if (all_rounding) {
+        EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp, x, func(x),
+                                       ulp_tolerance);
+      } else {
+        EXPECT_MPFR_MATCH(mpfr::Operation::Exp, x, func(x), ulp_tolerance);
+      }
+      if (check_exception_and_errno) {
+        EXPECT_MATH_ERRNO(ERANGE);
+      }
+    }
+  }
 
-  float x = FPBits(0xc2cffff8U).get_val();
-  EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp, x,
-                                 LIBC_NAMESPACE::expf(x), 0.5);
-  EXPECT_MATH_ERRNO(ERANGE);
+  void test_borderline(float (*func)(float), double ulp_tolerance = 0.5,
+                       bool all_rounding = true, bool check_errno = true) {
+    constexpr float INPUTS[] = {
+        FPBits(0x42affff8U).get_val(), FPBits(0x42b00008U).get_val(),
+        FPBits(0xc2affff8U).get_val(), FPBits(0xc2b00008U).get_val(),
+        FPBits(0xc236bd8cU).get_val()};
+
+    for (float x : INPUTS) {
+      if (all_rounding) {
+        ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp, x, func(x),
+                                       ulp_tolerance);
+      } else {
+        ASSERT_MPFR_MATCH(mpfr::Operation::Exp, x, func(x), ulp_tolerance);
+      }
+      if (check_errno) {
+        EXPECT_MATH_ERRNO(0);
+      }
+    }
+  }
 
-  x = FPBits(0xc2d00008U).get_val();
-  EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp, x,
-                                 LIBC_NAMESPACE::expf(x), 0.5);
-  EXPECT_MATH_ERRNO(ERANGE);
-}
+  void test_in_range(float (*func)(float), double ulp_tolerance = 0.5,
+                     bool all_rounding = true, bool check_errno = true) {
+    constexpr uint32_t COUNT = 1'231;
+    constexpr uint32_t STEP = UINT32_MAX / COUNT;
+    for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
+      float x = FPBits(v).get_val();
+      if (FPBits(v).is_nan() || FPBits(v).is_inf())
+        continue;
+
+      libc_errno = 0;
+      float result = func(x);
+      if (FPBits(result).is_nan() || FPBits(result).is_inf())
+        continue;
+      if (check_errno && libc_errno != 0)
+        continue;
+
+      if (all_rounding) {
+        EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp, x, func(x),
+                                       ulp_tolerance);
+      } else {
+        EXPECT_MPFR_MATCH(mpfr::Operation::Exp, x, result, ulp_tolerance);
+      }
+    }
+  }
+};
+
+#define LIST_EXPF_TESTS(suffix, func, ulp_tolerance, all_rounding,             \
+                        check_exception_and_errno, check_errno)                \
+  using LlvmLibcExpfTest##suffix = ExpfTest;                                   \
+  TEST_F(LlvmLibcExpfTest##suffix, SpecialNumbers) {                           \
+    test_special_numbers(&func, check_errno);                                  \
+  }                                                                            \
+  TEST_F(LlvmLibcExpfTest##suffix, Overflow) {                                 \
+    test_overflow(&func, check_exception_and_errno);                           \
+  }                                                                            \
+  TEST_F(LlvmLibcExpfTest##suffix, Underflow) {                                \
+    test_underflow(&func, ulp_tolerance, all_rounding,                         \
+                   check_exception_and_errno);                                 \
+  }                                                                            \
+  TEST_F(LlvmLibcExpfTest##suffix, Borderline) {                               \
+    test_borderline(&func, ulp_tolerance, all_rounding, check_errno);          \
+  }                                                                            \
+  TEST_F(LlvmLibcExpfTest##suffix, InFloatRange) {                             \
+    test_in_range(&func, ulp_tolerance, all_rounding, check_errno);            \
+  }
 
-// Test with inputs which are the borders of underflow/overflow but still
-// produce valid results without setting errno.
-TEST_F(LlvmLibcExpfTest, Borderline) {
-  float x;
-
-  x = FPBits(0x42affff8U).get_val();
-  ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp, x,
-                                 LIBC_NAMESPACE::expf(x), 0.5);
-  EXPECT_MATH_ERRNO(0);
-
-  x = FPBits(0x42b00008U).get_val();
-  ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp, x,
-                                 LIBC_NAMESPACE::expf(x), 0.5);
-  EXPECT_MATH_ERRNO(0);
-
-  x = FPBits(0xc2affff8U).get_val();
-  ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp, x,
-                                 LIBC_NAMESPACE::expf(x), 0.5);
-  EXPECT_MATH_ERRNO(0);
-
-  x = FPBits(0xc2b00008U).get_val();
-  ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp, x,
-                                 LIBC_NAMESPACE::expf(x), 0.5);
-  EXPECT_MATH_ERRNO(0);
-
-  x = FPBits(0xc236bd8cU).get_val();
-  EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp, x,
-                                 LIBC_NAMESPACE::expf(x), TOLERANCE + 0.5);
-  EXPECT_MATH_ERRNO(0);
+LIST_EXPF_TESTS(Default, LIBC_NAMESPACE::expf,
+                /*ulp_tolerance=*/TOLERANCE + 0.5,
+                /*all_rounding=*/true, /*check_exception_and_errno=*/true,
+                /*check_errno=*/true)
+LIST_EXPF_TESTS(DoubleEval, LIBC_NAMESPACE::math::double_eval::expf,
+                /*ulp_tolerance=*/TOLERANCE + 0.5, /*all_rounding=*/true,
+                /*check_exception_and_errno=*/true, /*check_errno=*/true)
+LIST_EXPF_TESTS(FloatEval, LIBC_NAMESPACE::math::float_eval::expf,
+                /*ulp_tolerance=*/1.5, /*all_rounding=*/false,
+                /*check_exception_and_errno=*/true, /*check_errno=*/true)
+LIST_EXPF_TESTS(IntegerEval, LIBC_NAMESPACE::math::integer_eval::expf,
+                /*ulp_tolerance=*/0.5, /*all_rounding=*/false,
+                /*check_exception_and_errno=*/false, /*check_errno=*/false)
+
+static float expf_static_rounding(float x) {
+  return LIBC_NAMESPACE::shared::math::static_rounding::expf(
+      x, LIBC_NAMESPACE::fputil::quick_get_round());
 }
 
-TEST_F(LlvmLibcExpfTest, InFloatRange) {
-  constexpr uint32_t COUNT = 1'231;
-  constexpr uint32_t STEP = UINT32_MAX / COUNT;
-  for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
-    float x = FPBits(v).get_val();
-    if (FPBits(v).is_nan() || FPBits(v).is_inf())
-      continue;
-    libc_errno = 0;
-    float result = LIBC_NAMESPACE::expf(x);
-
-    // If the computation resulted in an error or did not produce valid result
-    // in the single-precision floating point range, then ignore comparing with
-    // MPFR result as MPFR can still produce valid results because of its
-    // wider precision.
-    if (FPBits(result).is_nan() || FPBits(result).is_inf() || libc_errno != 0)
-      continue;
-    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp, x,
-                                   LIBC_NAMESPACE::expf(x), 0.5);
-  }
-}
+LIST_EXPF_TESTS(StaticRounding, expf_static_rounding,
+                /*ulp_tolerance=*/0.5, /*all_rounding=*/true,
+                /*check_exception_and_errno=*/false, /*check_errno=*/false)
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 603998cd1c41c..0bfe73a2e643a 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -1436,23 +1436,15 @@ add_fp_unittest(
     expf_test.cpp
   DEPENDS
     libc.hdr.errno_macros
+    libc.hdr.fenv_macros
     libc.src.math.expf
-    libc.src.__support.FPUtil.fp_bits
-)
-
-add_fp_unittest(
-  expf_static_rounding_test
-  SUITE
-    libc-math-smoke-tests
-  SRCS
-    expf_static_rounding_test.cpp
-  DEPENDS
-    libc.hdr.errno_macros
-    libc.src.__support.math.expf
+    libc.src.__support.math.expf_double_eval
+    libc.src.__support.math.expf_float_eval
     libc.src.__support.math.expf_integer_eval
     libc.src.__support.FPUtil.fp_bits
 )
 
+
 add_fp_unittest(
   expf16_test
   SUITE
@@ -1500,7 +1492,10 @@ add_fp_unittest(
     exp2f_test.cpp
   DEPENDS
     libc.hdr.errno_macros
+    libc.hdr.fenv_macros
     libc.src.math.exp2f
+    libc.src.__support.math.exp2f_double_eval
+    libc.src.__support.math.exp2f_float_eval
     libc.src.__support.FPUtil.fp_bits
 )
 
@@ -1561,7 +1556,10 @@ add_fp_unittest(
     exp10f_test.cpp
   DEPENDS
     libc.hdr.errno_macros
+    libc.hdr.fenv_macros
     libc.src.math.exp10f
+    libc.src.__support.math.exp10f_double_eval
+    libc.src.__support.math.exp10f_float_eval
     libc.src.__support.FPUtil.fp_bits
 )
 
diff --git a/libc/test/src/math/smoke/exp10f_test.cpp b/libc/test/src/math/smoke/exp10f_test.cpp
index 8d7c1714bcfd5..00c65dcf6acb9 100644
--- a/libc/test/src/math/smoke/exp10f_test.cpp
+++ b/libc/test/src/math/smoke/exp10f_test.cpp
@@ -1,82 +1,112 @@
-//===-- Unittests for exp10f ----------------------------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains smoke tests for exp10f.
+///
+//===----------------------------------------------------------------------===//
 
 #include "hdr/errno_macros.h"
+#include "hdr/fenv_macros.h"
 #include "hdr/math_macros.h"
 #include "hdr/stdint_proxy.h"
 #include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/math/exp10f_double_eval.h"
+#include "src/__support/math/exp10f_float_eval.h"
 #include "src/math/exp10f.h"
 #include "test/UnitTest/FPMatcher.h"
 #include "test/UnitTest/Test.h"
 
-using LlvmLibcExp10fTest = LIBC_NAMESPACE::testing::FPTest<float>;
-
-TEST_F(LlvmLibcExp10fTest, SpecialNumbers) {
-  EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::exp10f(sNaN), FE_INVALID);
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::exp10f(aNaN));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::exp10f(inf));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ_ALL_ROUNDING(0.0f, LIBC_NAMESPACE::exp10f(neg_inf));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ_ALL_ROUNDING(1.0f, LIBC_NAMESPACE::exp10f(0.0f));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ_ALL_ROUNDING(1.0f, LIBC_NAMESPACE::exp10f(-0.0f));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ_ALL_ROUNDING(10.0f, LIBC_NAMESPACE::exp10f(1.0f));
-  EXPECT_FP_EQ_ALL_ROUNDING(100.0f, LIBC_NAMESPACE::exp10f(2.0f));
-  EXPECT_FP_EQ_ALL_ROUNDING(1000.0f, LIBC_NAMESPACE::exp10f(3.0f));
-}
-
-TEST_F(LlvmLibcExp10fTest, Overflow) {
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::exp10f(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::exp10f(FPBits(0x43000000U).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::exp10f(FPBits(0x43000001U).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-}
+class Exp10fTest : public LIBC_NAMESPACE::testing::FPTest<float> {
+public:
+  void test_special_numbers(float (*func)(float),
+                            bool check_snan_invalid = false) {
+    if (check_snan_invalid) {
+      EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, func(sNaN), FE_INVALID);
+    } else {
+      EXPECT_FP_EQ(aNaN, func(sNaN));
+    }
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(aNaN));
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ_ALL_ROUNDING(inf, func(inf));
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ_ALL_ROUNDING(0.0f, func(neg_inf));
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ_ALL_ROUNDING(1.0f, func(0.0f));
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ_ALL_ROUNDING(1.0f, func(-0.0f));
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ_ALL_ROUNDING(10.0f, func(1.0f));
+    EXPECT_FP_EQ_ALL_ROUNDING(100.0f, func(2.0f));
+    EXPECT_FP_EQ_ALL_ROUNDING(1000.0f, func(3.0f));
+  }
+
+  void test_overflow(float (*func)(float),
+                     bool check_exception_and_errno = true) {
+    constexpr float VALUES[] = {
+        FPBits(0x7f7fffffU).get_val(),
+        FPBits(0x43000000U).get_val(),
+        FPBits(0x43000001U).get_val(),
+    };
+    for (float x : VALUES) {
+      if (check_exception_and_errno) {
+        EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(x), FE_OVERFLOW);
+        EXPECT_MATH_ERRNO(ERANGE);
+      } else {
+        EXPECT_FP_EQ(inf, func(x));
+      }
+    }
+  }
 
 #ifdef LIBC_TEST_FTZ_DAZ
+  void test_denormals(float (*func)(float)) {
+    EXPECT_FP_EQ(1.0f, func(min_denormal));
+    EXPECT_FP_EQ(1.0f, func(max_denormal));
+  }
+#endif // LIBC_TEST_FTZ_DAZ
+};
 
-using namespace LIBC_NAMESPACE::testing;
-
-TEST_F(LlvmLibcExp10fTest, FTZMode) {
-  ModifyMXCSR mxcsr(FTZ);
-
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp10f(min_denormal));
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp10f(max_denormal));
-}
-
-TEST_F(LlvmLibcExp10fTest, DAZMode) {
-  ModifyMXCSR mxcsr(DAZ);
-
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp10f(min_denormal));
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp10f(max_denormal));
-}
-
-TEST_F(LlvmLibcExp10fTest, FTZDAZMode) {
-  ModifyMXCSR mxcsr(FTZ | DAZ);
-
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp10f(min_denormal));
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp10f(max_denormal));
-}
-
-#endif
+#ifdef LIBC_TEST_FTZ_DAZ
+#define LIST_EXP10F_FTZ_DAZ_TESTS(suffix, func)                                \
+  TEST_F(LlvmLibcExp10fTest##suffix, FTZMode) {                                \
+    LIBC_NAMESPACE::testing::ModifyMXCSR mxcsr(LIBC_NAMESPACE::testing::FTZ);  \
+    test_denormals(&func);                                                     \
+  }                                                                            \
+  TEST_F(LlvmLibcExp10fTest##suffix, DAZMode) {                                \
+    LIBC_NAMESPACE::testing::ModifyMXCSR mxcsr(LIBC_NAMESPACE::testing::DAZ);  \
+    test_denormals(&func);                                                     \
+  }                                                                            \
+  TEST_F(LlvmLibcExp10fTest##suffix, FTZDAZMode) {                             \
+    LIBC_NAMESPACE::testing::ModifyMXCSR mxcsr(LIBC_NAMESPACE::testing::FTZ |  \
+                                               LIBC_NAMESPACE::testing::DAZ);  \
+    test_denormals(&func);                                                     \
+  }
+#else // !LIBC_TEST_FTZ_DAZ
+#define LIST_EXP10F_FTZ_DAZ_TESTS(suffix, func)
+#endif // LIBC_TEST_FTZ_DAZ
+
+#define LIST_EXP10F_TESTS(suffix, func, check_snan_invalid)                    \
+  using LlvmLibcExp10fTest##suffix = Exp10fTest;                               \
+  TEST_F(LlvmLibcExp10fTest##suffix, SpecialNumbers) {                         \
+    test_special_numbers(&func, check_snan_invalid);                           \
+  }                                                                            \
+  TEST_F(LlvmLibcExp10fTest##suffix, Overflow) { test_overflow(&func); }       \
+  LIST_EXP10F_FTZ_DAZ_TESTS(suffix, func)
+
+LIST_EXP10F_TESTS(Default, LIBC_NAMESPACE::exp10f, /*check_snan_invalid=*/true)
+LIST_EXP10F_TESTS(DoubleEval, LIBC_NAMESPACE::math::double_eval::exp10f,
+                  /*check_snan_invalid=*/false)
+LIST_EXP10F_TESTS(FloatEval, LIBC_NAMESPACE::math::float_eval::exp10f,
+                  /*check_snan_invalid=*/false)
diff --git a/libc/test/src/math/smoke/exp2f_test.cpp b/libc/test/src/math/smoke/exp2f_test.cpp
index 2adfa5fc9040a..bb64844eb7558 100644
--- a/libc/test/src/math/smoke/exp2f_test.cpp
+++ b/libc/test/src/math/smoke/exp2f_test.cpp
@@ -1,83 +1,113 @@
-//===-- Unittests for exp2f -----------------------------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains smoke tests for exp2f.
+///
+//===----------------------------------------------------------------------===//
 
 #include "hdr/errno_macros.h"
+#include "hdr/fenv_macros.h"
 #include "hdr/math_macros.h"
 #include "hdr/stdint_proxy.h"
 #include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/math/exp2f_double_eval.h"
+#include "src/__support/math/exp2f_float_eval.h"
 #include "src/math/exp2f.h"
 #include "test/UnitTest/FPMatcher.h"
 #include "test/UnitTest/Test.h"
 
-using LlvmLibcExp2fTest = LIBC_NAMESPACE::testing::FPTest<float>;
-
-TEST_F(LlvmLibcExp2fTest, SpecialNumbers) {
-  EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::exp2f(sNaN), FE_INVALID);
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::exp2f(aNaN));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::exp2f(inf));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ_ALL_ROUNDING(0.0f, LIBC_NAMESPACE::exp2f(neg_inf));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ_ALL_ROUNDING(1.0f, LIBC_NAMESPACE::exp2f(0.0f));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ_ALL_ROUNDING(1.0f, LIBC_NAMESPACE::exp2f(-0.0f));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ_ALL_ROUNDING(2.0f, LIBC_NAMESPACE::exp2f(1.0f));
-  EXPECT_FP_EQ_ALL_ROUNDING(0.5f, LIBC_NAMESPACE::exp2f(-1.0f));
-  EXPECT_FP_EQ_ALL_ROUNDING(4.0f, LIBC_NAMESPACE::exp2f(2.0f));
-  EXPECT_FP_EQ_ALL_ROUNDING(0.25f, LIBC_NAMESPACE::exp2f(-2.0f));
-}
-
-TEST_F(LlvmLibcExp2fTest, Overflow) {
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::exp2f(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::exp2f(FPBits(0x43000000U).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::exp2f(FPBits(0x43000001U).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-}
+class Exp2fTest : public LIBC_NAMESPACE::testing::FPTest<float> {
+public:
+  void test_special_numbers(float (*func)(float),
+                            bool check_snan_invalid = false) {
+    if (check_snan_invalid) {
+      EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, func(sNaN), FE_INVALID);
+    } else {
+      EXPECT_FP_EQ(aNaN, func(sNaN));
+    }
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(aNaN));
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ_ALL_ROUNDING(inf, func(inf));
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ_ALL_ROUNDING(0.0f, func(neg_inf));
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ_ALL_ROUNDING(1.0f, func(0.0f));
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ_ALL_ROUNDING(1.0f, func(-0.0f));
+    EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ_ALL_ROUNDING(2.0f, func(1.0f));
+    EXPECT_FP_EQ_ALL_ROUNDING(0.5f, func(-1.0f));
+    EXPECT_FP_EQ_ALL_ROUNDING(4.0f, func(2.0f));
+    EXPECT_FP_EQ_ALL_ROUNDING(0.25f, func(-2.0f));
+  }
+
+  void test_overflow(float (*func)(float),
+                     bool check_exception_and_errno = true) {
+    constexpr float VALUES[] = {
+        FPBits(0x7f7fffffU).get_val(),
+        FPBits(0x43000000U).get_val(),
+        FPBits(0x43000001U).get_val(),
+    };
+    for (float x : VALUES) {
+      if (check_exception_and_errno) {
+        EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(x), FE_OVERFLOW);
+        EXPECT_MATH_ERRNO(ERANGE);
+      } else {
+        EXPECT_FP_EQ(inf, func(x));
+      }
+    }
+  }
 
 #ifdef LIBC_TEST_FTZ_DAZ
+  void test_denormals(float (*func)(float)) {
+    EXPECT_FP_EQ(1.0f, func(min_denormal));
+    EXPECT_FP_EQ(1.0f, func(max_denormal));
+  }
+#endif // LIBC_TEST_FTZ_DAZ
+};
 
-using namespace LIBC_NAMESPACE::testing;
-
-TEST_F(LlvmLibcExp2fTest, FTZMode) {
-  ModifyMXCSR mxcsr(FTZ);
-
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp2f(min_denormal));
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp2f(max_denormal));
-}
-
-TEST_F(LlvmLibcExp2fTest, DAZMode) {
-  ModifyMXCSR mxcsr(DAZ);
-
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp2f(min_denormal));
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp2f(max_denormal));
-}
-
-TEST_F(LlvmLibcExp2fTest, FTZDAZMode) {
-  ModifyMXCSR mxcsr(FTZ | DAZ);
-
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp2f(min_denormal));
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp2f(max_denormal));
-}
-
-#endif
+#ifdef LIBC_TEST_FTZ_DAZ
+#define LIST_EXP2F_FTZ_DAZ_TESTS(suffix, func)                                 \
+  TEST_F(LlvmLibcExp2fTest##suffix, FTZMode) {                                 \
+    LIBC_NAMESPACE::testing::ModifyMXCSR mxcsr(LIBC_NAMESPACE::testing::FTZ);  \
+    test_denormals(&func);                                                     \
+  }                                                                            \
+  TEST_F(LlvmLibcExp2fTest##suffix, DAZMode) {                                 \
+    LIBC_NAMESPACE::testing::ModifyMXCSR mxcsr(LIBC_NAMESPACE::testing::DAZ);  \
+    test_denormals(&func);                                                     \
+  }                                                                            \
+  TEST_F(LlvmLibcExp2fTest##suffix, FTZDAZMode) {                              \
+    LIBC_NAMESPACE::testing::ModifyMXCSR mxcsr(LIBC_NAMESPACE::testing::FTZ |  \
+                                               LIBC_NAMESPACE::testing::DAZ);  \
+    test_denormals(&func);                                                     \
+  }
+#else // !LIBC_TEST_FTZ_DAZ
+#define LIST_EXP2F_FTZ_DAZ_TESTS(suffix, func)
+#endif // LIBC_TEST_FTZ_DAZ
+
+#define LIST_EXP2F_TESTS(suffix, func, check_snan_invalid)                     \
+  using LlvmLibcExp2fTest##suffix = Exp2fTest;                                 \
+  TEST_F(LlvmLibcExp2fTest##suffix, SpecialNumbers) {                          \
+    test_special_numbers(&func, check_snan_invalid);                           \
+  }                                                                            \
+  TEST_F(LlvmLibcExp2fTest##suffix, Overflow) { test_overflow(&func); }        \
+  LIST_EXP2F_FTZ_DAZ_TESTS(suffix, func)
+
+LIST_EXP2F_TESTS(Default, LIBC_NAMESPACE::exp2f, /*check_snan_invalid=*/true)
+LIST_EXP2F_TESTS(DoubleEval, LIBC_NAMESPACE::math::double_eval::exp2f,
+                 /*check_snan_invalid=*/false)
+LIST_EXP2F_TESTS(FloatEval, LIBC_NAMESPACE::math::float_eval::exp2f,
+                 /*check_snan_invalid=*/false)
diff --git a/libc/test/src/math/smoke/expf_static_rounding_test.cpp b/libc/test/src/math/smoke/expf_static_rounding_test.cpp
deleted file mode 100644
index 908f87714868c..0000000000000
--- a/libc/test/src/math/smoke/expf_static_rounding_test.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// This file contains smoke tests for static_rounding::expf(x)
-///
-//===----------------------------------------------------------------------===//
-
-#include "hdr/errno_macros.h"
-#include "hdr/math_macros.h"
-#include "hdr/stdint_proxy.h"
-#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/math/expf.h"
-#include "src/__support/math/expf_integer_eval.h"
-#include "test/UnitTest/FPMatcher.h"
-#include "test/UnitTest/Test.h"
-
-using LlvmLibcExpfStaticRoundingTest = LIBC_NAMESPACE::testing::FPTest<float>;
-
-namespace static_rounding = LIBC_NAMESPACE::shared::math::static_rounding;
-namespace math = LIBC_NAMESPACE::math;
-
-TEST_F(LlvmLibcExpfStaticRoundingTest, SpecialNumbers) {
-  using LIBC_NAMESPACE::fputil::testing::get_fe_rounding;
-
-  constexpr float VALUES[] = {sNaN, aNaN, inf, neg_inf, 0.0f, -0.0f};
-
-  for (auto rounding : ROUNDING_MODES) {
-    const int fenv_rounding = get_fe_rounding(rounding);
-
-    for (auto x : VALUES) {
-      EXPECT_FP_EQ_ROUNDING_MODE(
-          math::expf(x), static_rounding::expf(x, fenv_rounding), rounding);
-      // Statically rounded expf doesn't raise exceptions, but the baseline
-      // expf may raise overflow exception.
-      // So, we won't check for that here.
-    }
-  }
-}
-
-TEST_F(LlvmLibcExpfStaticRoundingTest, Overflow) {
-  using LIBC_NAMESPACE::fputil::testing::get_fe_rounding;
-
-  constexpr float VALUES[] = {FPBits(0x7f7fffffU).get_val(),
-                              FPBits(0x42cffff8U).get_val(),
-                              FPBits(0x42d00008U).get_val()};
-
-  for (auto rounding : ROUNDING_MODES) {
-    const int fenv_rounding = get_fe_rounding(rounding);
-
-    for (auto x : VALUES) {
-      EXPECT_FP_EQ_ROUNDING_MODE(
-          math::expf(x), static_rounding::expf(x, fenv_rounding), rounding);
-      // The same reason above, in the SpecialNumbers smoke test suite
-    }
-  }
-}
diff --git a/libc/test/src/math/smoke/expf_test.cpp b/libc/test/src/math/smoke/expf_test.cpp
index ca5bc59619201..f63d0d039fe41 100644
--- a/libc/test/src/math/smoke/expf_test.cpp
+++ b/libc/test/src/math/smoke/expf_test.cpp
@@ -1,78 +1,134 @@
-//===-- Unittests for expf ------------------------------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains smoke tests for expf.
+///
+//===----------------------------------------------------------------------===//
 
 #include "hdr/errno_macros.h"
+#include "hdr/fenv_macros.h"
 #include "hdr/math_macros.h"
 #include "hdr/stdint_proxy.h"
 #include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/math/expf_double_eval.h"
+#include "src/__support/math/expf_float_eval.h"
+#include "src/__support/math/expf_integer_eval.h"
 #include "src/math/expf.h"
 #include "test/UnitTest/FPMatcher.h"
 #include "test/UnitTest/Test.h"
 
-using LlvmLibcExpfTest = LIBC_NAMESPACE::testing::FPTest<float>;
-
-TEST_F(LlvmLibcExpfTest, SpecialNumbers) {
-  EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::expf(sNaN), FE_INVALID);
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::expf(aNaN));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::expf(inf));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ_ALL_ROUNDING(0.0f, LIBC_NAMESPACE::expf(neg_inf));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ_ALL_ROUNDING(1.0f, LIBC_NAMESPACE::expf(0.0f));
-  EXPECT_MATH_ERRNO(0);
-
-  EXPECT_FP_EQ_ALL_ROUNDING(1.0f, LIBC_NAMESPACE::expf(-0.0f));
-  EXPECT_MATH_ERRNO(0);
-}
-
-TEST_F(LlvmLibcExpfTest, Overflow) {
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::expf(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::expf(FPBits(0x42cffff8U).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-
-  EXPECT_FP_EQ_WITH_EXCEPTION(
-      inf, LIBC_NAMESPACE::expf(FPBits(0x42d00008U).get_val()), FE_OVERFLOW);
-  EXPECT_MATH_ERRNO(ERANGE);
-}
+class ExpfTest : public LIBC_NAMESPACE::testing::FPTest<float> {
+public:
+  void test_special_numbers(float (*func)(float),
+                            bool check_snan_invalid = false,
+                            bool check_errno = true) {
+    if (check_snan_invalid) {
+      EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, func(sNaN), FE_INVALID);
+    } else {
+      EXPECT_FP_EQ(aNaN, func(sNaN));
+    }
+    if (check_errno)
+      EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(aNaN));
+    if (check_errno)
+      EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ_ALL_ROUNDING(inf, func(inf));
+    if (check_errno)
+      EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ_ALL_ROUNDING(0.0f, func(neg_inf));
+    if (check_errno)
+      EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ_ALL_ROUNDING(1.0f, func(0.0f));
+    if (check_errno)
+      EXPECT_MATH_ERRNO(0);
+
+    EXPECT_FP_EQ_ALL_ROUNDING(1.0f, func(-0.0f));
+    if (check_errno)
+      EXPECT_MATH_ERRNO(0);
+  }
+
+  void test_overflow(float (*func)(float),
+                     bool check_exception_and_errno = true) {
+    constexpr float VALUES[] = {
+        FPBits(0x7f7fffffU).get_val(),
+        FPBits(0x42cffff8U).get_val(),
+        FPBits(0x42d00008U).get_val(),
+    };
+    for (float x : VALUES) {
+      if (check_exception_and_errno) {
+        EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(x), FE_OVERFLOW);
+        EXPECT_MATH_ERRNO(ERANGE);
+      } else {
+        EXPECT_FP_EQ(inf, func(x));
+      }
+    }
+  }
 
 #ifdef LIBC_TEST_FTZ_DAZ
+  void test_denormals(float (*func)(float)) {
+    EXPECT_FP_EQ(1.0f, func(min_denormal));
+    EXPECT_FP_EQ(1.0f, func(max_denormal));
+  }
+#endif // LIBC_TEST_FTZ_DAZ
+};
 
-using namespace LIBC_NAMESPACE::testing;
-
-TEST_F(LlvmLibcExpfTest, FTZMode) {
-  ModifyMXCSR mxcsr(FTZ);
-
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::expf(min_denormal));
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::expf(max_denormal));
-}
-
-TEST_F(LlvmLibcExpfTest, DAZMode) {
-  ModifyMXCSR mxcsr(DAZ);
-
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::expf(min_denormal));
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::expf(max_denormal));
-}
-
-TEST_F(LlvmLibcExpfTest, FTZDAZMode) {
-  ModifyMXCSR mxcsr(FTZ | DAZ);
-
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::expf(min_denormal));
-  EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::expf(max_denormal));
+#ifdef LIBC_TEST_FTZ_DAZ
+#define LIST_EXPF_FTZ_DAZ_TESTS(suffix, func)                                  \
+  TEST_F(LlvmLibcExpfTest##suffix, FTZMode) {                                  \
+    LIBC_NAMESPACE::testing::ModifyMXCSR mxcsr(LIBC_NAMESPACE::testing::FTZ);  \
+    test_denormals(&func);                                                     \
+  }                                                                            \
+  TEST_F(LlvmLibcExpfTest##suffix, DAZMode) {                                  \
+    LIBC_NAMESPACE::testing::ModifyMXCSR mxcsr(LIBC_NAMESPACE::testing::DAZ);  \
+    test_denormals(&func);                                                     \
+  }                                                                            \
+  TEST_F(LlvmLibcExpfTest##suffix, FTZDAZMode) {                               \
+    LIBC_NAMESPACE::testing::ModifyMXCSR mxcsr(LIBC_NAMESPACE::testing::FTZ |  \
+                                               LIBC_NAMESPACE::testing::DAZ);  \
+    test_denormals(&func);                                                     \
+  }
+#else // !LIBC_TEST_FTZ_DAZ
+#define LIST_EXPF_FTZ_DAZ_TESTS(suffix, func)
+#endif // LIBC_TEST_FTZ_DAZ
+
+#define LIST_EXPF_TESTS(suffix, func, check_snan_invalid,                      \
+                        check_exception_and_errno, check_errno)                \
+  using LlvmLibcExpfTest##suffix = ExpfTest;                                   \
+  TEST_F(LlvmLibcExpfTest##suffix, SpecialNumbers) {                           \
+    test_special_numbers(&func, check_snan_invalid, check_errno);              \
+  }                                                                            \
+  TEST_F(LlvmLibcExpfTest##suffix, Overflow) {                                 \
+    test_overflow(&func, check_exception_and_errno);                           \
+  }                                                                            \
+  LIST_EXPF_FTZ_DAZ_TESTS(suffix, func)
+
+LIST_EXPF_TESTS(Default, LIBC_NAMESPACE::expf, /*check_snan_invalid=*/true,
+                /*check_exception_and_errno=*/true, /*check_errno=*/true)
+LIST_EXPF_TESTS(DoubleEval, LIBC_NAMESPACE::math::double_eval::expf,
+                /*check_snan_invalid=*/false,
+                /*check_exception_and_errno=*/true, /*check_errno=*/true)
+LIST_EXPF_TESTS(FloatEval, LIBC_NAMESPACE::math::float_eval::expf,
+                /*check_snan_invalid=*/false,
+                /*check_exception_and_errno=*/true, /*check_errno=*/true)
+LIST_EXPF_TESTS(IntegerEval, LIBC_NAMESPACE::math::integer_eval::expf,
+                /*check_snan_invalid=*/false,
+                /*check_exception_and_errno=*/false, /*check_errno=*/false)
+
+static float expf_static_rounding(float x) {
+  return LIBC_NAMESPACE::shared::math::static_rounding::expf(
+      x, LIBC_NAMESPACE::fputil::quick_get_round());
 }
 
-#endif
+LIST_EXPF_TESTS(StaticRounding, expf_static_rounding,
+                /*check_snan_invalid=*/false,
+                /*check_exception_and_errno=*/false, /*check_errno=*/false)

>From ab0b77c8c03fb3bde8031ae3c5afcbd2bcfb9d8e Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Sat, 19 Sep 2026 02:40:43 +0000
Subject: [PATCH 2/3] Remove redundant typename.

---
 libc/src/__support/math/exp10f_double_eval.h | 2 +-
 libc/src/__support/math/exp10f_float_eval.h  | 2 +-
 libc/src/__support/math/exp2f_double_eval.h  | 2 +-
 libc/src/__support/math/exp2f_float_eval.h   | 2 +-
 libc/src/__support/math/expf_double_eval.h   | 2 +-
 libc/src/__support/math/expf_float_eval.h    | 2 +-
 libc/src/__support/math/expf_integer_eval.h  | 2 +-
 7 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/libc/src/__support/math/exp10f_double_eval.h b/libc/src/__support/math/exp10f_double_eval.h
index 03e3790c87e70..e1a7cc9d68e98 100644
--- a/libc/src/__support/math/exp10f_double_eval.h
+++ b/libc/src/__support/math/exp10f_double_eval.h
@@ -28,7 +28,7 @@ namespace math {
 namespace double_eval {
 
 LIBC_INLINE float exp10f(float x) {
-  using FPBits = typename fputil::FPBits<float>;
+  using FPBits = fputil::FPBits<float>;
   FPBits xbits(x);
 
   uint32_t x_u = xbits.uintval();
diff --git a/libc/src/__support/math/exp10f_float_eval.h b/libc/src/__support/math/exp10f_float_eval.h
index 19bbfb93a509e..304d3e310234c 100644
--- a/libc/src/__support/math/exp10f_float_eval.h
+++ b/libc/src/__support/math/exp10f_float_eval.h
@@ -31,7 +31,7 @@ namespace math {
 namespace float_eval {
 
 LIBC_INLINE float exp10f(float x) {
-  using FPBits = typename fputil::FPBits<float>;
+  using FPBits = fputil::FPBits<float>;
   FPBits xbits(x);
 
   uint32_t x_u = xbits.uintval();
diff --git a/libc/src/__support/math/exp2f_double_eval.h b/libc/src/__support/math/exp2f_double_eval.h
index 821e726d012d3..e0387f32e193f 100644
--- a/libc/src/__support/math/exp2f_double_eval.h
+++ b/libc/src/__support/math/exp2f_double_eval.h
@@ -32,7 +32,7 @@ namespace math {
 namespace double_eval {
 
 LIBC_INLINE float exp2f(float x) {
-  using FPBits = typename fputil::FPBits<float>;
+  using FPBits = fputil::FPBits<float>;
   FPBits xbits(x);
 
   uint32_t x_u = xbits.uintval();
diff --git a/libc/src/__support/math/exp2f_float_eval.h b/libc/src/__support/math/exp2f_float_eval.h
index 8298ae7b18add..d1ea060478f6f 100644
--- a/libc/src/__support/math/exp2f_float_eval.h
+++ b/libc/src/__support/math/exp2f_float_eval.h
@@ -29,7 +29,7 @@ namespace math {
 namespace float_eval {
 
 LIBC_INLINE float exp2f(float x) {
-  using FPBits = typename fputil::FPBits<float>;
+  using FPBits = fputil::FPBits<float>;
   FPBits xbits(x);
 
   uint32_t x_u = xbits.uintval();
diff --git a/libc/src/__support/math/expf_double_eval.h b/libc/src/__support/math/expf_double_eval.h
index 8a990bd67c265..12f745a4bc60a 100644
--- a/libc/src/__support/math/expf_double_eval.h
+++ b/libc/src/__support/math/expf_double_eval.h
@@ -30,7 +30,7 @@ namespace math {
 namespace double_eval {
 
 LIBC_INLINE float expf(float x) {
-  using FPBits = typename fputil::FPBits<float>;
+  using FPBits = fputil::FPBits<float>;
   FPBits xbits(x);
 
   uint32_t x_u = xbits.uintval();
diff --git a/libc/src/__support/math/expf_float_eval.h b/libc/src/__support/math/expf_float_eval.h
index 5561e9d8e06f8..e479cb58d2fea 100644
--- a/libc/src/__support/math/expf_float_eval.h
+++ b/libc/src/__support/math/expf_float_eval.h
@@ -31,7 +31,7 @@ namespace math {
 namespace float_eval {
 
 LIBC_INLINE float expf(float x) {
-  using FPBits = typename fputil::FPBits<float>;
+  using FPBits = fputil::FPBits<float>;
   FPBits xbits(x);
 
   uint32_t x_u = xbits.uintval();
diff --git a/libc/src/__support/math/expf_integer_eval.h b/libc/src/__support/math/expf_integer_eval.h
index c072abaf96955..52736323d8d7e 100644
--- a/libc/src/__support/math/expf_integer_eval.h
+++ b/libc/src/__support/math/expf_integer_eval.h
@@ -59,7 +59,7 @@ LIBC_INLINE_VAR constexpr Frac64 EXPF_COEFFS[] = {
 // Statically rounded, no except implementation of expf using integer-only
 // arithmetic.
 LIBC_INLINE float expf(float x, [[maybe_unused]] int rounding) {
-  using FPBits = typename fputil::FPBits<float>;
+  using FPBits = fputil::FPBits<float>;
   using FPBounds = LIBC_NAMESPACE::math::check::exp_internal::Bounds<float>;
   FPBits xbits(x);
 

>From b5a7c89118bc3d4439211cf487959fb2a6917ff0 Mon Sep 17 00:00:00 2001
From: lntue <lntue.h at gmail.com>
Date: Sat, 19 Sep 2026 09:14:24 -0400
Subject: [PATCH 3/3] Update libc/test/src/math/exhaustive/CMakeLists.txt

Co-authored-by: Muhammad Bassiouni <60100307+bassiounix at users.noreply.github.com>
---
 libc/test/src/math/exhaustive/CMakeLists.txt | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libc/test/src/math/exhaustive/CMakeLists.txt b/libc/test/src/math/exhaustive/CMakeLists.txt
index 2d42bee4c6540..23a66e28cf17f 100644
--- a/libc/test/src/math/exhaustive/CMakeLists.txt
+++ b/libc/test/src/math/exhaustive/CMakeLists.txt
@@ -710,7 +710,6 @@ add_fp_unittest(
     libc.src.__support.math.atanf
 )
 
-
 add_fp_unittest(
   asinf_test
   NO_RUN_POSTBUILD



More information about the libc-commits mailing list