[libcxx-commits] [libcxx] db2944e - [libc++][format] Adds formatter floating-point.

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jan 24 09:12:35 PST 2022


Author: Mark de Wever
Date: 2022-01-24T18:12:24+01:00
New Revision: db2944e34b16387bf4326ddfd2a8c420594572f4

URL: https://github.com/llvm/llvm-project/commit/db2944e34b16387bf4326ddfd2a8c420594572f4
DIFF: https://github.com/llvm/llvm-project/commit/db2944e34b16387bf4326ddfd2a8c420594572f4.diff

LOG: [libc++][format] Adds formatter floating-point.

This properly implements the formatter for floating-point types.

Completes:
- P1652R1 Printf corner cases in std::format
- LWG 3250 std::format: # (alternate form) for NaN and inf
- LWG 3243 std::format and negative zeroes

Implements parts of:
- P0645 Text Formatting

Reviewed By: #libc, ldionne, vitaut

Differential Revision: https://reviews.llvm.org/D114001

Added: 
    libcxx/benchmarks/formatter_float.bench.cpp
    libcxx/include/__format/formatter_floating_point.h
    libcxx/test/libcxx/diagnostics/detail.headers/format/formatter_floating_point.module.verify.cpp
    libcxx/test/libcxx/utilities/format/format.string/format.string.std/std_format_spec_floating_point.pass.cpp

Modified: 
    libcxx/docs/Status/Cxx20Issues.csv
    libcxx/docs/Status/Cxx20Papers.csv
    libcxx/include/CMakeLists.txt
    libcxx/include/__format/formatter.h
    libcxx/include/__format/formatter_integral.h
    libcxx/include/__format/parser_std_format_spec.h
    libcxx/include/format
    libcxx/include/module.modulemap
    libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.floating_point.pass.cpp
    libcxx/test/std/utilities/format/format.functions/format_tests.h
    libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/benchmarks/formatter_float.bench.cpp b/libcxx/benchmarks/formatter_float.bench.cpp
new file mode 100644
index 0000000000000..3190b3779c5d9
--- /dev/null
+++ b/libcxx/benchmarks/formatter_float.bench.cpp
@@ -0,0 +1,241 @@
+//===----------------------------------------------------------------------===//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include <format>
+
+#include <array>
+#include <limits>
+#include <random>
+#include <string>
+
+#include "CartesianBenchmarks.h"
+#include "benchmark/benchmark.h"
+
+// *** Localization ***
+enum class LocalizationE { False, True };
+struct AllLocalizations : EnumValuesAsTuple<AllLocalizations, LocalizationE, 2> {
+  static constexpr const char* Names[] = {"LocFalse", "LocTrue"};
+};
+
+template <LocalizationE E>
+struct Localization {};
+
+template <>
+struct Localization<LocalizationE::False> {
+  static constexpr const char* fmt = "";
+};
+
+template <>
+struct Localization<LocalizationE::True> {
+  static constexpr const char* fmt = "L";
+};
+
+// *** Types ***
+enum class TypeE { Float, Double, LongDouble };
+// TODO FMT Set to 3 after to_chars has long double suport.
+struct AllTypes : EnumValuesAsTuple<AllTypes, TypeE, 2> {
+  static constexpr const char* Names[] = {"Float", "Double", "LongDouble"};
+};
+
+template <TypeE E>
+struct Type {};
+
+template <>
+struct Type<TypeE::Float> {
+  using type = float;
+};
+
+template <>
+struct Type<TypeE::Double> {
+  using type = double;
+};
+
+template <>
+struct Type<TypeE::LongDouble> {
+  using type = long double;
+};
+
+// *** Values ***
+enum class ValueE { Inf, Random };
+struct AllValues : EnumValuesAsTuple<AllValues, ValueE, 2> {
+  static constexpr const char* Names[] = {"Inf", "Random"};
+};
+
+template <ValueE E>
+struct Value {};
+
+template <>
+struct Value<ValueE::Inf> {
+  template <class F>
+  static std::array<F, 1000> make_data() {
+    std::array<F, 1000> result;
+    std::fill(result.begin(), result.end(), -std::numeric_limits<F>::infinity());
+    return result;
+  }
+};
+
+template <>
+struct Value<ValueE::Random> {
+  template <class F>
+  static std::array<F, 1000> make_data() {
+    std::random_device seed;
+    std::mt19937 generator(seed());
+    std::uniform_int_distribution<std::conditional_t<sizeof(F) == sizeof(uint32_t), uint32_t, uint64_t>> distribution;
+
+    std::array<F, 1000> result;
+    std::generate(result.begin(), result.end(), [&] {
+      while (true) {
+        auto result = std::bit_cast<F>(distribution(generator));
+        if (std::isfinite(result))
+          return result;
+      }
+    });
+    return result;
+  }
+};
+
+// *** Display Type ***
+enum class DisplayTypeE {
+  Default,
+  Hex,
+  Scientific,
+  Fixed,
+  General,
+};
+struct AllDisplayTypes : EnumValuesAsTuple<AllDisplayTypes, DisplayTypeE, 5> {
+  static constexpr const char* Names[] = {"DisplayDefault", "DisplayHex", "DisplayScientific", "DisplayFixed",
+                                          "DisplayGeneral"};
+};
+
+template <DisplayTypeE E>
+struct DisplayType {};
+
+template <>
+struct DisplayType<DisplayTypeE::Default> {
+  static constexpr const char* fmt = "";
+};
+
+template <>
+struct DisplayType<DisplayTypeE::Hex> {
+  static constexpr const char* fmt = "a";
+};
+
+template <>
+struct DisplayType<DisplayTypeE::Scientific> {
+  static constexpr const char* fmt = "e";
+};
+
+template <>
+struct DisplayType<DisplayTypeE::Fixed> {
+  static constexpr const char* fmt = "f";
+};
+
+template <>
+struct DisplayType<DisplayTypeE::General> {
+  static constexpr const char* fmt = "g";
+};
+
+// *** Alignment ***
+enum class AlignmentE { None, Left, Center, Right, ZeroPadding };
+struct AllAlignments : EnumValuesAsTuple<AllAlignments, AlignmentE, 5> {
+  static constexpr const char* Names[] = {"AlignNone", "AlignmentLeft", "AlignmentCenter", "AlignmentRight",
+                                          "ZeroPadding"};
+};
+
+template <AlignmentE E>
+struct Alignment {};
+
+template <>
+struct Alignment<AlignmentE::None> {
+  static constexpr const char* fmt = "";
+};
+
+template <>
+struct Alignment<AlignmentE::Left> {
+  // Width > PrecisionE::Huge
+  static constexpr const char* fmt = "0<17500";
+};
+
+template <>
+struct Alignment<AlignmentE::Center> {
+  // Width > PrecisionE::Huge
+  static constexpr const char* fmt = "0^17500";
+};
+
+template <>
+struct Alignment<AlignmentE::Right> {
+  // Width > PrecisionE::Huge
+  static constexpr const char* fmt = "0>17500";
+};
+
+template <>
+struct Alignment<AlignmentE::ZeroPadding> {
+  // Width > PrecisionE::Huge
+  static constexpr const char* fmt = "017500";
+};
+
+enum class PrecisionE { None, Zero, Small, Huge };
+struct AllPrecisions : EnumValuesAsTuple<AllPrecisions, PrecisionE, 4> {
+  static constexpr const char* Names[] = {"PrecNone", "PrecZero", "PrecSmall", "PrecHuge"};
+};
+
+template <PrecisionE E>
+struct Precision {};
+
+template <>
+struct Precision<PrecisionE::None> {
+  static constexpr const char* fmt = "";
+};
+
+template <>
+struct Precision<PrecisionE::Zero> {
+  static constexpr const char* fmt = ".0";
+};
+
+template <>
+struct Precision<PrecisionE::Small> {
+  static constexpr const char* fmt = ".10";
+};
+
+template <>
+struct Precision<PrecisionE::Huge> {
+  // The maximum precision for a minimal sub normal long double is ±0x1p-16494.
+  // This value is always larger than that value forcing the trailing zero path
+  // to be executed.
+  static constexpr const char* fmt = ".17000";
+};
+
+template <class L, class DT, class T, class V, class A, class P>
+struct FloatingPoint {
+  using F = typename Type<T::value>::type;
+
+  void run(benchmark::State& state) const {
+    std::array<F, 1000> data{Value<V::value>::template make_data<F>()};
+    std::array<char, 20'000> output;
+    std::string fmt{std::string("{:") + Alignment<A::value>::fmt + Precision<P::value>::fmt +
+                    Localization<L::value>::fmt + DisplayType<DT::value>::fmt + "}"};
+
+    while (state.KeepRunningBatch(1000))
+      for (F value : data)
+        benchmark::DoNotOptimize(std::format_to(output.begin(), fmt, value));
+  }
+
+  std::string name() const {
+    return "FloatingPoint" + L::name() + DT::name() + T::name() + V::name() + A::name() + P::name();
+  }
+};
+
+int main(int argc, char** argv) {
+  benchmark::Initialize(&argc, argv);
+  if (benchmark::ReportUnrecognizedArguments(argc, argv))
+    return 1;
+
+  makeCartesianProductBenchmark<FloatingPoint, AllLocalizations, AllDisplayTypes, AllTypes, AllValues, AllAlignments,
+                                AllPrecisions>();
+
+  benchmark::RunSpecifiedBenchmarks();
+}

diff  --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv
index f93e66fda1849..034fac3ca22f8 100644
--- a/libcxx/docs/Status/Cxx20Issues.csv
+++ b/libcxx/docs/Status/Cxx20Issues.csv
@@ -203,10 +203,10 @@
 "`3237 <https://wg21.link/LWG3237>`__","LWG 3038 and 3190 have inconsistent PRs","Prague","|Complete|","14.0"
 "`3238 <https://wg21.link/LWG3238>`__","Insufficiently-defined behavior of ``std::function``\  deduction guides","Prague","",""
 "`3242 <https://wg21.link/LWG3242>`__","``std::format``\ : missing rules for ``arg-id``\  in ``width``\  and ``precision``\ ","Prague","|Complete|","Clang 14","|format|"
-"`3243 <https://wg21.link/LWG3243>`__","``std::format``\  and negative zeroes","Prague","","","|format|"
+"`3243 <https://wg21.link/LWG3243>`__","``std::format``\  and negative zeroes","Prague","|Complete|","14.0","|format|"
 "`3247 <https://wg21.link/LWG3247>`__","``ranges::iter_move``\  should perform ADL-only lookup of ``iter_move``\ ","Prague","","","|ranges|"
 "`3248 <https://wg21.link/LWG3248>`__","``std::format``\  ``#b``\ , ``#B``\ , ``#o``\ , ``#x``\ , and ``#X``\   presentation types misformat negative numbers","Prague","|Complete|","14.0","|format|"
-"`3250 <https://wg21.link/LWG3250>`__","``std::format``\ : ``#``\  (alternate form) for NaN and inf","Prague","","","|format|"
+"`3250 <https://wg21.link/LWG3250>`__","``std::format``\ : ``#``\  (alternate form) for NaN and inf","Prague","|Complete|","14.0","|format|"
 "`3251 <https://wg21.link/LWG3251>`__","Are ``std::format``\  alignment specifiers applied to string arguments?","Prague","","","|format|"
 "`3252 <https://wg21.link/LWG3252>`__","Parse locale's aware modifiers for commands are not consistent with POSIX spec","Prague","","","|chrono|"
 "`3254 <https://wg21.link/LWG3254>`__","Strike ``stop_token``\ 's ``operator!=``\ ","Prague","",""

diff  --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv
index d0927e09426ce..5a974a798f7bd 100644
--- a/libcxx/docs/Status/Cxx20Papers.csv
+++ b/libcxx/docs/Status/Cxx20Papers.csv
@@ -129,7 +129,7 @@
 "`P1644R0 <https://wg21.link/P1644R0>`__","LWG","Add wait/notify to atomic<shared_ptr>","Cologne","",""
 "`P1650R0 <https://wg21.link/P1650R0>`__","LWG","Output std::chrono::days with 'd' suffix","Cologne","",""
 "`P1651R0 <https://wg21.link/P1651R0>`__","LWG","bind_front should not unwrap reference_wrapper","Cologne","|Complete|","13.0"
-"`P1652R1 <https://wg21.link/P1652R1>`__","LWG","Printf corner cases in std::format","Cologne","|In Progress|",""
+"`P1652R1 <https://wg21.link/P1652R1>`__","LWG","Printf corner cases in std::format","Cologne","|Complete|","14.0"
 "`P1661R1 <https://wg21.link/P1661R1>`__","LWG","Remove dedicated precalculated hash lookup interface","Cologne","|Nothing To Do|",""
 "`P1754R1 <https://wg21.link/P1754R1>`__","LWG","Rename concepts to standard_case for C++20, while we still can","Cologne","|In Progress|",""
 "","","","","",""

diff  --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index b7222540846fa..3886ddba8e4e5 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -178,6 +178,7 @@ set(files
   __format/formatter.h
   __format/formatter_bool.h
   __format/formatter_char.h
+  __format/formatter_floating_point.h
   __format/formatter_integer.h
   __format/formatter_integral.h
   __format/formatter_string.h

diff  --git a/libcxx/include/__format/formatter.h b/libcxx/include/__format/formatter.h
index 1adce75a86110..0c0c02ba19173 100644
--- a/libcxx/include/__format/formatter.h
+++ b/libcxx/include/__format/formatter.h
@@ -190,6 +190,34 @@ __write(output_iterator<const _CharT&> auto __out_it, const _CharT* __first,
   return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after, __fill);
 }
 
+/**
+ * @overload
+ *
+ * Writes additional zero's for the precision before the exponent.
+ * This is used when the precision requested in the format string is larger
+ * than the maximum precision of the floating-point type. These precision
+ * digits are always 0.
+ *
+ * @param __exponent           The location of the exponent character.
+ * @param __num_trailing_zeros The number of 0's to write before the exponent
+ *                             character.
+ */
+template <class _CharT, class _Fill>
+_LIBCPP_HIDE_FROM_ABI auto __write(output_iterator<const _CharT&> auto __out_it, const _CharT* __first,
+                                   const _CharT* __last, size_t __size, size_t __width, _Fill __fill,
+                                   __format_spec::_Flags::_Alignment __alignment, const _CharT* __exponent,
+                                   size_t __num_trailing_zeros) -> decltype(__out_it) {
+  _LIBCPP_ASSERT(__first <= __last, "Not a valid range");
+  _LIBCPP_ASSERT(__num_trailing_zeros > 0, "The overload not writing trailing zeros should have been used");
+
+  __padding_size_result __padding = __padding_size(__size + __num_trailing_zeros, __width, __alignment);
+  __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __padding.__before, __fill);
+  __out_it = _VSTD::copy(__first, __exponent, _VSTD::move(__out_it));
+  __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __num_trailing_zeros, _CharT('0'));
+  __out_it = _VSTD::copy(__exponent, __last, _VSTD::move(__out_it));
+  return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after, __fill);
+}
+
 /**
  * @overload
  *

diff  --git a/libcxx/include/__format/formatter_floating_point.h b/libcxx/include/__format/formatter_floating_point.h
new file mode 100644
index 0000000000000..2e710b409deb6
--- /dev/null
+++ b/libcxx/include/__format/formatter_floating_point.h
@@ -0,0 +1,717 @@
+// -*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___FORMAT_FORMATTER_FLOATING_POINT_H
+#define _LIBCPP___FORMAT_FORMATTER_FLOATING_POINT_H
+
+#include <__algorithm/copy.h>
+#include <__algorithm/copy_n.h>
+#include <__algorithm/fill_n.h>
+#include <__algorithm/find.h>
+#include <__algorithm/min.h>
+#include <__algorithm/rotate.h>
+#include <__algorithm/transform.h>
+#include <__concepts/arithmetic.h>
+#include <__config>
+#include <__debug>
+#include <__format/format_error.h>
+#include <__format/format_fwd.h>
+#include <__format/format_string.h>
+#include <__format/formatter.h>
+#include <__format/formatter_integral.h>
+#include <__format/parser_std_format_spec.h>
+#include <__utility/move.h>
+#include <charconv>
+#include <cmath>
+
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+#  include <locale>
+#endif
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER > 17
+
+// TODO FMT Remove this once we require compilers with proper C++20 support.
+// If the compiler has no concepts support, the format header will be disabled.
+// Without concepts support enable_if needs to be used and that too much effort
+// to support compilers with partial C++20 support.
+#  if !defined(_LIBCPP_HAS_NO_CONCEPTS)
+
+namespace __format_spec {
+
+template <floating_point _Tp>
+_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value) {
+  to_chars_result __r = _VSTD::to_chars(__first, __last, __value);
+  _LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small");
+  return __r.ptr;
+}
+
+template <floating_point _Tp>
+_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, chars_format __fmt) {
+  to_chars_result __r = _VSTD::to_chars(__first, __last, __value, __fmt);
+  _LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small");
+  return __r.ptr;
+}
+
+template <floating_point _Tp>
+_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, chars_format __fmt, int __precision) {
+  to_chars_result __r = _VSTD::to_chars(__first, __last, __value, __fmt, __precision);
+  _LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small");
+  return __r.ptr;
+}
+
+// https://en.cppreference.com/w/cpp/language/types#cite_note-1
+// float             min subnormal: +/-0x1p-149   max: +/- 3.402,823,4 10^38
+// double            min subnormal: +/-0x1p-1074  max  +/- 1.797,693,134,862,315,7 10^308
+// long double (x86) min subnormal: +/-0x1p-16446 max: +/- 1.189,731,495,357,231,765,021 10^4932
+//
+// The maximum number of digits required for the integral part is based on the
+// maximum's value power of 10. Every power of 10 requires one additional
+// decimal digit.
+// The maximum number of digits required for the fractional part is based on
+// the minimal subnormal hexadecimal output's power of 10. Every division of a
+// fraction's binary 1 by 2, requires one additional decimal digit.
+//
+// The maximum size of a formatted value depends on the selected output format.
+// Ignoring the fact the format string can request a precision larger than the
+// values maximum required, these values are:
+//
+// sign                    1 code unit
+// __max_integral
+// radix point             1 code unit
+// __max_fractional
+// exponent character      1 code unit
+// sign                    1 code unit
+// __max_fractional_value
+// -----------------------------------
+// total                   4 code units extra required.
+//
+// TODO FMT Optimize the storage to avoid storing digits that are known to be zero.
+// https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/
+
+// TODO FMT Add long double specialization when to_chars has proper long double support.
+template <class _Tp>
+struct __traits;
+
+template <floating_point _Fp>
+static constexpr size_t __float_buffer_size(int __precision) {
+  using _Traits = __traits<_Fp>;
+  return 4 + _Traits::__max_integral + __precision + _Traits::__max_fractional_value;
+}
+
+template <>
+struct __traits<float> {
+  static constexpr int __max_integral = 38;
+  static constexpr int __max_fractional = 149;
+  static constexpr int __max_fractional_value = 3;
+  static constexpr size_t __stack_buffer_size = 256;
+
+  static constexpr int __hex_precision_digits = 3;
+};
+
+template <>
+struct __traits<double> {
+  static constexpr int __max_integral = 308;
+  static constexpr int __max_fractional = 1074;
+  static constexpr int __max_fractional_value = 4;
+  static constexpr size_t __stack_buffer_size = 1024;
+
+  static constexpr int __hex_precision_digits = 4;
+};
+
+/// Helper class to store the conversion buffer.
+///
+/// Depending on the maxium size required for a value, the buffer is allocated
+/// on the stack or the heap.
+template <floating_point _Fp>
+class _LIBCPP_TEMPLATE_VIS __float_buffer {
+  using _Traits = __traits<_Fp>;
+
+public:
+  // TODO FMT Improve this constructor to do a better estimate.
+  // When using a scientific formatting with a precision of 6 a stack buffer
+  // will always suffice. At the moment that isn't important since floats and
+  // doubles use a stack buffer, unless the precision used in the format string
+  // is large.
+  // When supporting long doubles the __max_integral part becomes 4932 which
+  // may be too much for some platforms. For these cases a better estimate is
+  // required.
+  explicit _LIBCPP_HIDE_FROM_ABI __float_buffer(int __precision)
+      : __precision_(__precision != -1 ? __precision : _Traits::__max_fractional) {
+
+    // When the precision is larger than _Traits::__max_fractional the digits in
+    // the range (_Traits::__max_fractional, precision] will contain the value
+    // zero. There's no need to request to_chars to write these zeros:
+    // - When the value is large a temporary heap buffer needs to be allocated.
+    // - When to_chars writes the values they need to be "copied" to the output:
+    //   - char: std::fill on the output iterator is faster than std::copy.
+    //   - wchar_t: same argument as char, but additional std::copy won't work.
+    //     The input is always a char buffer, so every char in the buffer needs
+    //     to be converted from a char to a wchar_t.
+    if (__precision_ > _Traits::__max_fractional) {
+      __num_trailing_zeros_ = __precision_ - _Traits::__max_fractional;
+      __precision_ = _Traits::__max_fractional;
+    }
+
+    __size_ = __format_spec::__float_buffer_size<_Fp>(__precision_);
+    if (__size_ > _Traits::__stack_buffer_size)
+      // The allocated buffer's contents don't need initialization.
+      __begin_ = allocator<char>{}.allocate(__size_);
+    else
+      __begin_ = __buffer_;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI ~__float_buffer() {
+    if (__size_ > _Traits::__stack_buffer_size)
+      allocator<char>{}.deallocate(__begin_, __size_);
+  }
+  _LIBCPP_HIDE_FROM_ABI __float_buffer(const __float_buffer&) = delete;
+  _LIBCPP_HIDE_FROM_ABI __float_buffer& operator=(const __float_buffer&) = delete;
+
+  _LIBCPP_HIDE_FROM_ABI char* begin() const { return __begin_; }
+  _LIBCPP_HIDE_FROM_ABI char* end() const { return __begin_ + __size_; }
+
+  _LIBCPP_HIDE_FROM_ABI int __precision() const { return __precision_; }
+  _LIBCPP_HIDE_FROM_ABI int __num_trailing_zeros() const { return __num_trailing_zeros_; }
+  _LIBCPP_HIDE_FROM_ABI void __remove_trailing_zeros() { __num_trailing_zeros_ = 0; }
+
+private:
+  int __precision_;
+  int __num_trailing_zeros_{0};
+  size_t __size_;
+  char* __begin_;
+  char __buffer_[_Traits::__stack_buffer_size];
+};
+
+struct __float_result {
+  /// Points at the beginning of the integral part in the buffer.
+  ///
+  /// When there's no sign character this points at the start of the buffer.
+  char* __integral;
+
+  /// Points at the radix point, when not present it's the same as \ref __last.
+  char* __radix_point;
+
+  /// Points at the exponent character, when not present it's the same as \ref __last.
+  char* __exponent;
+
+  /// Points beyond the last written element in the buffer.
+  char* __last;
+};
+
+/// Finds the position of the exponent character 'e' at the end of the buffer.
+///
+/// Assuming there is an exponent the input will terminate with
+/// eSdd and eSdddd (S = sign, d = digit)
+///
+/// \returns a pointer to the exponent or __last when not found.
+constexpr inline _LIBCPP_HIDE_FROM_ABI char* __find_exponent(char* __first, char* __last) {
+  ptr
diff _t __size = __last - __first;
+  if (__size > 4) {
+    __first = __last - _VSTD::min(__size, ptr
diff _t(6));
+    for (; __first != __last - 3; ++__first) {
+      if (*__first == 'e')
+        return __first;
+    }
+  }
+  return __last;
+}
+
+template <class _Fp, class _Tp>
+_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_default(const __float_buffer<_Fp>& __buffer, _Tp __value,
+                                                             char* __integral) {
+  __float_result __result;
+  __result.__integral = __integral;
+  __result.__last = __format_spec::__to_buffer(__integral, __buffer.end(), __value);
+
+  __result.__exponent = __format_spec::__find_exponent(__result.__integral, __result.__last);
+
+  // Constrains:
+  // - There's at least one decimal digit before the radix point.
+  // - The radix point, when present, is placed before the exponent.
+  __result.__radix_point = _VSTD::find(__result.__integral + 1, __result.__exponent, '.');
+
+  // When the radix point isn't found its position is the exponent instead of
+  // __result.__last.
+  if (__result.__radix_point == __result.__exponent)
+    __result.__radix_point = __result.__last;
+
+  // clang-format off
+  _LIBCPP_ASSERT((__result.__integral != __result.__last) &&
+                 (__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
+                 (__result.__exponent == __result.__last || *__result.__exponent == 'e'),
+                 "Post-condition failure.");
+  // clang-format on
+
+  return __result;
+}
+
+template <class _Fp, class _Tp>
+_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_hexadecimal_lower_case(const __float_buffer<_Fp>& __buffer,
+                                                                            _Tp __value, int __precision,
+                                                                            char* __integral) {
+  __float_result __result;
+  __result.__integral = __integral;
+  if (__precision == -1)
+    __result.__last = __format_spec::__to_buffer(__integral, __buffer.end(), __value, chars_format::hex);
+  else
+    __result.__last = __format_spec::__to_buffer(__integral, __buffer.end(), __value, chars_format::hex, __precision);
+
+  // H = one or more hex-digits
+  // S = sign
+  // D = one or more decimal-digits
+  // When the fractional part is zero and no precision the output is 0p+0
+  // else the output is                                              0.HpSD
+  // So testing the second position can 
diff erentiate between these two cases.
+  char* __first = __integral + 1;
+  if (*__first == '.') {
+    __result.__radix_point = __first;
+    // One digit is the minimum
+    // 0.hpSd
+    //       ^-- last
+    //     ^---- integral = end of search
+    // ^-------- start of search
+    // 0123456
+    //
+    // Four digits is the maximum
+    // 0.hpSdddd
+    //          ^-- last
+    //        ^---- integral = end of search
+    //    ^-------- start of search
+    // 0123456789
+    static_assert(__traits<_Fp>::__hex_precision_digits <= 4, "Guard against possible underflow.");
+
+    char* __last = __result.__last - 2;
+    __first = __last - __traits<_Fp>::__hex_precision_digits;
+    __result.__exponent = _VSTD::find(__first, __last, 'p');
+  } else {
+    __result.__radix_point = __result.__last;
+    __result.__exponent = __first;
+  }
+
+  // clang-format off
+  _LIBCPP_ASSERT((__result.__integral != __result.__last) &&
+                 (__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
+                 (__result.__exponent != __result.__last && *__result.__exponent == 'p'),
+                 "Post-condition failure.");
+  // clang-format on
+
+  return __result;
+}
+
+template <class _Fp, class _Tp>
+_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_hexadecimal_upper_case(const __float_buffer<_Fp>& __buffer,
+                                                                            _Tp __value, int __precision,
+                                                                            char* __integral) {
+  __float_result __result =
+      __format_spec::__format_buffer_hexadecimal_lower_case(__buffer, __value, __precision, __integral);
+  _VSTD::transform(__result.__integral, __result.__exponent, __result.__integral, __hex_to_upper);
+  *__result.__exponent = 'P';
+  return __result;
+}
+
+template <class _Fp, class _Tp>
+_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_scientific_lower_case(const __float_buffer<_Fp>& __buffer,
+                                                                           _Tp __value, int __precision,
+                                                                           char* __integral) {
+  __float_result __result;
+  __result.__integral = __integral;
+  __result.__last =
+      __format_spec::__to_buffer(__integral, __buffer.end(), __value, chars_format::scientific, __precision);
+
+  char* __first = __integral + 1;
+  _LIBCPP_ASSERT(__first != __result.__last, "No exponent present");
+  if (*__first == '.') {
+    __result.__radix_point = __first;
+    __result.__exponent = __format_spec::__find_exponent(__first + 1, __result.__last);
+  } else {
+    __result.__radix_point = __result.__last;
+    __result.__exponent = __first;
+  }
+
+  // clang-format off
+  _LIBCPP_ASSERT((__result.__integral != __result.__last) &&
+                 (__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
+                 (__result.__exponent != __result.__last && *__result.__exponent == 'e'),
+                 "Post-condition failure.");
+  // clang-format on
+  return __result;
+}
+
+template <class _Fp, class _Tp>
+_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_scientific_upper_case(const __float_buffer<_Fp>& __buffer,
+                                                                           _Tp __value, int __precision,
+                                                                           char* __integral) {
+  __float_result __result =
+      __format_spec::__format_buffer_scientific_lower_case(__buffer, __value, __precision, __integral);
+  *__result.__exponent = 'E';
+  return __result;
+}
+
+template <class _Fp, class _Tp>
+_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_fixed(const __float_buffer<_Fp>& __buffer, _Tp __value,
+                                                           int __precision, char* __integral) {
+  __float_result __result;
+  __result.__integral = __integral;
+  __result.__last = __format_spec::__to_buffer(__integral, __buffer.end(), __value, chars_format::fixed, __precision);
+
+  // When there's no precision there's no radix point.
+  // Else the radix point is placed at __precision + 1 from the end.
+  // By converting __precision to a bool the subtraction can be done
+  // unconditionally.
+  __result.__radix_point = __result.__last - (__precision + bool(__precision));
+  __result.__exponent = __result.__last;
+
+  // clang-format off
+  _LIBCPP_ASSERT((__result.__integral != __result.__last) &&
+                 (__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
+                 (__result.__exponent == __result.__last),
+                 "Post-condition failure.");
+  // clang-format on
+  return __result;
+}
+
+template <class _Fp, class _Tp>
+_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_general_lower_case(__float_buffer<_Fp>& __buffer, _Tp __value,
+                                                                        int __precision, char* __integral) {
+
+  __buffer.__remove_trailing_zeros();
+
+  __float_result __result;
+  __result.__integral = __integral;
+  __result.__last = __format_spec::__to_buffer(__integral, __buffer.end(), __value, chars_format::general, __precision);
+
+  char* __first = __integral + 1;
+  if (__first == __result.__last) {
+    __result.__radix_point = __result.__last;
+    __result.__exponent = __result.__last;
+  } else {
+    __result.__exponent = __format_spec::__find_exponent(__first, __result.__last);
+    if (__result.__exponent != __result.__last)
+      // In scientific mode if there's a radix point it will always be after
+      // the first digit. (This is the position __first points at).
+      __result.__radix_point = *__first == '.' ? __first : __result.__last;
+    else {
+      // In fixed mode the algorithm truncates trailing spaces and possibly the
+      // radix point. There's no good guess for the position of the radix point
+      // therefore scan the output after the first digit.
+      __result.__radix_point = _VSTD::find(__first, __result.__last, '.');
+    }
+  }
+
+  // clang-format off
+  _LIBCPP_ASSERT((__result.__integral != __result.__last) &&
+                 (__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
+                 (__result.__exponent == __result.__last || *__result.__exponent == 'e'),
+                 "Post-condition failure.");
+  // clang-format on
+
+  return __result;
+}
+
+template <class _Fp, class _Tp>
+_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_general_upper_case(__float_buffer<_Fp>& __buffer, _Tp __value,
+                                                                        int __precision, char* __integral) {
+  __float_result __result =
+      __format_spec::__format_buffer_general_lower_case(__buffer, __value, __precision, __integral);
+  if (__result.__exponent != __result.__last)
+    *__result.__exponent = 'E';
+  return __result;
+}
+
+#    ifndef _LIBCPP_HAS_NO_LOCALIZATION
+template <class _OutIt, class _Fp, class _CharT>
+_LIBCPP_HIDE_FROM_ABI _OutIt __format_locale_specific_form(_OutIt __out_it, const __float_buffer<_Fp>& __buffer,
+                                                           const __float_result& __result, _VSTD::locale __loc,
+                                                           size_t __width, _Flags::_Alignment __alignment,
+                                                           _CharT __fill) {
+  const auto& __np = use_facet<numpunct<_CharT>>(__loc);
+  string __grouping = __np.grouping();
+  char* __first = __result.__integral;
+  // When no radix point or exponent are present __last will be __result.__last.
+  char* __last = _VSTD::min(__result.__radix_point, __result.__exponent);
+
+  ptr
diff _t __digits = __last - __first;
+  if (!__grouping.empty()) {
+    if (__digits <= __grouping[0])
+      __grouping.clear();
+    else
+      __grouping = __determine_grouping(__digits, __grouping);
+  }
+
+  size_t __size = __result.__last - __buffer.begin() + // Formatted string
+                  __buffer.__num_trailing_zeros() +    // Not yet rendered zeros
+                  __grouping.size() -                  // Grouping contains one
+                  !__grouping.empty();                 // additional character
+
+  __formatter::__padding_size_result __padding = {0, 0};
+  bool __zero_padding = __alignment == _Flags::_Alignment::__default;
+  if (__size < __width) {
+    if (__zero_padding) {
+      __alignment = _Flags::_Alignment::__right;
+      __fill = _CharT('0');
+    }
+
+    __padding = __formatter::__padding_size(__size, __width, __alignment);
+  }
+
+  // sign and (zero padding or alignment)
+  if (__zero_padding && __first != __buffer.begin())
+    *__out_it++ = *__buffer.begin();
+  __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __padding.__before, __fill);
+  if (!__zero_padding && __first != __buffer.begin())
+    *__out_it++ = *__buffer.begin();
+
+  // integral part
+  if (__grouping.empty()) {
+    __out_it = _VSTD::copy_n(__first, __digits, _VSTD::move(__out_it));
+  } else {
+    auto __r = __grouping.rbegin();
+    auto __e = __grouping.rend() - 1;
+    _CharT __sep = __np.thousands_sep();
+    // The output is divided in small groups of numbers to write:
+    // - A group before the first separator.
+    // - A separator and a group, repeated for the number of separators.
+    // - A group after the last separator.
+    // This loop achieves that process by testing the termination condition
+    // midway in the loop.
+    while (true) {
+      __out_it = _VSTD::copy_n(__first, *__r, _VSTD::move(__out_it));
+      __first += *__r;
+
+      if (__r == __e)
+        break;
+
+      ++__r;
+      *__out_it++ = __sep;
+    }
+  }
+
+  // fractional part
+  if (__result.__radix_point != __result.__last) {
+    *__out_it++ = __np.decimal_point();
+    __out_it = _VSTD::copy(__result.__radix_point + 1, __result.__exponent, _VSTD::move(__out_it));
+    __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __buffer.__num_trailing_zeros(), _CharT('0'));
+  }
+
+  // exponent
+  if (__result.__exponent != __result.__last)
+    __out_it = _VSTD::copy(__result.__exponent, __result.__last, _VSTD::move(__out_it));
+
+  // alignment
+  return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after, __fill);
+}
+
+#    endif // _LIBCPP_HAS_NO_LOCALIZATION
+
+template <__formatter::__char_type _CharT>
+class _LIBCPP_TEMPLATE_VIS __formatter_floating_point : public __parser_floating_point<_CharT> {
+public:
+  template <floating_point _Tp>
+  _LIBCPP_HIDE_FROM_ABI auto format(_Tp __value, auto& __ctx) -> decltype(__ctx.out()) {
+    if (this->__width_needs_substitution())
+      this->__substitute_width_arg_id(__ctx.arg(this->__width));
+
+    bool __negative = _VSTD::signbit(__value);
+
+    if (!_VSTD::isfinite(__value)) [[unlikely]]
+      return __format_non_finite(__ctx.out(), __negative, _VSTD::isnan(__value));
+
+    bool __has_precision = this->__has_precision_field();
+    if (this->__precision_needs_substitution())
+      this->__substitute_precision_arg_id(__ctx.arg(this->__precision));
+
+    // Depending on the std-format-spec string the sign and the value
+    // might not be outputted together:
+    // - zero-padding may insert additional '0' characters.
+    // Therefore the value is processed as a non negative value.
+    // The function @ref __insert_sign will insert a '-' when the value was
+    // negative.
+
+    if (__negative)
+      __value = _VSTD::copysign(__value, +1.0);
+
+    // TODO FMT _Fp should just be _Tp when to_chars has proper long double support.
+    using _Fp = conditional_t<same_as<_Tp, long double>, double, _Tp>;
+    // Force the type of the precision to avoid -1 to become an unsigned value.
+    __float_buffer<_Fp> __buffer(__has_precision ? int(this->__precision) : -1);
+    __float_result __result = __format_buffer(__buffer, __value, __negative, __has_precision);
+
+    if (this->__alternate_form && __result.__radix_point == __result.__last) {
+      *__result.__last++ = '.';
+
+      // When there is an exponent the point needs to be moved before the
+      // exponent. When there's no exponent the rotate does nothing. Since
+      // rotate tests whether the operation is a nop, call it unconditionally.
+      _VSTD::rotate(__result.__exponent, __result.__last - 1, __result.__last);
+      __result.__radix_point = __result.__exponent;
+
+      // The radix point is always placed before the exponent.
+      // - No exponent needs to point to the new last.
+      // - An exponent needs to move one position to the right.
+      // So it's safe to increment the value unconditionally.
+      ++__result.__exponent;
+    }
+
+#    ifndef _LIBCPP_HAS_NO_LOCALIZATION
+    if (this->__locale_specific_form)
+      return __format_spec::__format_locale_specific_form(__ctx.out(), __buffer, __result, __ctx.locale(),
+                                                          this->__width, this->__alignment, this->__fill);
+#    endif
+
+    ptr
diff _t __size = __result.__last - __buffer.begin();
+    int __num_trailing_zeros = __buffer.__num_trailing_zeros();
+    if (__size + __num_trailing_zeros >= this->__width) {
+      if (__num_trailing_zeros && __result.__exponent != __result.__last)
+        // Insert trailing zeros before exponent character.
+        return _VSTD::copy(__result.__exponent, __result.__last,
+                           _VSTD::fill_n(_VSTD::copy(__buffer.begin(), __result.__exponent, __ctx.out()),
+                                         __num_trailing_zeros, _CharT('0')));
+
+      return _VSTD::fill_n(_VSTD::copy(__buffer.begin(), __result.__last, __ctx.out()), __num_trailing_zeros,
+                           _CharT('0'));
+    }
+
+    auto __out_it = __ctx.out();
+    char* __first = __buffer.begin();
+    if (this->__alignment == _Flags::_Alignment::__default) {
+      // When there is a sign output it before the padding. Note the __size
+      // doesn't need any adjustment, regardless whether the sign is written
+      // here or in __formatter::__write.
+      if (__first != __result.__integral)
+        *__out_it++ = *__first++;
+      // After the sign is written, zero padding is the same a right alignment
+      // with '0'.
+      this->__alignment = _Flags::_Alignment::__right;
+      this->__fill = _CharT('0');
+    }
+
+    if (__num_trailing_zeros)
+      return __formatter::__write(_VSTD::move(__out_it), __first, __result.__last, __size, this->__width, this->__fill,
+                                  this->__alignment, __result.__exponent, __num_trailing_zeros);
+
+    return __formatter::__write(_VSTD::move(__out_it), __first, __result.__last, __size, this->__width, this->__fill,
+                                this->__alignment);
+  }
+
+private:
+  template <class _OutIt>
+  _LIBCPP_HIDE_FROM_ABI _OutIt __format_non_finite(_OutIt __out_it, bool __negative, bool __isnan) {
+    char __buffer[4];
+    char* __last = __insert_sign(__buffer, __negative, this->__sign);
+
+    // to_char can return inf, infinity, nan, and nan(n-char-sequence).
+    // The format library requires inf and nan.
+    // All in one expression to avoid dangling references.
+    __last = _VSTD::copy_n(&("infnanINFNAN"[6 * (this->__type == _Flags::_Type::__float_hexadecimal_upper_case ||
+                                                 this->__type == _Flags::_Type::__scientific_upper_case ||
+                                                 this->__type == _Flags::_Type::__fixed_upper_case ||
+                                                 this->__type == _Flags::_Type::__general_upper_case) +
+                                            3 * __isnan]),
+                           3, __last);
+
+    // [format.string.std]/13
+    // A zero (0) character preceding the width field pads the field with
+    // leading zeros (following any indication of sign or base) to the field
+    // width, except when applied to an infinity or NaN.
+    if (this->__alignment == _Flags::_Alignment::__default)
+      this->__alignment = _Flags::_Alignment::__right;
+
+    ptr
diff _t __size = __last - __buffer;
+    if (__size >= this->__width)
+      return _VSTD::copy_n(__buffer, __size, _VSTD::move(__out_it));
+
+    return __formatter::__write(_VSTD::move(__out_it), __buffer, __last, __size, this->__width, this->__fill,
+                                this->__alignment);
+  }
+
+  /// Fills the buffer with the data based on the requested formatting.
+  ///
+  /// This function, when needed, turns the characters to upper case and
+  /// determines the "interesting" locations which are returned to the caller.
+  ///
+  /// This means the caller never has to convert the contents of the buffer to
+  /// upper case or search for radix points and the location of the exponent.
+  /// This gives a bit of overhead. The original code didn't do that, but due
+  /// to the number of possible additional work needed to turn this number to
+  /// the proper output the code was littered with tests for upper cases and
+  /// searches for radix points and exponents.
+  /// - When a precision larger than the type's precision is selected
+  ///   additional zero characters need to be written before the exponent.
+  /// - alternate form needs to add a radix point when not present.
+  /// - localization needs to do grouping in the integral part.
+  template <class _Fp, class _Tp>
+  // TODO FMT _Fp should just be _Tp when to_chars has proper long double support.
+  _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer(__float_buffer<_Fp>& __buffer, _Tp __value, bool __negative,
+                                                       bool __has_precision) {
+    char* __first = __insert_sign(__buffer.begin(), __negative, this->__sign);
+    switch (this->__type) {
+    case _Flags::_Type::__default:
+      return __format_spec::__format_buffer_default(__buffer, __value, __first);
+
+    case _Flags::_Type::__float_hexadecimal_lower_case:
+      return __format_spec::__format_buffer_hexadecimal_lower_case(
+          __buffer, __value, __has_precision ? __buffer.__precision() : -1, __first);
+
+    case _Flags::_Type::__float_hexadecimal_upper_case:
+      return __format_spec::__format_buffer_hexadecimal_upper_case(
+          __buffer, __value, __has_precision ? __buffer.__precision() : -1, __first);
+
+    case _Flags::_Type::__scientific_lower_case:
+      return __format_spec::__format_buffer_scientific_lower_case(__buffer, __value, __buffer.__precision(), __first);
+
+    case _Flags::_Type::__scientific_upper_case:
+      return __format_spec::__format_buffer_scientific_upper_case(__buffer, __value, __buffer.__precision(), __first);
+
+    case _Flags::_Type::__fixed_lower_case:
+    case _Flags::_Type::__fixed_upper_case:
+      return __format_spec::__format_buffer_fixed(__buffer, __value, __buffer.__precision(), __first);
+
+    case _Flags::_Type::__general_lower_case:
+      return __format_spec::__format_buffer_general_lower_case(__buffer, __value, __buffer.__precision(), __first);
+
+    case _Flags::_Type::__general_upper_case:
+      return __format_spec::__format_buffer_general_upper_case(__buffer, __value, __buffer.__precision(), __first);
+
+    default:
+      _LIBCPP_ASSERT(false, "The parser should have validated the type");
+      _LIBCPP_UNREACHABLE();
+    }
+  }
+};
+
+} //namespace __format_spec
+
+template <__formatter::__char_type _CharT>
+struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<float, _CharT>
+    : public __format_spec::__formatter_floating_point<_CharT> {};
+template <__formatter::__char_type _CharT>
+struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<double, _CharT>
+    : public __format_spec::__formatter_floating_point<_CharT> {};
+template <__formatter::__char_type _CharT>
+struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<long double, _CharT>
+    : public __format_spec::__formatter_floating_point<_CharT> {};
+
+#  endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
+
+#endif //_LIBCPP_STD_VER > 17
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___FORMAT_FORMATTER_FLOATING_POINT_H

diff  --git a/libcxx/include/__format/formatter_integral.h b/libcxx/include/__format/formatter_integral.h
index 73e2fed8c0b7b..f164ee6109748 100644
--- a/libcxx/include/__format/formatter_integral.h
+++ b/libcxx/include/__format/formatter_integral.h
@@ -82,7 +82,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 namespace __format_spec {
 
 /** Wrapper around @ref to_chars, returning the output pointer. */
-template <class _Tp>
+template <integral _Tp>
 _LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last,
                                         _Tp __value, int __base) {
   // TODO FMT Evaluate code overhead due to not calling the internal function

diff  --git a/libcxx/include/__format/parser_std_format_spec.h b/libcxx/include/__format/parser_std_format_spec.h
index 6eae27d9ad188..75fc626c84ac1 100644
--- a/libcxx/include/__format/parser_std_format_spec.h
+++ b/libcxx/include/__format/parser_std_format_spec.h
@@ -475,6 +475,21 @@ __parse_type(const _CharT* __begin, _Flags& __flags) {
   return ++__begin;
 }
 
+/**
+ * Process the parsed alignment and zero-padding state of arithmetic types.
+ *
+ * [format.string.std]/13
+ *   If the 0 character and an align option both appear, the 0 character is
+ *   ignored.
+ *
+ * For the formatter a @ref __default alignment means zero-padding.
+ */
+_LIBCPP_HIDE_FROM_ABI constexpr void __process_arithmetic_alignment(_Flags& __flags) {
+  __flags.__zero_padding &= __flags.__alignment == _Flags::_Alignment::__default;
+  if (!__flags.__zero_padding && __flags.__alignment == _Flags::_Alignment::__default)
+    __flags.__alignment = _Flags::_Alignment::__right;
+}
+
 /**
  * The parser for the std-format-spec.
  *
@@ -648,23 +663,9 @@ class _LIBCPP_TEMPLATE_VIS __parser_integral
     return __begin;
   }
 
-  /**
-   * Handles the post-parsing updates for the integer types.
-   *
-   * Updates the zero-padding and alignment for integer types.
-   *
-   * [format.string.std]/13
-   *   If the 0 character and an align option both appear, the 0 character is
-   *   ignored.
-   *
-   * For the formatter a @ref __default alignment means zero-padding. Update
-   * the alignment based on parsed format string.
-   */
+  /** Handles the post-parsing updates for the integer types. */
   _LIBCPP_HIDE_FROM_ABI constexpr void __handle_integer() noexcept {
-    this->__zero_padding &= this->__alignment == _Flags::_Alignment::__default;
-    if (!this->__zero_padding &&
-        this->__alignment == _Flags::_Alignment::__default)
-      this->__alignment = _Flags::_Alignment::__right;
+    __process_arithmetic_alignment(static_cast<_Flags&>(*this));
   }
 
   /**
@@ -701,7 +702,130 @@ class _LIBCPP_TEMPLATE_VIS __parser_integral
   }
 };
 
-// TODO FMT Add a parser for floating-point values.
+/**
+ * The parser for the std-format-spec.
+ *
+ * This implements the parser for the floating-point types.
+ *
+ * See @ref __parser_string.
+ */
+template <class _CharT>
+class _LIBCPP_TEMPLATE_VIS __parser_floating_point
+    : public __parser_width,              // provides __width(|as_arg)
+      public __parser_precision,          // provides __precision(|as_arg)
+      public __parser_fill_align<_CharT>, // provides __fill and uses __flags
+      public _Flags                       // provides __flags
+{
+public:
+  using char_type = _CharT;
+
+  /**
+   * The low-level std-format-spec parse function.
+   *
+   * @pre __begin points at the beginning of the std-format-spec. This means
+   * directly after the ':'.
+   * @pre The std-format-spec parses the entire input, or the first unmatched
+   * character is a '}'.
+   *
+   * @returns The iterator pointing at the last parsed character.
+   */
+  _LIBCPP_HIDE_FROM_ABI constexpr auto parse(auto& __parse_ctx)
+      -> decltype(__parse_ctx.begin()) {
+    auto __it = __parse(__parse_ctx);
+    __process_arithmetic_alignment(static_cast<_Flags&>(*this));
+    __process_display_type();
+    return __it;
+  }
+protected:
+  /**
+   * The low-level std-format-spec parse function.
+   *
+   * @pre __begin points at the beginning of the std-format-spec. This means
+   * directly after the ':'.
+   * @pre The std-format-spec parses the entire input, or the first unmatched
+   * character is a '}'.
+   *
+   * @returns The iterator pointing at the last parsed character.
+   */
+  _LIBCPP_HIDE_FROM_ABI constexpr auto __parse(auto& __parse_ctx)
+      -> decltype(__parse_ctx.begin()) {
+    auto __begin = __parse_ctx.begin();
+    auto __end = __parse_ctx.end();
+    if (__begin == __end)
+      return __begin;
+
+    __begin = __parser_fill_align<_CharT>::__parse(__begin, __end,
+                                                   static_cast<_Flags&>(*this));
+    if (__begin == __end)
+      return __begin;
+
+    __begin = __parse_sign(__begin, static_cast<_Flags&>(*this));
+    if (__begin == __end)
+      return __begin;
+
+    __begin = __parse_alternate_form(__begin, static_cast<_Flags&>(*this));
+    if (__begin == __end)
+      return __begin;
+
+    __begin = __parse_zero_padding(__begin, static_cast<_Flags&>(*this));
+    if (__begin == __end)
+      return __begin;
+
+    __begin = __parser_width::__parse(__begin, __end, __parse_ctx);
+    if (__begin == __end)
+      return __begin;
+
+    __begin = __parser_precision::__parse(__begin, __end, __parse_ctx);
+    if (__begin == __end)
+      return __begin;
+
+    __begin =
+        __parse_locale_specific_form(__begin, static_cast<_Flags&>(*this));
+    if (__begin == __end)
+      return __begin;
+
+    __begin = __parse_type(__begin, static_cast<_Flags&>(*this));
+
+    if (__begin != __end && *__begin != _CharT('}'))
+      __throw_format_error(
+          "The format-spec should consume the input or end with a '}'");
+
+    return __begin;
+  }
+
+  /** Processes the parsed std-format-spec based on the parsed display type. */
+  _LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type() {
+    switch (this->__type) {
+    case _Flags::_Type::__default:
+      // When no precision specified then it keeps default since that
+      // formatting 
diff ers from the other types.
+      if (this->__has_precision_field())
+        this->__type = _Flags::_Type::__general_lower_case;
+      break;
+    case _Flags::_Type::__float_hexadecimal_lower_case:
+    case _Flags::_Type::__float_hexadecimal_upper_case:
+      // Precision specific behavior will be handled later.
+      break;
+    case _Flags::_Type::__scientific_lower_case:
+    case _Flags::_Type::__scientific_upper_case:
+    case _Flags::_Type::__fixed_lower_case:
+    case _Flags::_Type::__fixed_upper_case:
+    case _Flags::_Type::__general_lower_case:
+    case _Flags::_Type::__general_upper_case:
+      if (!this->__has_precision_field()) {
+        // Set the default precision for the call to to_chars.
+        this->__precision = 6;
+        this->__precision_as_arg = false;
+      }
+      break;
+
+    default:
+      __throw_format_error("The format-spec type has a type not supported for "
+                           "a floating-point argument");
+    }
+  }
+};
+
 // TODO FMT Add a parser for pointer values.
 
 /** Helper struct returned from @ref __get_string_alignment. */

diff  --git a/libcxx/include/format b/libcxx/include/format
index 788b9c299abc0..3a186469dd5c0 100644
--- a/libcxx/include/format
+++ b/libcxx/include/format
@@ -277,6 +277,7 @@ namespace std {
 #include <__format/formatter.h>
 #include <__format/formatter_bool.h>
 #include <__format/formatter_char.h>
+#include <__format/formatter_floating_point.h>
 #include <__format/formatter_integer.h>
 #include <__format/formatter_string.h>
 #include <__format/parser_std_format_spec.h>

diff  --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index a927f9d0e6700..c940a6d11d816 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -488,25 +488,26 @@ module std [system] {
     export *
 
     module __format {
-      module format_arg             { private header "__format/format_arg.h" }
-      module format_args            { private header "__format/format_args.h" }
+      module format_arg               { private header "__format/format_arg.h" }
+      module format_args              { private header "__format/format_args.h" }
       module format_context {
         private header "__format/format_context.h"
         export optional
         export locale
       }
-      module format_error           { private header "__format/format_error.h" }
-      module format_fwd             { private header "__format/format_fwd.h" }
-      module format_parse_context   { private header "__format/format_parse_context.h" }
-      module format_string          { private header "__format/format_string.h" }
-      module format_to_n_result     { private header "__format/format_to_n_result.h" }
-      module formatter              { private header "__format/formatter.h" }
-      module formatter_bool         { private header "__format/formatter_bool.h" }
-      module formatter_char         { private header "__format/formatter_char.h" }
-      module formatter_integer      { private header "__format/formatter_integer.h" }
-      module formatter_integral     { private header "__format/formatter_integral.h" }
-      module formatter_string       { private header "__format/formatter_string.h" }
-      module parser_std_format_spec { private header "__format/parser_std_format_spec.h" }
+      module format_error             { private header "__format/format_error.h" }
+      module format_fwd               { private header "__format/format_fwd.h" }
+      module format_parse_context     { private header "__format/format_parse_context.h" }
+      module format_string            { private header "__format/format_string.h" }
+      module format_to_n_result       { private header "__format/format_to_n_result.h" }
+      module formatter                { private header "__format/formatter.h" }
+      module formatter_bool           { private header "__format/formatter_bool.h" }
+      module formatter_char           { private header "__format/formatter_char.h" }
+      module formatter_floating_point { private header "__format/formatter_floating_point.h" }
+      module formatter_integer        { private header "__format/formatter_integer.h" }
+      module formatter_integral       { private header "__format/formatter_integral.h" }
+      module formatter_string         { private header "__format/formatter_string.h" }
+      module parser_std_format_spec   { private header "__format/parser_std_format_spec.h" }
     }
   }
   module forward_list {

diff  --git a/libcxx/test/libcxx/diagnostics/detail.headers/format/formatter_floating_point.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/format/formatter_floating_point.module.verify.cpp
new file mode 100644
index 0000000000000..35f19dcf76a73
--- /dev/null
+++ b/libcxx/test/libcxx/diagnostics/detail.headers/format/formatter_floating_point.module.verify.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: modules-build
+
+// WARNING: This test was generated by 'generate_private_header_tests.py'
+// and should not be edited manually.
+
+// expected-error@*:* {{use of private header from outside its module: '__format/formatter_floating_point.h'}}
+#include <__format/formatter_floating_point.h>

diff  --git a/libcxx/test/libcxx/utilities/format/format.string/format.string.std/std_format_spec_floating_point.pass.cpp b/libcxx/test/libcxx/utilities/format/format.string/format.string.std/std_format_spec_floating_point.pass.cpp
new file mode 100644
index 0000000000000..caf38a7e520a0
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/format/format.string/format.string.std/std_format_spec_floating_point.pass.cpp
@@ -0,0 +1,353 @@
+//===----------------------------------------------------------------------===//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+
+// <format>
+
+// Tests the parsing of the format string as specified in [format.string.std].
+// It validates whether the std-format-spec is valid for a floating-point type.
+
+#include <format>
+#include <cassert>
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+#  include <iostream>
+#endif
+
+#include "concepts_precision.h"
+#include "test_macros.h"
+#include "make_string.h"
+#include "test_exception.h"
+
+#define CSTR(S) MAKE_CSTRING(CharT, S)
+
+using namespace std::__format_spec;
+
+template <class CharT>
+using Parser = __parser_floating_point<CharT>;
+
+template <class CharT>
+struct Expected {
+  CharT fill = CharT(' ');
+  _Flags::_Alignment alignment = _Flags::_Alignment::__right;
+  _Flags::_Sign sign = _Flags::_Sign::__default;
+  bool alternate_form = false;
+  bool zero_padding = false;
+  uint32_t width = 0;
+  bool width_as_arg = false;
+  uint32_t precision = std::__format::__number_max;
+  bool precision_as_arg = true;
+  bool locale_specific_form = false;
+  _Flags::_Type type = _Flags::_Type::__default;
+};
+
+template <class CharT>
+constexpr void test(Expected<CharT> expected, size_t size, std::basic_string_view<CharT> fmt) {
+  // Initialize parser with sufficient arguments to avoid the parsing to fail
+  // due to insufficient arguments.
+  std::basic_format_parse_context<CharT> parse_ctx(fmt, std::__format::__number_max);
+  auto begin = parse_ctx.begin();
+  auto end = parse_ctx.end();
+  Parser<CharT> parser;
+  auto it = parser.parse(parse_ctx);
+
+  assert(begin == parse_ctx.begin());
+  assert(end == parse_ctx.end());
+
+  assert(begin + size == it);
+  assert(parser.__fill == expected.fill);
+  assert(parser.__alignment == expected.alignment);
+  assert(parser.__sign == expected.sign);
+  assert(parser.__alternate_form == expected.alternate_form);
+  assert(parser.__zero_padding == expected.zero_padding);
+  assert(parser.__width == expected.width);
+  assert(parser.__width_as_arg == expected.width_as_arg);
+  assert(parser.__precision == expected.precision);
+  assert(parser.__precision_as_arg == expected.precision_as_arg);
+  assert(parser.__locale_specific_form == expected.locale_specific_form);
+  assert(parser.__type == expected.type);
+}
+
+template <class CharT>
+constexpr void test(Expected<CharT> expected, size_t size, const CharT* f) {
+  // The format-spec is valid if completely consumed or terminates at a '}'.
+  // The valid inputs all end with a '}'. The test is executed twice:
+  // - first with the terminating '}',
+  // - second consuming the entire input.
+  std::basic_string_view<CharT> fmt{f};
+  assert(fmt.back() == CharT('}') && "Pre-condition failure");
+
+  test(expected, size, fmt);
+  fmt.remove_suffix(1);
+  test(expected, size, fmt);
+}
+
+template <class CharT>
+constexpr void test() {
+  Parser<CharT> parser;
+
+  assert(parser.__fill == CharT(' '));
+  assert(parser.__alignment == _Flags::_Alignment::__default);
+  assert(parser.__sign == _Flags::_Sign::__default);
+  assert(parser.__alternate_form == false);
+  assert(parser.__zero_padding == false);
+  assert(parser.__width == 0);
+  assert(parser.__width_as_arg == false);
+  assert(parser.__precision == std::__format::__number_max);
+  assert(parser.__precision_as_arg == true);
+  assert(parser.__locale_specific_form == false);
+  assert(parser.__type == _Flags::_Type::__default);
+
+  // Depending on whether or not a precision is specified the results 
diff er.
+  // Table 65: Meaning of type options for floating-point types [tab:format.type.float]
+
+  test({}, 0, CSTR("}"));
+  test({.precision = 0, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 2, CSTR(".0}"));
+  test({.precision = 1, .precision_as_arg = true, .type = _Flags::_Type::__general_lower_case}, 4, CSTR(".{1}}"));
+
+  test({.type = _Flags::_Type::__float_hexadecimal_lower_case}, 1, CSTR("a}"));
+  test({.type = _Flags::_Type::__float_hexadecimal_upper_case}, 1, CSTR("A}"));
+
+  test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__scientific_lower_case}, 1, CSTR("e}"));
+  test({.precision = 0, .precision_as_arg = false, .type = _Flags::_Type::__scientific_lower_case}, 3, CSTR(".0e}"));
+  test({.precision = 1, .precision_as_arg = true, .type = _Flags::_Type::__scientific_lower_case}, 5, CSTR(".{1}e}"));
+  test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__scientific_upper_case}, 1, CSTR("E}"));
+  test({.precision = 0, .precision_as_arg = false, .type = _Flags::_Type::__scientific_upper_case}, 3, CSTR(".0E}"));
+  test({.precision = 1, .precision_as_arg = true, .type = _Flags::_Type::__scientific_upper_case}, 5, CSTR(".{1}E}"));
+
+  test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__fixed_lower_case}, 1, CSTR("f}"));
+  test({.precision = 0, .precision_as_arg = false, .type = _Flags::_Type::__fixed_lower_case}, 3, CSTR(".0f}"));
+  test({.precision = 1, .precision_as_arg = true, .type = _Flags::_Type::__fixed_lower_case}, 5, CSTR(".{1}f}"));
+  test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__fixed_upper_case}, 1, CSTR("F}"));
+  test({.precision = 0, .precision_as_arg = false, .type = _Flags::_Type::__fixed_upper_case}, 3, CSTR(".0F}"));
+  test({.precision = 1, .precision_as_arg = true, .type = _Flags::_Type::__fixed_upper_case}, 5, CSTR(".{1}F}"));
+
+  test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 1, CSTR("g}"));
+  test({.precision = 0, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 3, CSTR(".0g}"));
+  test({.precision = 1, .precision_as_arg = true, .type = _Flags::_Type::__general_lower_case}, 5, CSTR(".{1}g}"));
+  test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__general_upper_case}, 1, CSTR("G}"));
+  test({.precision = 0, .precision_as_arg = false, .type = _Flags::_Type::__general_upper_case}, 3, CSTR(".0G}"));
+  test({.precision = 1, .precision_as_arg = true, .type = _Flags::_Type::__general_upper_case}, 5, CSTR(".{1}G}"));
+
+  // *** Align-fill ***
+  test({.alignment = _Flags::_Alignment::__left}, 1, CSTR("<}"));
+  test({.alignment = _Flags::_Alignment::__center}, 1, "^}");
+  test({.alignment = _Flags::_Alignment::__right}, 1, ">}");
+
+  test({.fill = CharT('L'), .alignment = _Flags::_Alignment::__left}, 2, CSTR("L<}"));
+  test({.fill = CharT('#'), .alignment = _Flags::_Alignment::__center}, 2, CSTR("#^}"));
+  test({.fill = CharT('0'), .alignment = _Flags::_Alignment::__right}, 2, CSTR("0>}"));
+
+  test_exception<Parser<CharT>>("The format-spec fill field contains an invalid character", CSTR("{<"));
+  test_exception<Parser<CharT>>("The format-spec fill field contains an invalid character", CSTR("}<"));
+
+  // *** Sign ***
+  test({.sign = _Flags::_Sign::__minus}, 1, CSTR("-}"));
+  test({.sign = _Flags::_Sign::__plus}, 1, CSTR("+}"));
+  test({.sign = _Flags::_Sign::__space}, 1, CSTR(" }"));
+
+  // *** Alternate form ***
+  test({.alternate_form = true}, 1, CSTR("#}"));
+
+  // *** Zero padding ***
+  // TODO FMT What to do with zero-padding without a width?
+  // [format.string.std]/13
+  //   A zero (0) character preceding the width field pads the field with
+  //   leading zeros (following any indication of sign or base) to the field
+  //   width, except when applied to an infinity or NaN.
+  // Obviously it makes no sense, but should it be allowed or is it a format
+  // error?
+  test({.alignment = _Flags::_Alignment::__default, .zero_padding = true}, 1, CSTR("0}"));
+  test({.alignment = _Flags::_Alignment::__left, .zero_padding = false}, 2, CSTR("<0}"));
+  test({.alignment = _Flags::_Alignment::__center, .zero_padding = false}, 2, CSTR("^0}"));
+  test({.alignment = _Flags::_Alignment::__right, .zero_padding = false}, 2, CSTR(">0}"));
+
+  // *** Width ***
+  test({.width = 0, .width_as_arg = false}, 0, CSTR("}"));
+  test({.width = 1, .width_as_arg = false}, 1, CSTR("1}"));
+  test({.width = 10, .width_as_arg = false}, 2, CSTR("10}"));
+  test({.width = 1000, .width_as_arg = false}, 4, CSTR("1000}"));
+  test({.width = 1000000, .width_as_arg = false}, 7, CSTR("1000000}"));
+
+  test({.width = 0, .width_as_arg = true}, 2, CSTR("{}}"));
+  test({.width = 0, .width_as_arg = true}, 3, CSTR("{0}}"));
+  test({.width = 1, .width_as_arg = true}, 3, CSTR("{1}}"));
+
+  test_exception<Parser<CharT>>("A format-spec width field shouldn't have a leading zero", CSTR("00"));
+
+  static_assert(std::__format::__number_max == 2'147'483'647, "Update the assert and the test.");
+  test({.width = 2'147'483'647, .width_as_arg = false}, 10, CSTR("2147483647}"));
+  test_exception<Parser<CharT>>("The numeric value of the format-spec is too large", CSTR("2147483648"));
+  test_exception<Parser<CharT>>("The numeric value of the format-spec is too large", CSTR("5000000000"));
+  test_exception<Parser<CharT>>("The numeric value of the format-spec is too large", CSTR("10000000000"));
+
+  test_exception<Parser<CharT>>("End of input while parsing format-spec arg-id", CSTR("{"));
+  test_exception<Parser<CharT>>("Invalid arg-id", CSTR("{0"));
+  test_exception<Parser<CharT>>("The arg-id of the format-spec starts with an invalid character", CSTR("{a"));
+  test_exception<Parser<CharT>>("Invalid arg-id", CSTR("{1"));
+  test_exception<Parser<CharT>>("Invalid arg-id", CSTR("{9"));
+  test_exception<Parser<CharT>>("Invalid arg-id", CSTR("{9:"));
+  test_exception<Parser<CharT>>("Invalid arg-id", CSTR("{9a"));
+  static_assert(std::__format::__number_max == 2'147'483'647, "Update the assert and the test.");
+  // Note the static_assert tests whether the arg-id is valid.
+  // Therefore the following should be true arg-id < __format::__number_max.
+  test({.width = 2'147'483'646, .width_as_arg = true}, 12, CSTR("{2147483646}}"));
+  test_exception<Parser<CharT>>("The numeric value of the format-spec is too large", CSTR("{2147483648}"));
+  test_exception<Parser<CharT>>("The numeric value of the format-spec is too large", CSTR("{5000000000}"));
+  test_exception<Parser<CharT>>("The numeric value of the format-spec is too large", CSTR("{10000000000}"));
+
+  // *** Precision ***
+  test({.precision = 0, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 2, CSTR(".0}"));
+  test({.precision = 1, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 2, CSTR(".1}"));
+  test({.precision = 10, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 3, CSTR(".10}"));
+  test({.precision = 1000, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 5, CSTR(".1000}"));
+  test({.precision = 1000000, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 8,
+       CSTR(".1000000}"));
+
+  test({.precision = 0, .precision_as_arg = true, .type = _Flags::_Type::__general_lower_case}, 3, CSTR(".{}}"));
+  test({.precision = 0, .precision_as_arg = true, .type = _Flags::_Type::__general_lower_case}, 4, CSTR(".{0}}"));
+  test({.precision = 1, .precision_as_arg = true, .type = _Flags::_Type::__general_lower_case}, 4, CSTR(".{1}}"));
+
+  test_exception<Parser<CharT>>("The format-spec precision field doesn't contain a value or arg-id", CSTR(".a"));
+  test_exception<Parser<CharT>>("The format-spec precision field doesn't contain a value or arg-id", CSTR(".:"));
+
+  static_assert(std::__format::__number_max == 2'147'483'647, "Update the assert and the test.");
+  test({.precision = 2'147'483'647, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 11,
+       CSTR(".2147483647}"));
+  test_exception<Parser<CharT>>("The numeric value of the format-spec is too large", CSTR(".2147483648"));
+  test_exception<Parser<CharT>>("The numeric value of the format-spec is too large", CSTR(".5000000000"));
+  test_exception<Parser<CharT>>("The numeric value of the format-spec is too large", CSTR(".10000000000"));
+
+  test_exception<Parser<CharT>>("End of input while parsing format-spec arg-id", CSTR(".{"));
+  test_exception<Parser<CharT>>("Invalid arg-id", CSTR(".{0"));
+  test_exception<Parser<CharT>>("The arg-id of the format-spec starts with an invalid character", CSTR(".{a"));
+  test_exception<Parser<CharT>>("Invalid arg-id", CSTR(".{1"));
+  test_exception<Parser<CharT>>("Invalid arg-id", CSTR(".{9"));
+  test_exception<Parser<CharT>>("Invalid arg-id", CSTR(".{9:"));
+  test_exception<Parser<CharT>>("Invalid arg-id", CSTR(".{9a"));
+
+  static_assert(std::__format::__number_max == 2'147'483'647, "Update the assert and the test.");
+  // Note the static_assert tests whether the arg-id is valid.
+  // Therefore the following should be true arg-id < __format::__number_max.
+  test({.precision = 2'147'483'646, .precision_as_arg = true, .type = _Flags::_Type::__general_lower_case}, 13,
+       CSTR(".{2147483646}}"));
+  test_exception<Parser<CharT>>("The numeric value of the format-spec is too large", CSTR(".{2147483648}"));
+  test_exception<Parser<CharT>>("The numeric value of the format-spec is too large", CSTR(".{5000000000}"));
+  test_exception<Parser<CharT>>("The numeric value of the format-spec is too large", CSTR(".{10000000000}"));
+
+  // *** Width & Precision ***
+  test({.width = 1,
+        .width_as_arg = false,
+        .precision = 0,
+        .precision_as_arg = false,
+        .type = _Flags::_Type::__general_lower_case},
+       3, CSTR("1.0}"));
+  test({.width = 0,
+        .width_as_arg = true,
+        .precision = 1,
+        .precision_as_arg = true,
+        .type = _Flags::_Type::__general_lower_case},
+       5, CSTR("{}.{}}"));
+  test({.width = 10,
+        .width_as_arg = true,
+        .precision = 9,
+        .precision_as_arg = true,
+        .type = _Flags::_Type::__general_lower_case},
+       8, CSTR("{10}.{9}}"));
+
+  // *** Locale-specific form ***
+  test({.locale_specific_form = true}, 1, CSTR("L}"));
+
+  // *** Type ***
+  {
+    const char* unsuported_type = "The format-spec type has a type not supported for a floating-point argument";
+    const char* not_a_type = "The format-spec should consume the input or end with a '}'";
+
+    test({.type = _Flags::_Type::__float_hexadecimal_upper_case}, 1, CSTR("A}"));
+    test_exception<Parser<CharT>>(unsuported_type, CSTR("B}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("C}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("D}"));
+    test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__scientific_upper_case}, 1, CSTR("E}"));
+    test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__fixed_upper_case}, 1, CSTR("F}"));
+    test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__general_upper_case}, 1, CSTR("G}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("H}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("I}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("J}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("K}"));
+    test({.locale_specific_form = true}, 1, CSTR("L}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("M}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("N}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("O}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("P}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("Q}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("R}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("S}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("T}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("U}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("V}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("W}"));
+    test_exception<Parser<CharT>>(unsuported_type, CSTR("X}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("Y}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("Z}"));
+
+    test({.type = _Flags::_Type::__float_hexadecimal_lower_case}, 1, CSTR("a}"));
+    test_exception<Parser<CharT>>(unsuported_type, CSTR("b}"));
+    test_exception<Parser<CharT>>(unsuported_type, CSTR("c}"));
+    test_exception<Parser<CharT>>(unsuported_type, CSTR("d}"));
+    test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__scientific_lower_case}, 1, CSTR("e}"));
+    test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__fixed_lower_case}, 1, CSTR("f}"));
+    test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 1, CSTR("g}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("h}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("i}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("j}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("k}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("l}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("m}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("n}"));
+    test_exception<Parser<CharT>>(unsuported_type, CSTR("o}"));
+    test_exception<Parser<CharT>>(unsuported_type, CSTR("p}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("q}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("r}"));
+    test_exception<Parser<CharT>>(unsuported_type, CSTR("s}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("t}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("u}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("v}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("w}"));
+    test_exception<Parser<CharT>>(unsuported_type, CSTR("x}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("y}"));
+    test_exception<Parser<CharT>>(not_a_type, CSTR("z}"));
+  }
+  // **** General ***
+  test_exception<Parser<CharT>>("The format-spec should consume the input or end with a '}'", CSTR("ss"));
+}
+
+constexpr bool test() {
+  test<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+#endif
+
+  return true;
+}
+
+int main(int, char**) {
+#if !defined(_WIN32) && !defined(_AIX)
+  // Make sure the parsers match the expectations. The layout of the
+  // subobjects is chosen to minimize the size required.
+  static_assert(sizeof(Parser<char>) == 3 * sizeof(uint32_t));
+#  ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  static_assert(sizeof(Parser<wchar_t>) == (sizeof(wchar_t) <= 2 ? 3 * sizeof(uint32_t) : 4 * sizeof(uint32_t)));
+#  endif
+#endif
+
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.floating_point.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.floating_point.pass.cpp
index 1ba1189b512c5..0e8e95d2762f6 100644
--- a/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.floating_point.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.floating_point.pass.cpp
@@ -8,7 +8,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // UNSUPPORTED: libcpp-no-concepts
 // UNSUPPORTED: libcpp-has-no-incomplete-format
-// UNSUPPORTED: LIBCXX-DEBUG-FIXME
 
 // <format>
 
@@ -25,11 +24,14 @@
 // - double
 // - long double
 
-// TODO FMT Enable after floating-point support has been enabled
-#if 0
 #include <format>
+
+#include <array>
 #include <cassert>
+#include <cmath>
+#include <charconv>
 #include <concepts>
+#include <string>
 #include <type_traits>
 
 #include "test_macros.h"
@@ -37,9 +39,8 @@
 
 #define STR(S) MAKE_STRING(CharT, S)
 
-template <class StringViewT, class ArithmeticT>
-void test(StringViewT fmt, ArithmeticT arg) {
-  using CharT = typename StringViewT::value_type;
+template <class CharT, class ArithmeticT>
+void test(std::basic_string_view<CharT> fmt, ArithmeticT arg, std::basic_string<CharT> expected) {
   auto parse_ctx = std::basic_format_parse_context<CharT>(fmt);
   std::formatter<ArithmeticT, CharT> formatter;
   static_assert(std::semiregular<decltype(formatter)>);
@@ -51,15 +52,19 @@ void test(StringViewT fmt, ArithmeticT arg) {
   auto out = std::back_inserter(result);
   using FormatCtxT = std::basic_format_context<decltype(out), CharT>;
 
-  auto format_ctx = std::__format_context_create<decltype(out), CharT>(
-      out, std::make_format_args<FormatCtxT>(arg));
+  auto format_ctx = std::__format_context_create<decltype(out), CharT>(out, std::make_format_args<FormatCtxT>(arg));
   formatter.format(arg, format_ctx);
-  std::string expected = std::to_string(arg);
-  assert(result == std::basic_string<CharT>(expected.begin(), expected.end()));
+
+  if (expected.empty()) {
+    std::array<char, 128> buffer;
+    expected.append(buffer.begin(), std::to_chars(buffer.begin(), buffer.end(), arg).ptr);
+  }
+
+  assert(result == expected);
 }
 
 template <class StringT, class ArithmeticT>
-void test_termination_condition(StringT f, ArithmeticT arg) {
+void test_termination_condition(StringT f, ArithmeticT arg, StringT expected = {}) {
   // The format-spec is valid if completely consumed or terminates at a '}'.
   // The valid inputs all end with a '}'. The test is executed twice:
   // - first with the terminating '}',
@@ -68,40 +73,398 @@ void test_termination_condition(StringT f, ArithmeticT arg) {
   std::basic_string_view<CharT> fmt{f};
   assert(fmt.back() == CharT('}') && "Pre-condition failure");
 
-  test(fmt, arg);
+  test(fmt, arg, expected);
   fmt.remove_suffix(1);
-  test(fmt, arg);
+  test(fmt, arg, expected);
+}
+
+template <class CharT, class ArithmeticT>
+void test_hex_lower_case_precision(ArithmeticT value) {
+  std::array<char, 25'000> buffer;
+  char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::hex, 20'000).ptr;
+  test_termination_condition(STR(".20000a}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+  size_t size = buffer.end() - end;
+  std::fill_n(end, size, '#');
+  test_termination_condition(STR("#<25000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
+  test_termination_condition(STR("#^25000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
+  test_termination_condition(STR("#>25000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::fill_n(buffer.begin(), size, '0');
+  if (std::signbit(value)) {
+    buffer[0] = '-';
+    buffer[size] = '0';
+  }
+  test_termination_condition(STR("025000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+  end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::hex, 20'000).ptr;
+  test_termination_condition(STR(".20000La}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+  size = buffer.end() - end;
+  std::fill_n(end, size, '#');
+  test_termination_condition(STR("#<25000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
+  test_termination_condition(STR("#^25000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
+  test_termination_condition(STR("#>25000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::fill_n(buffer.begin(), size, '0');
+  if (std::signbit(value)) {
+    buffer[0] = '-';
+    buffer[size] = '0';
+  }
+  test_termination_condition(STR("025000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+#endif
+}
+
+template <class CharT, class ArithmeticT>
+void test_hex_upper_case_precision(ArithmeticT value) {
+  std::array<char, 25'000> buffer;
+  char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::hex, 20'000).ptr;
+  std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
+  test_termination_condition(STR(".20000A}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+  size_t size = buffer.end() - end;
+  std::fill_n(end, size, '#');
+  test_termination_condition(STR("#<25000.20000A}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
+  test_termination_condition(STR("#^25000.20000A}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
+  test_termination_condition(STR("#>25000.20000A}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::fill_n(buffer.begin(), size, '0');
+  if (std::signbit(value)) {
+    buffer[0] = '-';
+    buffer[size] = '0';
+  }
+  test_termination_condition(STR("025000.20000A}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+  end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::hex, 20'000).ptr;
+  std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
+  test_termination_condition(STR(".20000LA}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+  size = buffer.end() - end;
+  std::fill_n(end, size, '#');
+  test_termination_condition(STR("#<25000.20000LA}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
+  test_termination_condition(STR("#^25000.20000LA}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
+  test_termination_condition(STR("#>25000.20000LA}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::fill_n(buffer.begin(), size, '0');
+  if (std::signbit(value)) {
+    buffer[0] = '-';
+    buffer[size] = '0';
+  }
+  test_termination_condition(STR("025000.20000LA}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+#endif
+}
+
+template <class CharT, class ArithmeticT>
+void test_scientific_lower_case_precision(ArithmeticT value) {
+  std::array<char, 25'000> buffer;
+  char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::scientific, 20'000).ptr;
+  test_termination_condition(STR(".20000e}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+  size_t size = buffer.end() - end;
+  std::fill_n(end, size, '#');
+  test_termination_condition(STR("#<25000.20000e}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
+  test_termination_condition(STR("#^25000.20000e}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
+  test_termination_condition(STR("#>25000.20000e}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::fill_n(buffer.begin(), size, '0');
+  if (std::signbit(value)) {
+    buffer[0] = '-';
+    buffer[size] = '0';
+  }
+  test_termination_condition(STR("025000.20000e}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+  end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::scientific, 20'000).ptr;
+  test_termination_condition(STR(".20000Le}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+  size = buffer.end() - end;
+  std::fill_n(end, size, '#');
+  test_termination_condition(STR("#<25000.20000Le}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
+  test_termination_condition(STR("#^25000.20000Le}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
+  test_termination_condition(STR("#>25000.20000Le}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::fill_n(buffer.begin(), size, '0');
+  if (std::signbit(value)) {
+    buffer[0] = '-';
+    buffer[size] = '0';
+  }
+  test_termination_condition(STR("025000.20000Le}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+#endif
+}
+
+template <class CharT, class ArithmeticT>
+void test_scientific_upper_case_precision(ArithmeticT value) {
+  std::array<char, 25'000> buffer;
+  char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::scientific, 20'000).ptr;
+  std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
+  test_termination_condition(STR(".20000E}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+  size_t size = buffer.end() - end;
+  std::fill_n(end, size, '#');
+  test_termination_condition(STR("#<25000.20000E}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
+  test_termination_condition(STR("#^25000.20000E}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
+  test_termination_condition(STR("#>25000.20000E}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::fill_n(buffer.begin(), size, '0');
+  if (std::signbit(value)) {
+    buffer[0] = '-';
+    buffer[size] = '0';
+  }
+  test_termination_condition(STR("025000.20000E}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+  end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::scientific, 20'000).ptr;
+  std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
+  test_termination_condition(STR(".20000LE}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+  size = buffer.end() - end;
+  std::fill_n(end, size, '#');
+  test_termination_condition(STR("#<25000.20000LE}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
+  test_termination_condition(STR("#^25000.20000LE}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
+  test_termination_condition(STR("#>25000.20000LE}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::fill_n(buffer.begin(), size, '0');
+  if (std::signbit(value)) {
+    buffer[0] = '-';
+    buffer[size] = '0';
+  }
+  test_termination_condition(STR("025000.20000LE}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+#endif
+}
+
+template <class CharT, class ArithmeticT>
+void test_fixed_lower_case_precision(ArithmeticT value) {
+  std::array<char, 25'000> buffer;
+  char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::fixed, 20'000).ptr;
+  test_termination_condition(STR(".20000f}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+  size_t size = buffer.end() - end;
+  std::fill_n(end, size, '#');
+  test_termination_condition(STR("#<25000.20000f}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
+  test_termination_condition(STR("#^25000.20000f}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
+  test_termination_condition(STR("#>25000.20000f}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::fill_n(buffer.begin(), size, '0');
+  if (std::signbit(value)) {
+    buffer[0] = '-';
+    buffer[size] = '0';
+  }
+  test_termination_condition(STR("025000.20000f}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+  end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::fixed, 20'000).ptr;
+  test_termination_condition(STR(".20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+  size = buffer.end() - end;
+  std::fill_n(end, size, '#');
+  test_termination_condition(STR("#<25000.20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
+  test_termination_condition(STR("#^25000.20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
+  test_termination_condition(STR("#>25000.20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::fill_n(buffer.begin(), size, '0');
+  if (std::signbit(value)) {
+    buffer[0] = '-';
+    buffer[size] = '0';
+  }
+  test_termination_condition(STR("025000.20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+#endif
+}
+
+template <class CharT, class ArithmeticT>
+void test_fixed_upper_case_precision(ArithmeticT value) {
+  std::array<char, 25'000> buffer;
+  char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::fixed, 20'000).ptr;
+  std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
+  test_termination_condition(STR(".20000F}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+  size_t size = buffer.end() - end;
+  std::fill_n(end, size, '#');
+  test_termination_condition(STR("#<25000.20000F}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
+  test_termination_condition(STR("#^25000.20000F}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
+  test_termination_condition(STR("#>25000.20000F}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::fill_n(buffer.begin(), size, '0');
+  if (std::signbit(value)) {
+    buffer[0] = '-';
+    buffer[size] = '0';
+  }
+  test_termination_condition(STR("025000.20000F}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+  end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::fixed, 20'000).ptr;
+  std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
+  test_termination_condition(STR(".20000LF}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+  size = buffer.end() - end;
+  std::fill_n(end, size, '#');
+  test_termination_condition(STR("#<25000.20000LF}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
+  test_termination_condition(STR("#^25000.20000LF}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
+  test_termination_condition(STR("#>25000.20000LF}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::fill_n(buffer.begin(), size, '0');
+  if (std::signbit(value)) {
+    buffer[0] = '-';
+    buffer[size] = '0';
+  }
+  test_termination_condition(STR("025000.20000LF}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+#endif
+}
+
+template <class CharT, class ArithmeticT>
+void test_general_lower_case_precision(ArithmeticT value) {
+  std::array<char, 25'000> buffer;
+  char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::general, 20'000).ptr;
+  test_termination_condition(STR(".20000g}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+  size_t size = buffer.end() - end;
+  std::fill_n(end, size, '#');
+  test_termination_condition(STR("#<25000.20000g}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
+  test_termination_condition(STR("#^25000.20000g}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
+  test_termination_condition(STR("#>25000.20000g}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::fill_n(buffer.begin(), size, '0');
+  if (std::signbit(value)) {
+    buffer[0] = '-';
+    buffer[size] = '0';
+  }
+  test_termination_condition(STR("025000.20000g}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+  end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::general, 20'000).ptr;
+  test_termination_condition(STR(".20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+  size = buffer.end() - end;
+  std::fill_n(end, size, '#');
+  test_termination_condition(STR("#<25000.20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
+  test_termination_condition(STR("#^25000.20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
+  test_termination_condition(STR("#>25000.20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::fill_n(buffer.begin(), size, '0');
+  if (std::signbit(value)) {
+    buffer[0] = '-';
+    buffer[size] = '0';
+  }
+  test_termination_condition(STR("025000.20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+#endif
+}
+
+template <class CharT, class ArithmeticT>
+void test_general_upper_case_precision(ArithmeticT value) {
+  std::array<char, 25'000> buffer;
+  char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::general, 20'000).ptr;
+  std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
+  test_termination_condition(STR(".20000G}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+  size_t size = buffer.end() - end;
+  std::fill_n(end, size, '#');
+  test_termination_condition(STR("#<25000.20000G}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
+  test_termination_condition(STR("#^25000.20000G}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
+  test_termination_condition(STR("#>25000.20000G}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::fill_n(buffer.begin(), size, '0');
+  if (std::signbit(value)) {
+    buffer[0] = '-';
+    buffer[size] = '0';
+  }
+  test_termination_condition(STR("025000.20000G}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+  end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::general, 20'000).ptr;
+  std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
+  test_termination_condition(STR(".20000LG}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+  size = buffer.end() - end;
+  std::fill_n(end, size, '#');
+  test_termination_condition(STR("#<25000.20000LG}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
+  test_termination_condition(STR("#^25000.20000LG}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
+  test_termination_condition(STR("#>25000.20000LG}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+  std::fill_n(buffer.begin(), size, '0');
+  if (std::signbit(value)) {
+    buffer[0] = '-';
+    buffer[size] = '0';
+  }
+  test_termination_condition(STR("025000.20000LG}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+#endif
+}
+
+template <class CharT, class ArithmeticT>
+void test_value(ArithmeticT value) {
+  test_hex_lower_case_precision<CharT>(value);
+  test_hex_upper_case_precision<CharT>(value);
+
+  test_scientific_lower_case_precision<CharT>(value);
+  test_scientific_upper_case_precision<CharT>(value);
+
+  test_fixed_lower_case_precision<CharT>(value);
+  test_fixed_upper_case_precision<CharT>(value);
+
+  test_general_lower_case_precision<CharT>(value);
+  test_general_upper_case_precision<CharT>(value);
+}
+
+template <class ArithmeticT, class CharT>
+void test_special_values() {
+  using A = ArithmeticT;
+
+  test_value<CharT>(-std::numeric_limits<A>::max());
+  test_value<CharT>(A(-1.0));
+  test_value<CharT>(-std::numeric_limits<A>::min());
+  test_value<CharT>(-std::numeric_limits<A>::denorm_min());
+  test_value<CharT>(A(-0.0));
+
+  test_value<CharT>(A(0.0));
+  test_value<CharT>(std::numeric_limits<A>::denorm_min());
+  test_value<CharT>(A(1.0));
+  test_value<CharT>(std::numeric_limits<A>::min());
+  test_value<CharT>(std::numeric_limits<A>::max());
 }
 
 template <class ArithmeticT, class CharT>
 void test_float_type() {
   using A = ArithmeticT;
+
   test_termination_condition(STR("}"), A(-std::numeric_limits<float>::max()));
   test_termination_condition(STR("}"), A(-std::numeric_limits<float>::min()));
   test_termination_condition(STR("}"), A(-0.0));
+
   test_termination_condition(STR("}"), A(0.0));
   test_termination_condition(STR("}"), A(std::numeric_limits<float>::min()));
   test_termination_condition(STR("}"), A(std::numeric_limits<float>::max()));
   if (sizeof(A) > sizeof(float)) {
-    test_termination_condition(STR("}"),
-                               A(-std::numeric_limits<double>::max()));
-    test_termination_condition(STR("}"),
-                               A(-std::numeric_limits<double>::min()));
+    test_termination_condition(STR("}"), A(-std::numeric_limits<double>::max()));
+    test_termination_condition(STR("}"), A(-std::numeric_limits<double>::min()));
     test_termination_condition(STR("}"), A(std::numeric_limits<double>::min()));
     test_termination_condition(STR("}"), A(std::numeric_limits<double>::max()));
   }
   if (sizeof(A) > sizeof(double)) {
-    test_termination_condition(STR("}"),
-                               A(-std::numeric_limits<long double>::max()));
-    test_termination_condition(STR("}"),
-                               A(-std::numeric_limits<long double>::min()));
-    test_termination_condition(STR("}"),
-                               A(std::numeric_limits<long double>::min()));
-    test_termination_condition(STR("}"),
-                               A(std::numeric_limits<long double>::max()));
+    test_termination_condition(STR("}"), A(-std::numeric_limits<long double>::max()));
+    test_termination_condition(STR("}"), A(-std::numeric_limits<long double>::min()));
+    test_termination_condition(STR("}"), A(std::numeric_limits<long double>::min()));
+    test_termination_condition(STR("}"), A(std::numeric_limits<long double>::max()));
   }
 
-  // TODO FMT Also test with special floating point values: +/-Inf NaN.
+  // The results of inf and nan may 
diff er from the result of to_chars.
+  test_termination_condition(STR("}"), A(-std::numeric_limits<A>::infinity()), STR("-inf"));
+  test_termination_condition(STR("}"), A(std::numeric_limits<A>::infinity()), STR("inf"));
+
+  A nan = std::numeric_limits<A>::quiet_NaN();
+  test_termination_condition(STR("}"), std::copysign(nan, -1.0), STR("-nan"));
+  test_termination_condition(STR("}"), nan, STR("nan"));
+
+  // TODO FMT Enable long double testing
+  if constexpr (!std::same_as<A, long double>)
+    test_special_values<A, CharT>();
 }
 
 template <class CharT>
@@ -119,6 +482,3 @@ int main(int, char**) {
 
   return 0;
 }
-#else
-int main(int, char**) { return 0; }
-#endif

diff  --git a/libcxx/test/std/utilities/format/format.functions/format_tests.h b/libcxx/test/std/utilities/format/format.functions/format_tests.h
index 470da03b8b083..c2eeb236f99d0 100644
--- a/libcxx/test/std/utilities/format/format.functions/format_tests.h
+++ b/libcxx/test/std/utilities/format/format.functions/format_tests.h
@@ -13,6 +13,8 @@
 #include "make_string.h"
 #include "test_macros.h"
 
+#include <cmath>
+
 // In this file the following template types are used:
 // TestFunction must be callable as check(expected-result, string-to-format, args-to-format...)
 // ExceptionTest must be callable as check_exception(expected-exception, string-to-format, args-to-format...)
@@ -992,6 +994,1496 @@ void format_test_char_as_integer(TestFunction check,
         fmt, '*');
 }
 
+template <class F, class CharT, class TestFunction>
+void format_test_floating_point_hex_lower_case(TestFunction check) {
+  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
+  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"
+
+  // Test whether the hexadecimal letters are the proper case.
+  // The precision is too large for float, so two tests are used.
+  check(STR("answer is '1.abcp+0'"), STR("answer is '{:a}'"), F(0x1.abcp+0));
+  check(STR("answer is '1.defp+0'"), STR("answer is '{:a}'"), F(0x1.defp+0));
+
+  // *** align-fill & width ***
+  check(STR("answer is '   1p-2'"), STR("answer is '{:7a}'"), F(0.25));
+  check(STR("answer is '   1p-2'"), STR("answer is '{:>7a}'"), F(0.25));
+  check(STR("answer is '1p-2   '"), STR("answer is '{:<7a}'"), F(0.25));
+  check(STR("answer is ' 1p-2  '"), STR("answer is '{:^7a}'"), F(0.25));
+
+  check(STR("answer is '---1p-3'"), STR("answer is '{:->7a}'"), F(125e-3));
+  check(STR("answer is '1p-3---'"), STR("answer is '{:-<7a}'"), F(125e-3));
+  check(STR("answer is '-1p-3--'"), STR("answer is '{:-^7a}'"), F(125e-3));
+
+  check(STR("answer is '***inf'"), STR("answer is '{:*>6a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'inf***'"), STR("answer is '{:*<6a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '*inf**'"), STR("answer is '{:*^6a}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '###-inf'"), STR("answer is '{:#>7a}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf###'"), STR("answer is '{:#<7a}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '#-inf##'"), STR("answer is '{:#^7a}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '^^^nan'"), STR("answer is '{:^>6a}'"), nan_pos);
+  check(STR("answer is 'nan^^^'"), STR("answer is '{:^<6a}'"), nan_pos);
+  check(STR("answer is '^nan^^'"), STR("answer is '{:^^6a}'"), nan_pos);
+
+  check(STR("answer is '000-nan'"), STR("answer is '{:0>7a}'"), nan_neg);
+  check(STR("answer is '-nan000'"), STR("answer is '{:0<7a}'"), nan_neg);
+  check(STR("answer is '0-nan00'"), STR("answer is '{:0^7a}'"), nan_neg);
+
+  // Test whether zero padding is ignored
+  check(STR("answer is '   1p-2'"), STR("answer is '{:>07a}'"), F(0.25));
+  check(STR("answer is '1p-2   '"), STR("answer is '{:<07a}'"), F(0.25));
+  check(STR("answer is ' 1p-2  '"), STR("answer is '{:^07a}'"), F(0.25));
+
+  // *** Sign ***
+  check(STR("answer is '0p+0'"), STR("answer is '{:a}'"), F(0));
+  check(STR("answer is '0p+0'"), STR("answer is '{:-a}'"), F(0));
+  check(STR("answer is '+0p+0'"), STR("answer is '{:+a}'"), F(0));
+  check(STR("answer is ' 0p+0'"), STR("answer is '{: a}'"), F(0));
+
+  check(STR("answer is '-0p+0'"), STR("answer is '{:a}'"), F(-0.));
+  check(STR("answer is '-0p+0'"), STR("answer is '{:-a}'"), F(-0.));
+  check(STR("answer is '-0p+0'"), STR("answer is '{:+a}'"), F(-0.));
+  check(STR("answer is '-0p+0'"), STR("answer is '{: a}'"), F(-0.));
+
+  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
+  check(STR("answer is 'inf'"), STR("answer is '{:a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'inf'"), STR("answer is '{:-a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '+inf'"), STR("answer is '{:+a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is ' inf'"), STR("answer is '{: a}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '-inf'"), STR("answer is '{:a}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:-a}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:+a}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{: a}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'nan'"), STR("answer is '{:a}'"), nan_pos);
+  check(STR("answer is 'nan'"), STR("answer is '{:-a}'"), nan_pos);
+  check(STR("answer is '+nan'"), STR("answer is '{:+a}'"), nan_pos);
+  check(STR("answer is ' nan'"), STR("answer is '{: a}'"), nan_pos);
+
+  check(STR("answer is '-nan'"), STR("answer is '{:a}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{:-a}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{:+a}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{: a}'"), nan_neg);
+
+  // *** alternate form ***
+  // When precision is zero there's no decimal point except when the alternate form is specified.
+  check(STR("answer is '0p+0'"), STR("answer is '{:a}'"), F(0));
+  check(STR("answer is '0.p+0'"), STR("answer is '{:#a}'"), F(0));
+
+  check(STR("answer is '1p+1'"), STR("answer is '{:.0a}'"), F(2.5));
+  check(STR("answer is '1.p+1'"), STR("answer is '{:#.0a}'"), F(2.5));
+  check(STR("answer is '1.4p+1'"), STR("answer is '{:#a}'"), F(2.5));
+
+  check(STR("answer is 'inf'"), STR("answer is '{:#a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:#a}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'nan'"), STR("answer is '{:#a}'"), nan_pos);
+  check(STR("answer is '-nan'"), STR("answer is '{:#a}'"), nan_neg);
+
+  // *** zero-padding & width ***
+  check(STR("answer is '1p-5'"), STR("answer is '{:04a}'"), 0.03125);
+  check(STR("answer is '+1p-5'"), STR("answer is '{:+05a}'"), 0.03125);
+  check(STR("answer is '+01p-5'"), STR("answer is '{:+06a}'"), 0.03125);
+
+  check(STR("answer is '0001p-5'"), STR("answer is '{:07a}'"), 0.03125);
+  check(STR("answer is '0001p-5'"), STR("answer is '{:-07a}'"), 0.03125);
+  check(STR("answer is '+001p-5'"), STR("answer is '{:+07a}'"), 0.03125);
+  check(STR("answer is ' 001p-5'"), STR("answer is '{: 07a}'"), 0.03125);
+
+  check(STR("answer is '       inf'"), STR("answer is '{:010a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       inf'"), STR("answer is '{:-010a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '      +inf'"), STR("answer is '{:+010a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       inf'"), STR("answer is '{: 010a}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '      -inf'"), STR("answer is '{:010a}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{:-010a}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{:+010a}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{: 010a}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '       nan'"), STR("answer is '{:010a}'"), nan_pos);
+  check(STR("answer is '       nan'"), STR("answer is '{:-010a}'"), nan_pos);
+  check(STR("answer is '      +nan'"), STR("answer is '{:+010a}'"), nan_pos);
+  check(STR("answer is '       nan'"), STR("answer is '{: 010a}'"), nan_pos);
+
+  check(STR("answer is '      -nan'"), STR("answer is '{:010a}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{:-010a}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{:+010a}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{: 010a}'"), nan_neg);
+
+  // *** precision ***
+  // See format_test_floating_point_hex_lower_case_precision
+
+  // *** locale-specific form ***
+  // See locale-specific_form.pass.cpp
+}
+
+template <class F, class CharT, class TestFunction>
+void format_test_floating_point_hex_upper_case(TestFunction check) {
+  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
+  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"
+
+  // Test whether the hexadecimal letters are the proper case.
+  // The precision is too large for float, so two tests are used.
+  check(STR("answer is '1.ABCP+0'"), STR("answer is '{:A}'"), F(0x1.abcp+0));
+  check(STR("answer is '1.DEFP+0'"), STR("answer is '{:A}'"), F(0x1.defp+0));
+
+  // *** align-fill & width ***
+  check(STR("answer is '   1P-2'"), STR("answer is '{:7A}'"), F(0.25));
+  check(STR("answer is '   1P-2'"), STR("answer is '{:>7A}'"), F(0.25));
+  check(STR("answer is '1P-2   '"), STR("answer is '{:<7A}'"), F(0.25));
+  check(STR("answer is ' 1P-2  '"), STR("answer is '{:^7A}'"), F(0.25));
+
+  check(STR("answer is '---1P-3'"), STR("answer is '{:->7A}'"), F(125e-3));
+  check(STR("answer is '1P-3---'"), STR("answer is '{:-<7A}'"), F(125e-3));
+  check(STR("answer is '-1P-3--'"), STR("answer is '{:-^7A}'"), F(125e-3));
+
+  check(STR("answer is '***INF'"), STR("answer is '{:*>6A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'INF***'"), STR("answer is '{:*<6A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '*INF**'"), STR("answer is '{:*^6A}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '###-INF'"), STR("answer is '{:#>7A}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF###'"), STR("answer is '{:#<7A}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '#-INF##'"), STR("answer is '{:#^7A}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '^^^NAN'"), STR("answer is '{:^>6A}'"), nan_pos);
+  check(STR("answer is 'NAN^^^'"), STR("answer is '{:^<6A}'"), nan_pos);
+  check(STR("answer is '^NAN^^'"), STR("answer is '{:^^6A}'"), nan_pos);
+
+  check(STR("answer is '000-NAN'"), STR("answer is '{:0>7A}'"), nan_neg);
+  check(STR("answer is '-NAN000'"), STR("answer is '{:0<7A}'"), nan_neg);
+  check(STR("answer is '0-NAN00'"), STR("answer is '{:0^7A}'"), nan_neg);
+
+  // Test whether zero padding is ignored
+  check(STR("answer is '   1P-2'"), STR("answer is '{:>07A}'"), F(0.25));
+  check(STR("answer is '1P-2   '"), STR("answer is '{:<07A}'"), F(0.25));
+  check(STR("answer is ' 1P-2  '"), STR("answer is '{:^07A}'"), F(0.25));
+
+  // *** Sign ***
+  check(STR("answer is '0P+0'"), STR("answer is '{:A}'"), F(0));
+  check(STR("answer is '0P+0'"), STR("answer is '{:-A}'"), F(0));
+  check(STR("answer is '+0P+0'"), STR("answer is '{:+A}'"), F(0));
+  check(STR("answer is ' 0P+0'"), STR("answer is '{: A}'"), F(0));
+
+  check(STR("answer is '-0P+0'"), STR("answer is '{:A}'"), F(-0.));
+  check(STR("answer is '-0P+0'"), STR("answer is '{:-A}'"), F(-0.));
+  check(STR("answer is '-0P+0'"), STR("answer is '{:+A}'"), F(-0.));
+  check(STR("answer is '-0P+0'"), STR("answer is '{: A}'"), F(-0.));
+
+  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
+  check(STR("answer is 'INF'"), STR("answer is '{:A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'INF'"), STR("answer is '{:-A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '+INF'"), STR("answer is '{:+A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is ' INF'"), STR("answer is '{: A}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '-INF'"), STR("answer is '{:A}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{:-A}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{:+A}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{: A}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'NAN'"), STR("answer is '{:A}'"), nan_pos);
+  check(STR("answer is 'NAN'"), STR("answer is '{:-A}'"), nan_pos);
+  check(STR("answer is '+NAN'"), STR("answer is '{:+A}'"), nan_pos);
+  check(STR("answer is ' NAN'"), STR("answer is '{: A}'"), nan_pos);
+
+  check(STR("answer is '-NAN'"), STR("answer is '{:A}'"), nan_neg);
+  check(STR("answer is '-NAN'"), STR("answer is '{:-A}'"), nan_neg);
+  check(STR("answer is '-NAN'"), STR("answer is '{:+A}'"), nan_neg);
+  check(STR("answer is '-NAN'"), STR("answer is '{: A}'"), nan_neg);
+
+  // *** alternate form ***
+  // When precision is zero there's no decimal point except when the alternate form is specified.
+  check(STR("answer is '0P+0'"), STR("answer is '{:A}'"), F(0));
+  check(STR("answer is '0.P+0'"), STR("answer is '{:#A}'"), F(0));
+
+  check(STR("answer is '1P+1'"), STR("answer is '{:.0A}'"), F(2.5));
+  check(STR("answer is '1.P+1'"), STR("answer is '{:#.0A}'"), F(2.5));
+  check(STR("answer is '1.4P+1'"), STR("answer is '{:#A}'"), F(2.5));
+
+  check(STR("answer is 'INF'"), STR("answer is '{:#A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{:#A}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'NAN'"), STR("answer is '{:#A}'"), nan_pos);
+  check(STR("answer is '-NAN'"), STR("answer is '{:#A}'"), nan_neg);
+
+  // *** zero-padding & width ***
+  check(STR("answer is '1P-5'"), STR("answer is '{:04A}'"), 0.03125);
+  check(STR("answer is '+1P-5'"), STR("answer is '{:+05A}'"), 0.03125);
+  check(STR("answer is '+01P-5'"), STR("answer is '{:+06A}'"), 0.03125);
+
+  check(STR("answer is '0001P-5'"), STR("answer is '{:07A}'"), 0.03125);
+  check(STR("answer is '0001P-5'"), STR("answer is '{:-07A}'"), 0.03125);
+  check(STR("answer is '+001P-5'"), STR("answer is '{:+07A}'"), 0.03125);
+  check(STR("answer is ' 001P-5'"), STR("answer is '{: 07A}'"), 0.03125);
+
+  check(STR("answer is '       INF'"), STR("answer is '{:010A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       INF'"), STR("answer is '{:-010A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '      +INF'"), STR("answer is '{:+010A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       INF'"), STR("answer is '{: 010A}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '      -INF'"), STR("answer is '{:010A}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -INF'"), STR("answer is '{:-010A}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -INF'"), STR("answer is '{:+010A}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -INF'"), STR("answer is '{: 010A}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '       NAN'"), STR("answer is '{:010A}'"), nan_pos);
+  check(STR("answer is '       NAN'"), STR("answer is '{:-010A}'"), nan_pos);
+  check(STR("answer is '      +NAN'"), STR("answer is '{:+010A}'"), nan_pos);
+  check(STR("answer is '       NAN'"), STR("answer is '{: 010A}'"), nan_pos);
+
+  check(STR("answer is '      -NAN'"), STR("answer is '{:010A}'"), nan_neg);
+  check(STR("answer is '      -NAN'"), STR("answer is '{:-010A}'"), nan_neg);
+  check(STR("answer is '      -NAN'"), STR("answer is '{:+010A}'"), nan_neg);
+  check(STR("answer is '      -NAN'"), STR("answer is '{: 010A}'"), nan_neg);
+
+  // *** precision ***
+  // See format_test_floating_point_hex_upper_case_precision
+
+  // *** locale-specific form ***
+  // See locale-specific_form.pass.cpp
+}
+
+template <class F, class CharT, class TestFunction>
+void format_test_floating_point_hex_lower_case_precision(TestFunction check) {
+  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
+  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"
+
+  // *** align-fill & width ***
+  check(STR("answer is '   1.000000p-2'"), STR("answer is '{:14.6a}'"), F(0.25));
+  check(STR("answer is '   1.000000p-2'"), STR("answer is '{:>14.6a}'"), F(0.25));
+  check(STR("answer is '1.000000p-2   '"), STR("answer is '{:<14.6a}'"), F(0.25));
+  check(STR("answer is ' 1.000000p-2  '"), STR("answer is '{:^14.6a}'"), F(0.25));
+
+  check(STR("answer is '---1.000000p-3'"), STR("answer is '{:->14.6a}'"), F(125e-3));
+  check(STR("answer is '1.000000p-3---'"), STR("answer is '{:-<14.6a}'"), F(125e-3));
+  check(STR("answer is '-1.000000p-3--'"), STR("answer is '{:-^14.6a}'"), F(125e-3));
+
+  check(STR("answer is '***inf'"), STR("answer is '{:*>6.6a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'inf***'"), STR("answer is '{:*<6.6a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '*inf**'"), STR("answer is '{:*^6.6a}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '###-inf'"), STR("answer is '{:#>7.6a}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf###'"), STR("answer is '{:#<7.6a}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '#-inf##'"), STR("answer is '{:#^7.6a}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '^^^nan'"), STR("answer is '{:^>6.6a}'"), nan_pos);
+  check(STR("answer is 'nan^^^'"), STR("answer is '{:^<6.6a}'"), nan_pos);
+  check(STR("answer is '^nan^^'"), STR("answer is '{:^^6.6a}'"), nan_pos);
+
+  check(STR("answer is '000-nan'"), STR("answer is '{:0>7.6a}'"), nan_neg);
+  check(STR("answer is '-nan000'"), STR("answer is '{:0<7.6a}'"), nan_neg);
+  check(STR("answer is '0-nan00'"), STR("answer is '{:0^7.6a}'"), nan_neg);
+
+  // Test whether zero padding is ignored
+  check(STR("answer is '   1.000000p-2'"), STR("answer is '{:>014.6a}'"), F(0.25));
+  check(STR("answer is '1.000000p-2   '"), STR("answer is '{:<014.6a}'"), F(0.25));
+  check(STR("answer is ' 1.000000p-2  '"), STR("answer is '{:^014.6a}'"), F(0.25));
+
+  // *** Sign ***
+  check(STR("answer is '0.000000p+0'"), STR("answer is '{:.6a}'"), F(0));
+  check(STR("answer is '0.000000p+0'"), STR("answer is '{:-.6a}'"), F(0));
+  check(STR("answer is '+0.000000p+0'"), STR("answer is '{:+.6a}'"), F(0));
+  check(STR("answer is ' 0.000000p+0'"), STR("answer is '{: .6a}'"), F(0));
+
+  check(STR("answer is '-0.000000p+0'"), STR("answer is '{:.6a}'"), F(-0.));
+  check(STR("answer is '-0.000000p+0'"), STR("answer is '{:-.6a}'"), F(-0.));
+  check(STR("answer is '-0.000000p+0'"), STR("answer is '{:+.6a}'"), F(-0.));
+  check(STR("answer is '-0.000000p+0'"), STR("answer is '{: .6a}'"), F(-0.));
+
+  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
+  check(STR("answer is 'inf'"), STR("answer is '{:.6a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'inf'"), STR("answer is '{:-.6a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '+inf'"), STR("answer is '{:+.6a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is ' inf'"), STR("answer is '{: .6a}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '-inf'"), STR("answer is '{:.6a}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:-.6a}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:+.6a}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{: .6a}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'nan'"), STR("answer is '{:.6a}'"), nan_pos);
+  check(STR("answer is 'nan'"), STR("answer is '{:-.6a}'"), nan_pos);
+  check(STR("answer is '+nan'"), STR("answer is '{:+.6a}'"), nan_pos);
+  check(STR("answer is ' nan'"), STR("answer is '{: .6a}'"), nan_pos);
+
+  check(STR("answer is '-nan'"), STR("answer is '{:.6a}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{:-.6a}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{:+.6a}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{: .6a}'"), nan_neg);
+
+  // *** alternate form ***
+  check(STR("answer is '1.400000p+1'"), STR("answer is '{:#.6a}'"), F(2.5));
+
+  check(STR("answer is 'inf'"), STR("answer is '{:#.6a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:#.6a}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'nan'"), STR("answer is '{:#.6a}'"), nan_pos);
+  check(STR("answer is '-nan'"), STR("answer is '{:#.6a}'"), nan_neg);
+
+  // *** zero-padding & width ***
+  check(STR("answer is '1.000000p-5'"), STR("answer is '{:011.6a}'"), 0.03125);
+  check(STR("answer is '+1.000000p-5'"), STR("answer is '{:+012.6a}'"), 0.03125);
+  check(STR("answer is '+01.000000p-5'"), STR("answer is '{:+013.6a}'"), 0.03125);
+
+  check(STR("answer is '0001.000000p-5'"), STR("answer is '{:014.6a}'"), 0.03125);
+  check(STR("answer is '0001.000000p-5'"), STR("answer is '{:-014.6a}'"), 0.03125);
+  check(STR("answer is '+001.000000p-5'"), STR("answer is '{:+014.6a}'"), 0.03125);
+  check(STR("answer is ' 001.000000p-5'"), STR("answer is '{: 014.6a}'"), 0.03125);
+
+  check(STR("answer is '       inf'"), STR("answer is '{:010.6a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       inf'"), STR("answer is '{:-010.6a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '      +inf'"), STR("answer is '{:+010.6a}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       inf'"), STR("answer is '{: 010.6a}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '      -inf'"), STR("answer is '{:010.6a}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{:-010.6a}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{:+010.6a}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{: 010.6a}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '       nan'"), STR("answer is '{:010.6a}'"), nan_pos);
+  check(STR("answer is '       nan'"), STR("answer is '{:-010.6a}'"), nan_pos);
+  check(STR("answer is '      +nan'"), STR("answer is '{:+010.6a}'"), nan_pos);
+  check(STR("answer is '       nan'"), STR("answer is '{: 010.6a}'"), nan_pos);
+
+  check(STR("answer is '      -nan'"), STR("answer is '{:010.6a}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{:-010.6a}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{:+010.6a}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{: 010.6a}'"), nan_neg);
+
+  // *** locale-specific form ***
+  // See locale-specific_form.pass.cpp
+}
+
+template <class F, class CharT, class TestFunction>
+void format_test_floating_point_hex_upper_case_precision(TestFunction check) {
+  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
+  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"
+
+  // *** align-fill & width ***
+  check(STR("answer is '   1.000000P-2'"), STR("answer is '{:14.6A}'"), F(0.25));
+  check(STR("answer is '   1.000000P-2'"), STR("answer is '{:>14.6A}'"), F(0.25));
+  check(STR("answer is '1.000000P-2   '"), STR("answer is '{:<14.6A}'"), F(0.25));
+  check(STR("answer is ' 1.000000P-2  '"), STR("answer is '{:^14.6A}'"), F(0.25));
+
+  check(STR("answer is '---1.000000P-3'"), STR("answer is '{:->14.6A}'"), F(125e-3));
+  check(STR("answer is '1.000000P-3---'"), STR("answer is '{:-<14.6A}'"), F(125e-3));
+  check(STR("answer is '-1.000000P-3--'"), STR("answer is '{:-^14.6A}'"), F(125e-3));
+
+  check(STR("answer is '***INF'"), STR("answer is '{:*>6.6A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'INF***'"), STR("answer is '{:*<6.6A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '*INF**'"), STR("answer is '{:*^6.6A}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '###-INF'"), STR("answer is '{:#>7.6A}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF###'"), STR("answer is '{:#<7.6A}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '#-INF##'"), STR("answer is '{:#^7.6A}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '^^^NAN'"), STR("answer is '{:^>6.6A}'"), nan_pos);
+  check(STR("answer is 'NAN^^^'"), STR("answer is '{:^<6.6A}'"), nan_pos);
+  check(STR("answer is '^NAN^^'"), STR("answer is '{:^^6.6A}'"), nan_pos);
+
+  check(STR("answer is '000-NAN'"), STR("answer is '{:0>7.6A}'"), nan_neg);
+  check(STR("answer is '-NAN000'"), STR("answer is '{:0<7.6A}'"), nan_neg);
+  check(STR("answer is '0-NAN00'"), STR("answer is '{:0^7.6A}'"), nan_neg);
+
+  // Test whether zero padding is ignored
+  check(STR("answer is '   1.000000P-2'"), STR("answer is '{:>014.6A}'"), F(0.25));
+  check(STR("answer is '1.000000P-2   '"), STR("answer is '{:<014.6A}'"), F(0.25));
+  check(STR("answer is ' 1.000000P-2  '"), STR("answer is '{:^014.6A}'"), F(0.25));
+
+  // *** Sign ***
+  check(STR("answer is '0.000000P+0'"), STR("answer is '{:.6A}'"), F(0));
+  check(STR("answer is '0.000000P+0'"), STR("answer is '{:-.6A}'"), F(0));
+  check(STR("answer is '+0.000000P+0'"), STR("answer is '{:+.6A}'"), F(0));
+  check(STR("answer is ' 0.000000P+0'"), STR("answer is '{: .6A}'"), F(0));
+
+  check(STR("answer is '-0.000000P+0'"), STR("answer is '{:.6A}'"), F(-0.));
+  check(STR("answer is '-0.000000P+0'"), STR("answer is '{:-.6A}'"), F(-0.));
+  check(STR("answer is '-0.000000P+0'"), STR("answer is '{:+.6A}'"), F(-0.));
+  check(STR("answer is '-0.000000P+0'"), STR("answer is '{: .6A}'"), F(-0.));
+
+  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
+  check(STR("answer is 'INF'"), STR("answer is '{:.6A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'INF'"), STR("answer is '{:-.6A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '+INF'"), STR("answer is '{:+.6A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is ' INF'"), STR("answer is '{: .6A}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '-INF'"), STR("answer is '{:.6A}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{:-.6A}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{:+.6A}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{: .6A}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'NAN'"), STR("answer is '{:.6A}'"), nan_pos);
+  check(STR("answer is 'NAN'"), STR("answer is '{:-.6A}'"), nan_pos);
+  check(STR("answer is '+NAN'"), STR("answer is '{:+.6A}'"), nan_pos);
+  check(STR("answer is ' NAN'"), STR("answer is '{: .6A}'"), nan_pos);
+
+  check(STR("answer is '-NAN'"), STR("answer is '{:.6A}'"), nan_neg);
+  check(STR("answer is '-NAN'"), STR("answer is '{:-.6A}'"), nan_neg);
+  check(STR("answer is '-NAN'"), STR("answer is '{:+.6A}'"), nan_neg);
+  check(STR("answer is '-NAN'"), STR("answer is '{: .6A}'"), nan_neg);
+
+  // *** alternate form ***
+  check(STR("answer is '1.400000P+1'"), STR("answer is '{:#.6A}'"), F(2.5));
+
+  check(STR("answer is 'INF'"), STR("answer is '{:#.6A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{:#.6A}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'NAN'"), STR("answer is '{:#.6A}'"), nan_pos);
+  check(STR("answer is '-NAN'"), STR("answer is '{:#.6A}'"), nan_neg);
+
+  // *** zero-padding & width ***
+  check(STR("answer is '1.000000P-5'"), STR("answer is '{:011.6A}'"), 0.03125);
+  check(STR("answer is '+1.000000P-5'"), STR("answer is '{:+012.6A}'"), 0.03125);
+  check(STR("answer is '+01.000000P-5'"), STR("answer is '{:+013.6A}'"), 0.03125);
+
+  check(STR("answer is '0001.000000P-5'"), STR("answer is '{:014.6A}'"), 0.03125);
+  check(STR("answer is '0001.000000P-5'"), STR("answer is '{:-014.6A}'"), 0.03125);
+  check(STR("answer is '+001.000000P-5'"), STR("answer is '{:+014.6A}'"), 0.03125);
+  check(STR("answer is ' 001.000000P-5'"), STR("answer is '{: 014.6A}'"), 0.03125);
+
+  check(STR("answer is '       INF'"), STR("answer is '{:010.6A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       INF'"), STR("answer is '{:-010.6A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '      +INF'"), STR("answer is '{:+010.6A}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       INF'"), STR("answer is '{: 010.6A}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '      -INF'"), STR("answer is '{:010.6A}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -INF'"), STR("answer is '{:-010.6A}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -INF'"), STR("answer is '{:+010.6A}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -INF'"), STR("answer is '{: 010.6A}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '       NAN'"), STR("answer is '{:010.6A}'"), nan_pos);
+  check(STR("answer is '       NAN'"), STR("answer is '{:-010.6A}'"), nan_pos);
+  check(STR("answer is '      +NAN'"), STR("answer is '{:+010.6A}'"), nan_pos);
+  check(STR("answer is '       NAN'"), STR("answer is '{: 010.6A}'"), nan_pos);
+
+  check(STR("answer is '      -NAN'"), STR("answer is '{:010.6A}'"), nan_neg);
+  check(STR("answer is '      -NAN'"), STR("answer is '{:-010.6A}'"), nan_neg);
+  check(STR("answer is '      -NAN'"), STR("answer is '{:+010.6A}'"), nan_neg);
+  check(STR("answer is '      -NAN'"), STR("answer is '{: 010.6A}'"), nan_neg);
+
+  // *** locale-specific form ***
+  // See locale-specific_form.pass.cpp
+}
+
+template <class F, class CharT, class TestFunction>
+void format_test_floating_point_scientific_lower_case(TestFunction check) {
+  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
+  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"
+
+  // *** align-fill & width ***
+  check(STR("answer is '   2.500000e-01'"), STR("answer is '{:15e}'"), F(0.25));
+  check(STR("answer is '   2.500000e-01'"), STR("answer is '{:>15e}'"), F(0.25));
+  check(STR("answer is '2.500000e-01   '"), STR("answer is '{:<15e}'"), F(0.25));
+  check(STR("answer is ' 2.500000e-01  '"), STR("answer is '{:^15e}'"), F(0.25));
+
+  check(STR("answer is '---1.250000e-01'"), STR("answer is '{:->15e}'"), F(125e-3));
+  check(STR("answer is '1.250000e-01---'"), STR("answer is '{:-<15e}'"), F(125e-3));
+  check(STR("answer is '-1.250000e-01--'"), STR("answer is '{:-^15e}'"), F(125e-3));
+
+  check(STR("answer is '***inf'"), STR("answer is '{:*>6e}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'inf***'"), STR("answer is '{:*<6e}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '*inf**'"), STR("answer is '{:*^6e}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '###-inf'"), STR("answer is '{:#>7e}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf###'"), STR("answer is '{:#<7e}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '#-inf##'"), STR("answer is '{:#^7e}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '^^^nan'"), STR("answer is '{:^>6e}'"), nan_pos);
+  check(STR("answer is 'nan^^^'"), STR("answer is '{:^<6e}'"), nan_pos);
+  check(STR("answer is '^nan^^'"), STR("answer is '{:^^6e}'"), nan_pos);
+
+  check(STR("answer is '000-nan'"), STR("answer is '{:0>7e}'"), nan_neg);
+  check(STR("answer is '-nan000'"), STR("answer is '{:0<7e}'"), nan_neg);
+  check(STR("answer is '0-nan00'"), STR("answer is '{:0^7e}'"), nan_neg);
+
+  // Test whether zero padding is ignored
+  check(STR("answer is '   2.500000e-01'"), STR("answer is '{:>015e}'"), F(0.25));
+  check(STR("answer is '2.500000e-01   '"), STR("answer is '{:<015e}'"), F(0.25));
+  check(STR("answer is ' 2.500000e-01  '"), STR("answer is '{:^015e}'"), F(0.25));
+
+  // *** Sign ***
+  check(STR("answer is '0.000000e+00'"), STR("answer is '{:e}'"), F(0));
+  check(STR("answer is '0.000000e+00'"), STR("answer is '{:-e}'"), F(0));
+  check(STR("answer is '+0.000000e+00'"), STR("answer is '{:+e}'"), F(0));
+  check(STR("answer is ' 0.000000e+00'"), STR("answer is '{: e}'"), F(0));
+
+  check(STR("answer is '-0.000000e+00'"), STR("answer is '{:e}'"), F(-0.));
+  check(STR("answer is '-0.000000e+00'"), STR("answer is '{:-e}'"), F(-0.));
+  check(STR("answer is '-0.000000e+00'"), STR("answer is '{:+e}'"), F(-0.));
+  check(STR("answer is '-0.000000e+00'"), STR("answer is '{: e}'"), F(-0.));
+
+  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
+  check(STR("answer is 'inf'"), STR("answer is '{:e}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'inf'"), STR("answer is '{:-e}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '+inf'"), STR("answer is '{:+e}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is ' inf'"), STR("answer is '{: e}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '-inf'"), STR("answer is '{:e}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:-e}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:+e}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{: e}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'nan'"), STR("answer is '{:e}'"), nan_pos);
+  check(STR("answer is 'nan'"), STR("answer is '{:-e}'"), nan_pos);
+  check(STR("answer is '+nan'"), STR("answer is '{:+e}'"), nan_pos);
+  check(STR("answer is ' nan'"), STR("answer is '{: e}'"), nan_pos);
+
+  check(STR("answer is '-nan'"), STR("answer is '{:e}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{:-e}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{:+e}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{: e}'"), nan_neg);
+
+  // *** alternate form **
+  // When precision is zero there's no decimal point except when the alternate form is specified.
+  check(STR("answer is '0e+00'"), STR("answer is '{:.0e}'"), F(0));
+  check(STR("answer is '0.e+00'"), STR("answer is '{:#.0e}'"), F(0));
+
+  check(STR("answer is '0.000000e+00'"), STR("answer is '{:#e}'"), F(0));
+  check(STR("answer is '2.500000e+00'"), STR("answer is '{:#e}'"), F(2.5));
+
+  check(STR("answer is 'inf'"), STR("answer is '{:#e}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:#e}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'nan'"), STR("answer is '{:#e}'"), nan_pos);
+  check(STR("answer is '-nan'"), STR("answer is '{:#e}'"), nan_neg);
+
+  // *** zero-padding & width ***
+  check(STR("answer is '3.125000e-02'"), STR("answer is '{:07e}'"), 0.03125);
+  check(STR("answer is '+3.125000e-02'"), STR("answer is '{:+07e}'"), 0.03125);
+  check(STR("answer is '+3.125000e-02'"), STR("answer is '{:+08e}'"), 0.03125);
+  check(STR("answer is '+3.125000e-02'"), STR("answer is '{:+09e}'"), 0.03125);
+
+  check(STR("answer is '003.125000e-02'"), STR("answer is '{:014e}'"), 0.03125);
+  check(STR("answer is '003.125000e-02'"), STR("answer is '{:-014e}'"), 0.03125);
+  check(STR("answer is '+03.125000e-02'"), STR("answer is '{:+014e}'"), 0.03125);
+  check(STR("answer is ' 03.125000e-02'"), STR("answer is '{: 014e}'"), 0.03125);
+
+  check(STR("answer is '       inf'"), STR("answer is '{:010e}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       inf'"), STR("answer is '{:-010e}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '      +inf'"), STR("answer is '{:+010e}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       inf'"), STR("answer is '{: 010e}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '      -inf'"), STR("answer is '{:010e}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{:-010e}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{:+010e}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{: 010e}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '       nan'"), STR("answer is '{:010e}'"), nan_pos);
+  check(STR("answer is '       nan'"), STR("answer is '{:-010e}'"), nan_pos);
+  check(STR("answer is '      +nan'"), STR("answer is '{:+010e}'"), nan_pos);
+  check(STR("answer is '       nan'"), STR("answer is '{: 010e}'"), nan_pos);
+
+  check(STR("answer is '      -nan'"), STR("answer is '{:010e}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{:-010e}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{:+010e}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{: 010e}'"), nan_neg);
+
+  // *** precision ***
+  check(STR("answer is '3e-02'"), STR("answer is '{:.0e}'"), 0.03125);
+  check(STR("answer is '3.1e-02'"), STR("answer is '{:.1e}'"), 0.03125);
+  check(STR("answer is '3.125e-02'"), STR("answer is '{:.3e}'"), 0.03125);
+  check(STR("answer is '3.1250000000e-02'"), STR("answer is '{:.10e}'"), 0.03125);
+
+  // *** locale-specific form ***
+  // See locale-specific_form.pass.cpp
+}
+
+template <class F, class CharT, class TestFunction>
+void format_test_floating_point_scientific_upper_case(TestFunction check) {
+  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
+  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"
+
+  // *** align-fill & width ***
+  check(STR("answer is '   2.500000E-01'"), STR("answer is '{:15E}'"), F(0.25));
+  check(STR("answer is '   2.500000E-01'"), STR("answer is '{:>15E}'"), F(0.25));
+  check(STR("answer is '2.500000E-01   '"), STR("answer is '{:<15E}'"), F(0.25));
+  check(STR("answer is ' 2.500000E-01  '"), STR("answer is '{:^15E}'"), F(0.25));
+
+  check(STR("answer is '---1.250000E-01'"), STR("answer is '{:->15E}'"), F(125e-3));
+  check(STR("answer is '1.250000E-01---'"), STR("answer is '{:-<15E}'"), F(125e-3));
+  check(STR("answer is '-1.250000E-01--'"), STR("answer is '{:-^15E}'"), F(125e-3));
+
+  check(STR("answer is '***INF'"), STR("answer is '{:*>6E}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'INF***'"), STR("answer is '{:*<6E}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '*INF**'"), STR("answer is '{:*^6E}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '###-INF'"), STR("answer is '{:#>7E}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF###'"), STR("answer is '{:#<7E}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '#-INF##'"), STR("answer is '{:#^7E}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '^^^NAN'"), STR("answer is '{:^>6E}'"), nan_pos);
+  check(STR("answer is 'NAN^^^'"), STR("answer is '{:^<6E}'"), nan_pos);
+  check(STR("answer is '^NAN^^'"), STR("answer is '{:^^6E}'"), nan_pos);
+
+  check(STR("answer is '000-NAN'"), STR("answer is '{:0>7E}'"), nan_neg);
+  check(STR("answer is '-NAN000'"), STR("answer is '{:0<7E}'"), nan_neg);
+  check(STR("answer is '0-NAN00'"), STR("answer is '{:0^7E}'"), nan_neg);
+
+  // Test whether zero padding is ignored
+  check(STR("answer is '   2.500000E-01'"), STR("answer is '{:>015E}'"), F(0.25));
+  check(STR("answer is '2.500000E-01   '"), STR("answer is '{:<015E}'"), F(0.25));
+  check(STR("answer is ' 2.500000E-01  '"), STR("answer is '{:^015E}'"), F(0.25));
+
+  // *** Sign ***
+  check(STR("answer is '0.000000E+00'"), STR("answer is '{:E}'"), F(0));
+  check(STR("answer is '0.000000E+00'"), STR("answer is '{:-E}'"), F(0));
+  check(STR("answer is '+0.000000E+00'"), STR("answer is '{:+E}'"), F(0));
+  check(STR("answer is ' 0.000000E+00'"), STR("answer is '{: E}'"), F(0));
+
+  check(STR("answer is '-0.000000E+00'"), STR("answer is '{:E}'"), F(-0.));
+  check(STR("answer is '-0.000000E+00'"), STR("answer is '{:-E}'"), F(-0.));
+  check(STR("answer is '-0.000000E+00'"), STR("answer is '{:+E}'"), F(-0.));
+  check(STR("answer is '-0.000000E+00'"), STR("answer is '{: E}'"), F(-0.));
+
+  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
+  check(STR("answer is 'INF'"), STR("answer is '{:E}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'INF'"), STR("answer is '{:-E}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '+INF'"), STR("answer is '{:+E}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is ' INF'"), STR("answer is '{: E}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '-INF'"), STR("answer is '{:E}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{:-E}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{:+E}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{: E}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'NAN'"), STR("answer is '{:E}'"), nan_pos);
+  check(STR("answer is 'NAN'"), STR("answer is '{:-E}'"), nan_pos);
+  check(STR("answer is '+NAN'"), STR("answer is '{:+E}'"), nan_pos);
+  check(STR("answer is ' NAN'"), STR("answer is '{: E}'"), nan_pos);
+
+  check(STR("answer is '-NAN'"), STR("answer is '{:E}'"), nan_neg);
+  check(STR("answer is '-NAN'"), STR("answer is '{:-E}'"), nan_neg);
+  check(STR("answer is '-NAN'"), STR("answer is '{:+E}'"), nan_neg);
+  check(STR("answer is '-NAN'"), STR("answer is '{: E}'"), nan_neg);
+
+  // *** alternate form **
+  // When precision is zero there's no decimal point except when the alternate form is specified.
+  check(STR("answer is '0E+00'"), STR("answer is '{:.0E}'"), F(0));
+  check(STR("answer is '0.E+00'"), STR("answer is '{:#.0E}'"), F(0));
+
+  check(STR("answer is '0.000000E+00'"), STR("answer is '{:#E}'"), F(0));
+  check(STR("answer is '2.500000E+00'"), STR("answer is '{:#E}'"), F(2.5));
+
+  check(STR("answer is 'INF'"), STR("answer is '{:#E}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{:#E}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'NAN'"), STR("answer is '{:#E}'"), nan_pos);
+  check(STR("answer is '-NAN'"), STR("answer is '{:#E}'"), nan_neg);
+
+  // *** zero-padding & width ***
+  check(STR("answer is '3.125000E-02'"), STR("answer is '{:07E}'"), 0.03125);
+  check(STR("answer is '+3.125000E-02'"), STR("answer is '{:+07E}'"), 0.03125);
+  check(STR("answer is '+3.125000E-02'"), STR("answer is '{:+08E}'"), 0.03125);
+  check(STR("answer is '+3.125000E-02'"), STR("answer is '{:+09E}'"), 0.03125);
+
+  check(STR("answer is '003.125000E-02'"), STR("answer is '{:014E}'"), 0.03125);
+  check(STR("answer is '003.125000E-02'"), STR("answer is '{:-014E}'"), 0.03125);
+  check(STR("answer is '+03.125000E-02'"), STR("answer is '{:+014E}'"), 0.03125);
+  check(STR("answer is ' 03.125000E-02'"), STR("answer is '{: 014E}'"), 0.03125);
+
+  check(STR("answer is '       INF'"), STR("answer is '{:010E}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       INF'"), STR("answer is '{:-010E}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '      +INF'"), STR("answer is '{:+010E}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       INF'"), STR("answer is '{: 010E}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '      -INF'"), STR("answer is '{:010E}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -INF'"), STR("answer is '{:-010E}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -INF'"), STR("answer is '{:+010E}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -INF'"), STR("answer is '{: 010E}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '       NAN'"), STR("answer is '{:010E}'"), nan_pos);
+  check(STR("answer is '       NAN'"), STR("answer is '{:-010E}'"), nan_pos);
+  check(STR("answer is '      +NAN'"), STR("answer is '{:+010E}'"), nan_pos);
+  check(STR("answer is '       NAN'"), STR("answer is '{: 010E}'"), nan_pos);
+
+  check(STR("answer is '      -NAN'"), STR("answer is '{:010E}'"), nan_neg);
+  check(STR("answer is '      -NAN'"), STR("answer is '{:-010E}'"), nan_neg);
+  check(STR("answer is '      -NAN'"), STR("answer is '{:+010E}'"), nan_neg);
+  check(STR("answer is '      -NAN'"), STR("answer is '{: 010E}'"), nan_neg);
+
+  // *** precision ***
+  check(STR("answer is '3E-02'"), STR("answer is '{:.0E}'"), 0.03125);
+  check(STR("answer is '3.1E-02'"), STR("answer is '{:.1E}'"), 0.03125);
+  check(STR("answer is '3.125E-02'"), STR("answer is '{:.3E}'"), 0.03125);
+  check(STR("answer is '3.1250000000E-02'"), STR("answer is '{:.10E}'"), 0.03125);
+
+  // *** locale-specific form ***
+  // See locale-specific_form.pass.cpp
+}
+
+template <class F, class CharT, class TestFunction>
+void format_test_floating_point_fixed_lower_case(TestFunction check) {
+  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
+  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"
+
+  // *** align-fill & width ***
+  check(STR("answer is '   0.250000'"), STR("answer is '{:11f}'"), F(0.25));
+  check(STR("answer is '   0.250000'"), STR("answer is '{:>11f}'"), F(0.25));
+  check(STR("answer is '0.250000   '"), STR("answer is '{:<11f}'"), F(0.25));
+  check(STR("answer is ' 0.250000  '"), STR("answer is '{:^11f}'"), F(0.25));
+
+  check(STR("answer is '---0.125000'"), STR("answer is '{:->11f}'"), F(125e-3));
+  check(STR("answer is '0.125000---'"), STR("answer is '{:-<11f}'"), F(125e-3));
+  check(STR("answer is '-0.125000--'"), STR("answer is '{:-^11f}'"), F(125e-3));
+
+  check(STR("answer is '***inf'"), STR("answer is '{:*>6f}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'inf***'"), STR("answer is '{:*<6f}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '*inf**'"), STR("answer is '{:*^6f}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '###-inf'"), STR("answer is '{:#>7f}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf###'"), STR("answer is '{:#<7f}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '#-inf##'"), STR("answer is '{:#^7f}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '^^^nan'"), STR("answer is '{:^>6f}'"), nan_pos);
+  check(STR("answer is 'nan^^^'"), STR("answer is '{:^<6f}'"), nan_pos);
+  check(STR("answer is '^nan^^'"), STR("answer is '{:^^6f}'"), nan_pos);
+
+  check(STR("answer is '000-nan'"), STR("answer is '{:0>7f}'"), nan_neg);
+  check(STR("answer is '-nan000'"), STR("answer is '{:0<7f}'"), nan_neg);
+  check(STR("answer is '0-nan00'"), STR("answer is '{:0^7f}'"), nan_neg);
+
+  // Test whether zero padding is ignored
+  check(STR("answer is '   0.250000'"), STR("answer is '{:>011f}'"), F(0.25));
+  check(STR("answer is '0.250000   '"), STR("answer is '{:<011f}'"), F(0.25));
+  check(STR("answer is ' 0.250000  '"), STR("answer is '{:^011f}'"), F(0.25));
+
+  // *** Sign ***
+  check(STR("answer is '0.000000'"), STR("answer is '{:f}'"), F(0));
+  check(STR("answer is '0.000000'"), STR("answer is '{:-f}'"), F(0));
+  check(STR("answer is '+0.000000'"), STR("answer is '{:+f}'"), F(0));
+  check(STR("answer is ' 0.000000'"), STR("answer is '{: f}'"), F(0));
+
+  check(STR("answer is '-0.000000'"), STR("answer is '{:f}'"), F(-0.));
+  check(STR("answer is '-0.000000'"), STR("answer is '{:-f}'"), F(-0.));
+  check(STR("answer is '-0.000000'"), STR("answer is '{:+f}'"), F(-0.));
+  check(STR("answer is '-0.000000'"), STR("answer is '{: f}'"), F(-0.));
+
+  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
+  check(STR("answer is 'inf'"), STR("answer is '{:f}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'inf'"), STR("answer is '{:-f}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '+inf'"), STR("answer is '{:+f}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is ' inf'"), STR("answer is '{: f}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '-inf'"), STR("answer is '{:f}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:-f}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:+f}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{: f}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'nan'"), STR("answer is '{:f}'"), nan_pos);
+  check(STR("answer is 'nan'"), STR("answer is '{:-f}'"), nan_pos);
+  check(STR("answer is '+nan'"), STR("answer is '{:+f}'"), nan_pos);
+  check(STR("answer is ' nan'"), STR("answer is '{: f}'"), nan_pos);
+
+  check(STR("answer is '-nan'"), STR("answer is '{:f}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{:-f}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{:+f}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{: f}'"), nan_neg);
+
+  // *** alternate form **
+  // When precision is zero there's no decimal point except when the alternate form is specified.
+  check(STR("answer is '0'"), STR("answer is '{:.0f}'"), F(0));
+  check(STR("answer is '0.'"), STR("answer is '{:#.0f}'"), F(0));
+
+  check(STR("answer is '0.000000'"), STR("answer is '{:#f}'"), F(0));
+  check(STR("answer is '2.500000'"), STR("answer is '{:#f}'"), F(2.5));
+
+  check(STR("answer is 'inf'"), STR("answer is '{:#f}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:#f}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'nan'"), STR("answer is '{:#f}'"), nan_pos);
+  check(STR("answer is '-nan'"), STR("answer is '{:#f}'"), nan_neg);
+
+  // *** zero-padding & width ***
+  check(STR("answer is '0.031250'"), STR("answer is '{:07f}'"), 0.03125);
+  check(STR("answer is '+0.031250'"), STR("answer is '{:+07f}'"), 0.03125);
+  check(STR("answer is '+0.031250'"), STR("answer is '{:+08f}'"), 0.03125);
+  check(STR("answer is '+0.031250'"), STR("answer is '{:+09f}'"), 0.03125);
+
+  check(STR("answer is '000.031250'"), STR("answer is '{:010f}'"), 0.03125);
+  check(STR("answer is '000.031250'"), STR("answer is '{:-010f}'"), 0.03125);
+  check(STR("answer is '+00.031250'"), STR("answer is '{:+010f}'"), 0.03125);
+  check(STR("answer is ' 00.031250'"), STR("answer is '{: 010f}'"), 0.03125);
+
+  check(STR("answer is '       inf'"), STR("answer is '{:010f}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       inf'"), STR("answer is '{:-010f}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '      +inf'"), STR("answer is '{:+010f}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       inf'"), STR("answer is '{: 010f}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '      -inf'"), STR("answer is '{:010f}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{:-010f}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{:+010f}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{: 010f}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '       nan'"), STR("answer is '{:010f}'"), nan_pos);
+  check(STR("answer is '       nan'"), STR("answer is '{:-010f}'"), nan_pos);
+  check(STR("answer is '      +nan'"), STR("answer is '{:+010f}'"), nan_pos);
+  check(STR("answer is '       nan'"), STR("answer is '{: 010f}'"), nan_pos);
+
+  check(STR("answer is '      -nan'"), STR("answer is '{:010f}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{:-010f}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{:+010f}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{: 010f}'"), nan_neg);
+
+  // *** precision ***
+  check(STR("answer is '0'"), STR("answer is '{:.0f}'"), 0.03125);
+  check(STR("answer is '0.0'"), STR("answer is '{:.1f}'"), 0.03125);
+  check(STR("answer is '0.03125'"), STR("answer is '{:.5f}'"), 0.03125);
+  check(STR("answer is '0.0312500000'"), STR("answer is '{:.10f}'"), 0.03125);
+
+  // *** locale-specific form ***
+  // See locale-specific_form.pass.cpp
+}
+
+template <class F, class CharT, class TestFunction>
+void format_test_floating_point_fixed_upper_case(TestFunction check) {
+  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
+  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"
+
+  // *** align-fill & width ***
+  check(STR("answer is '   0.250000'"), STR("answer is '{:11F}'"), F(0.25));
+  check(STR("answer is '   0.250000'"), STR("answer is '{:>11F}'"), F(0.25));
+  check(STR("answer is '0.250000   '"), STR("answer is '{:<11F}'"), F(0.25));
+  check(STR("answer is ' 0.250000  '"), STR("answer is '{:^11F}'"), F(0.25));
+
+  check(STR("answer is '---0.125000'"), STR("answer is '{:->11F}'"), F(125e-3));
+  check(STR("answer is '0.125000---'"), STR("answer is '{:-<11F}'"), F(125e-3));
+  check(STR("answer is '-0.125000--'"), STR("answer is '{:-^11F}'"), F(125e-3));
+
+  check(STR("answer is '***INF'"), STR("answer is '{:*>6F}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'INF***'"), STR("answer is '{:*<6F}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '*INF**'"), STR("answer is '{:*^6F}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '###-INF'"), STR("answer is '{:#>7F}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF###'"), STR("answer is '{:#<7F}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '#-INF##'"), STR("answer is '{:#^7F}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '^^^NAN'"), STR("answer is '{:^>6F}'"), nan_pos);
+  check(STR("answer is 'NAN^^^'"), STR("answer is '{:^<6F}'"), nan_pos);
+  check(STR("answer is '^NAN^^'"), STR("answer is '{:^^6F}'"), nan_pos);
+
+  check(STR("answer is '000-NAN'"), STR("answer is '{:0>7F}'"), nan_neg);
+  check(STR("answer is '-NAN000'"), STR("answer is '{:0<7F}'"), nan_neg);
+  check(STR("answer is '0-NAN00'"), STR("answer is '{:0^7F}'"), nan_neg);
+
+  // Test whether zero padding is ignored
+  check(STR("answer is '   0.250000'"), STR("answer is '{:>011F}'"), F(0.25));
+  check(STR("answer is '0.250000   '"), STR("answer is '{:<011F}'"), F(0.25));
+  check(STR("answer is ' 0.250000  '"), STR("answer is '{:^011F}'"), F(0.25));
+
+  // *** Sign ***
+  check(STR("answer is '0.000000'"), STR("answer is '{:F}'"), F(0));
+  check(STR("answer is '0.000000'"), STR("answer is '{:-F}'"), F(0));
+  check(STR("answer is '+0.000000'"), STR("answer is '{:+F}'"), F(0));
+  check(STR("answer is ' 0.000000'"), STR("answer is '{: F}'"), F(0));
+
+  check(STR("answer is '-0.000000'"), STR("answer is '{:F}'"), F(-0.));
+  check(STR("answer is '-0.000000'"), STR("answer is '{:-F}'"), F(-0.));
+  check(STR("answer is '-0.000000'"), STR("answer is '{:+F}'"), F(-0.));
+  check(STR("answer is '-0.000000'"), STR("answer is '{: F}'"), F(-0.));
+
+  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
+  check(STR("answer is 'INF'"), STR("answer is '{:F}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'INF'"), STR("answer is '{:-F}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '+INF'"), STR("answer is '{:+F}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is ' INF'"), STR("answer is '{: F}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '-INF'"), STR("answer is '{:F}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{:-F}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{:+F}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{: F}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'NAN'"), STR("answer is '{:F}'"), nan_pos);
+  check(STR("answer is 'NAN'"), STR("answer is '{:-F}'"), nan_pos);
+  check(STR("answer is '+NAN'"), STR("answer is '{:+F}'"), nan_pos);
+  check(STR("answer is ' NAN'"), STR("answer is '{: F}'"), nan_pos);
+
+  check(STR("answer is '-NAN'"), STR("answer is '{:F}'"), nan_neg);
+  check(STR("answer is '-NAN'"), STR("answer is '{:-F}'"), nan_neg);
+  check(STR("answer is '-NAN'"), STR("answer is '{:+F}'"), nan_neg);
+  check(STR("answer is '-NAN'"), STR("answer is '{: F}'"), nan_neg);
+
+  // *** alternate form **
+  // When precision is zero there's no decimal point except when the alternate form is specified.
+  check(STR("answer is '0'"), STR("answer is '{:.0F}'"), F(0));
+  check(STR("answer is '0.'"), STR("answer is '{:#.0F}'"), F(0));
+
+  check(STR("answer is '0.000000'"), STR("answer is '{:#F}'"), F(0));
+  check(STR("answer is '2.500000'"), STR("answer is '{:#F}'"), F(2.5));
+
+  check(STR("answer is 'INF'"), STR("answer is '{:#F}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{:#F}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'NAN'"), STR("answer is '{:#F}'"), nan_pos);
+  check(STR("answer is '-NAN'"), STR("answer is '{:#F}'"), nan_neg);
+
+  // *** zero-padding & width ***
+  check(STR("answer is '0.031250'"), STR("answer is '{:07F}'"), 0.03125);
+  check(STR("answer is '+0.031250'"), STR("answer is '{:+07F}'"), 0.03125);
+  check(STR("answer is '+0.031250'"), STR("answer is '{:+08F}'"), 0.03125);
+  check(STR("answer is '+0.031250'"), STR("answer is '{:+09F}'"), 0.03125);
+
+  check(STR("answer is '000.031250'"), STR("answer is '{:010F}'"), 0.03125);
+  check(STR("answer is '000.031250'"), STR("answer is '{:-010F}'"), 0.03125);
+  check(STR("answer is '+00.031250'"), STR("answer is '{:+010F}'"), 0.03125);
+  check(STR("answer is ' 00.031250'"), STR("answer is '{: 010F}'"), 0.03125);
+
+  check(STR("answer is '       INF'"), STR("answer is '{:010F}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       INF'"), STR("answer is '{:-010F}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '      +INF'"), STR("answer is '{:+010F}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       INF'"), STR("answer is '{: 010F}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '      -INF'"), STR("answer is '{:010F}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -INF'"), STR("answer is '{:-010F}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -INF'"), STR("answer is '{:+010F}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -INF'"), STR("answer is '{: 010F}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '       NAN'"), STR("answer is '{:010F}'"), nan_pos);
+  check(STR("answer is '       NAN'"), STR("answer is '{:-010F}'"), nan_pos);
+  check(STR("answer is '      +NAN'"), STR("answer is '{:+010F}'"), nan_pos);
+  check(STR("answer is '       NAN'"), STR("answer is '{: 010F}'"), nan_pos);
+
+  check(STR("answer is '      -NAN'"), STR("answer is '{:010F}'"), nan_neg);
+  check(STR("answer is '      -NAN'"), STR("answer is '{:-010F}'"), nan_neg);
+  check(STR("answer is '      -NAN'"), STR("answer is '{:+010F}'"), nan_neg);
+  check(STR("answer is '      -NAN'"), STR("answer is '{: 010F}'"), nan_neg);
+
+  // *** precision ***
+  check(STR("answer is '0'"), STR("answer is '{:.0F}'"), 0.03125);
+  check(STR("answer is '0.0'"), STR("answer is '{:.1F}'"), 0.03125);
+  check(STR("answer is '0.03125'"), STR("answer is '{:.5F}'"), 0.03125);
+  check(STR("answer is '0.0312500000'"), STR("answer is '{:.10F}'"), 0.03125);
+
+  // *** locale-specific form ***
+  // See locale-specific_form.pass.cpp
+}
+
+template <class F, class CharT, class TestFunction>
+void format_test_floating_point_general_lower_case(TestFunction check) {
+  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
+  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"
+
+  // *** align-fill & width ***
+  check(STR("answer is '   0.25'"), STR("answer is '{:7g}'"), F(0.25));
+  check(STR("answer is '   0.25'"), STR("answer is '{:>7g}'"), F(0.25));
+  check(STR("answer is '0.25   '"), STR("answer is '{:<7g}'"), F(0.25));
+  check(STR("answer is ' 0.25  '"), STR("answer is '{:^7g}'"), F(0.25));
+
+  check(STR("answer is '---0.125'"), STR("answer is '{:->8g}'"), F(125e-3));
+  check(STR("answer is '0.125---'"), STR("answer is '{:-<8g}'"), F(125e-3));
+  check(STR("answer is '-0.125--'"), STR("answer is '{:-^8g}'"), F(125e-3));
+
+  check(STR("answer is '***inf'"), STR("answer is '{:*>6g}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'inf***'"), STR("answer is '{:*<6g}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '*inf**'"), STR("answer is '{:*^6g}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '###-inf'"), STR("answer is '{:#>7g}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf###'"), STR("answer is '{:#<7g}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '#-inf##'"), STR("answer is '{:#^7g}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '^^^nan'"), STR("answer is '{:^>6g}'"), nan_pos);
+  check(STR("answer is 'nan^^^'"), STR("answer is '{:^<6g}'"), nan_pos);
+  check(STR("answer is '^nan^^'"), STR("answer is '{:^^6g}'"), nan_pos);
+
+  check(STR("answer is '000-nan'"), STR("answer is '{:0>7g}'"), nan_neg);
+  check(STR("answer is '-nan000'"), STR("answer is '{:0<7g}'"), nan_neg);
+  check(STR("answer is '0-nan00'"), STR("answer is '{:0^7g}'"), nan_neg);
+
+  // Test whether zero padding is ignored
+  check(STR("answer is '   0.25'"), STR("answer is '{:>07g}'"), F(0.25));
+  check(STR("answer is '0.25   '"), STR("answer is '{:<07g}'"), F(0.25));
+  check(STR("answer is ' 0.25  '"), STR("answer is '{:^07g}'"), F(0.25));
+
+  // *** Sign ***
+  check(STR("answer is '0'"), STR("answer is '{:g}'"), F(0));
+  check(STR("answer is '0'"), STR("answer is '{:-g}'"), F(0));
+  check(STR("answer is '+0'"), STR("answer is '{:+g}'"), F(0));
+  check(STR("answer is ' 0'"), STR("answer is '{: g}'"), F(0));
+
+  check(STR("answer is '-0'"), STR("answer is '{:g}'"), F(-0.));
+  check(STR("answer is '-0'"), STR("answer is '{:-g}'"), F(-0.));
+  check(STR("answer is '-0'"), STR("answer is '{:+g}'"), F(-0.));
+  check(STR("answer is '-0'"), STR("answer is '{: g}'"), F(-0.));
+
+  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
+  check(STR("answer is 'inf'"), STR("answer is '{:g}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'inf'"), STR("answer is '{:-g}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '+inf'"), STR("answer is '{:+g}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is ' inf'"), STR("answer is '{: g}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '-inf'"), STR("answer is '{:g}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:-g}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:+g}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{: g}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'nan'"), STR("answer is '{:g}'"), nan_pos);
+  check(STR("answer is 'nan'"), STR("answer is '{:-g}'"), nan_pos);
+  check(STR("answer is '+nan'"), STR("answer is '{:+g}'"), nan_pos);
+  check(STR("answer is ' nan'"), STR("answer is '{: g}'"), nan_pos);
+
+  check(STR("answer is '-nan'"), STR("answer is '{:g}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{:-g}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{:+g}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{: g}'"), nan_neg);
+
+  // *** alternate form **
+  // When precision is zero there's no decimal point except when the alternate form is specified.
+  check(STR("answer is '0'"), STR("answer is '{:.0g}'"), F(0));
+  check(STR("answer is '0.'"), STR("answer is '{:#.0g}'"), F(0));
+
+  check(STR("answer is '0.'"), STR("answer is '{:#g}'"), F(0));
+  check(STR("answer is '2.5'"), STR("answer is '{:#g}'"), F(2.5));
+
+  check(STR("answer is 'inf'"), STR("answer is '{:#g}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:#g}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'nan'"), STR("answer is '{:#g}'"), nan_pos);
+  check(STR("answer is '-nan'"), STR("answer is '{:#g}'"), nan_neg);
+
+  // *** zero-padding & width ***
+  check(STR("answer is '0.03125'"), STR("answer is '{:06g}'"), 0.03125);
+  check(STR("answer is '+0.03125'"), STR("answer is '{:+06g}'"), 0.03125);
+  check(STR("answer is '+0.03125'"), STR("answer is '{:+07g}'"), 0.03125);
+  check(STR("answer is '+0.03125'"), STR("answer is '{:+08g}'"), 0.03125);
+
+  check(STR("answer is '000.03125'"), STR("answer is '{:09g}'"), 0.03125);
+  check(STR("answer is '000.03125'"), STR("answer is '{:-09g}'"), 0.03125);
+  check(STR("answer is '+00.03125'"), STR("answer is '{:+09g}'"), 0.03125);
+  check(STR("answer is ' 00.03125'"), STR("answer is '{: 09g}'"), 0.03125);
+
+  check(STR("answer is '       inf'"), STR("answer is '{:010g}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       inf'"), STR("answer is '{:-010g}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '      +inf'"), STR("answer is '{:+010g}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       inf'"), STR("answer is '{: 010g}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '      -inf'"), STR("answer is '{:010g}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{:-010g}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{:+010g}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{: 010g}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '       nan'"), STR("answer is '{:010g}'"), nan_pos);
+  check(STR("answer is '       nan'"), STR("answer is '{:-010g}'"), nan_pos);
+  check(STR("answer is '      +nan'"), STR("answer is '{:+010g}'"), nan_pos);
+  check(STR("answer is '       nan'"), STR("answer is '{: 010g}'"), nan_pos);
+
+  check(STR("answer is '      -nan'"), STR("answer is '{:010g}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{:-010g}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{:+010g}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{: 010g}'"), nan_neg);
+
+  // *** precision ***
+  check(STR("answer is '0.03'"), STR("answer is '{:.0g}'"), 0.03125);
+  check(STR("answer is '0.03'"), STR("answer is '{:.1g}'"), 0.03125);
+  check(STR("answer is '0.031'"), STR("answer is '{:.2g}'"), 0.03125);
+  check(STR("answer is '0.0312'"), STR("answer is '{:.3g}'"), 0.03125);
+  check(STR("answer is '0.03125'"), STR("answer is '{:.4g}'"), 0.03125);
+  check(STR("answer is '0.03125'"), STR("answer is '{:.5g}'"), 0.03125);
+  check(STR("answer is '0.03125'"), STR("answer is '{:.10g}'"), 0.03125);
+
+  // *** locale-specific form ***
+  // See locale-specific_form.pass.cpp
+}
+
+template <class F, class CharT, class TestFunction>
+void format_test_floating_point_general_upper_case(TestFunction check) {
+  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
+  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"
+
+  // *** align-fill & width ***
+  check(STR("answer is '   0.25'"), STR("answer is '{:7G}'"), F(0.25));
+  check(STR("answer is '   0.25'"), STR("answer is '{:>7G}'"), F(0.25));
+  check(STR("answer is '0.25   '"), STR("answer is '{:<7G}'"), F(0.25));
+  check(STR("answer is ' 0.25  '"), STR("answer is '{:^7G}'"), F(0.25));
+
+  check(STR("answer is '---0.125'"), STR("answer is '{:->8G}'"), F(125e-3));
+  check(STR("answer is '0.125---'"), STR("answer is '{:-<8G}'"), F(125e-3));
+  check(STR("answer is '-0.125--'"), STR("answer is '{:-^8G}'"), F(125e-3));
+
+  check(STR("answer is '***INF'"), STR("answer is '{:*>6G}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'INF***'"), STR("answer is '{:*<6G}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '*INF**'"), STR("answer is '{:*^6G}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '###-INF'"), STR("answer is '{:#>7G}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF###'"), STR("answer is '{:#<7G}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '#-INF##'"), STR("answer is '{:#^7G}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '^^^NAN'"), STR("answer is '{:^>6G}'"), nan_pos);
+  check(STR("answer is 'NAN^^^'"), STR("answer is '{:^<6G}'"), nan_pos);
+  check(STR("answer is '^NAN^^'"), STR("answer is '{:^^6G}'"), nan_pos);
+
+  check(STR("answer is '000-NAN'"), STR("answer is '{:0>7G}'"), nan_neg);
+  check(STR("answer is '-NAN000'"), STR("answer is '{:0<7G}'"), nan_neg);
+  check(STR("answer is '0-NAN00'"), STR("answer is '{:0^7G}'"), nan_neg);
+
+  // Test whether zero padding is ignored
+  check(STR("answer is '   0.25'"), STR("answer is '{:>07G}'"), F(0.25));
+  check(STR("answer is '0.25   '"), STR("answer is '{:<07G}'"), F(0.25));
+  check(STR("answer is ' 0.25  '"), STR("answer is '{:^07G}'"), F(0.25));
+
+  // *** Sign ***
+  check(STR("answer is '0'"), STR("answer is '{:G}'"), F(0));
+  check(STR("answer is '0'"), STR("answer is '{:-G}'"), F(0));
+  check(STR("answer is '+0'"), STR("answer is '{:+G}'"), F(0));
+  check(STR("answer is ' 0'"), STR("answer is '{: G}'"), F(0));
+
+  check(STR("answer is '-0'"), STR("answer is '{:G}'"), F(-0.));
+  check(STR("answer is '-0'"), STR("answer is '{:-G}'"), F(-0.));
+  check(STR("answer is '-0'"), STR("answer is '{:+G}'"), F(-0.));
+  check(STR("answer is '-0'"), STR("answer is '{: G}'"), F(-0.));
+
+  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
+  check(STR("answer is 'INF'"), STR("answer is '{:G}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'INF'"), STR("answer is '{:-G}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '+INF'"), STR("answer is '{:+G}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is ' INF'"), STR("answer is '{: G}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '-INF'"), STR("answer is '{:G}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{:-G}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{:+G}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{: G}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'NAN'"), STR("answer is '{:G}'"), nan_pos);
+  check(STR("answer is 'NAN'"), STR("answer is '{:-G}'"), nan_pos);
+  check(STR("answer is '+NAN'"), STR("answer is '{:+G}'"), nan_pos);
+  check(STR("answer is ' NAN'"), STR("answer is '{: G}'"), nan_pos);
+
+  check(STR("answer is '-NAN'"), STR("answer is '{:G}'"), nan_neg);
+  check(STR("answer is '-NAN'"), STR("answer is '{:-G}'"), nan_neg);
+  check(STR("answer is '-NAN'"), STR("answer is '{:+G}'"), nan_neg);
+  check(STR("answer is '-NAN'"), STR("answer is '{: G}'"), nan_neg);
+
+  // *** alternate form **
+  // When precision is zero there's no decimal point except when the alternate form is specified.
+  check(STR("answer is '0'"), STR("answer is '{:.0G}'"), F(0));
+  check(STR("answer is '0.'"), STR("answer is '{:#.0G}'"), F(0));
+
+  check(STR("answer is '0.'"), STR("answer is '{:#G}'"), F(0));
+  check(STR("answer is '2.5'"), STR("answer is '{:#G}'"), F(2.5));
+
+  check(STR("answer is 'INF'"), STR("answer is '{:#G}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '-INF'"), STR("answer is '{:#G}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'NAN'"), STR("answer is '{:#G}'"), nan_pos);
+  check(STR("answer is '-NAN'"), STR("answer is '{:#G}'"), nan_neg);
+
+  // *** zero-padding & width ***
+  check(STR("answer is '0.03125'"), STR("answer is '{:06G}'"), 0.03125);
+  check(STR("answer is '+0.03125'"), STR("answer is '{:+06G}'"), 0.03125);
+  check(STR("answer is '+0.03125'"), STR("answer is '{:+07G}'"), 0.03125);
+  check(STR("answer is '+0.03125'"), STR("answer is '{:+08G}'"), 0.03125);
+
+  check(STR("answer is '000.03125'"), STR("answer is '{:09G}'"), 0.03125);
+  check(STR("answer is '000.03125'"), STR("answer is '{:-09G}'"), 0.03125);
+  check(STR("answer is '+00.03125'"), STR("answer is '{:+09G}'"), 0.03125);
+  check(STR("answer is ' 00.03125'"), STR("answer is '{: 09G}'"), 0.03125);
+
+  check(STR("answer is '       INF'"), STR("answer is '{:010G}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       INF'"), STR("answer is '{:-010G}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '      +INF'"), STR("answer is '{:+010G}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       INF'"), STR("answer is '{: 010G}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '      -INF'"), STR("answer is '{:010G}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -INF'"), STR("answer is '{:-010G}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -INF'"), STR("answer is '{:+010G}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -INF'"), STR("answer is '{: 010G}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '       NAN'"), STR("answer is '{:010G}'"), nan_pos);
+  check(STR("answer is '       NAN'"), STR("answer is '{:-010G}'"), nan_pos);
+  check(STR("answer is '      +NAN'"), STR("answer is '{:+010G}'"), nan_pos);
+  check(STR("answer is '       NAN'"), STR("answer is '{: 010G}'"), nan_pos);
+
+  check(STR("answer is '      -NAN'"), STR("answer is '{:010G}'"), nan_neg);
+  check(STR("answer is '      -NAN'"), STR("answer is '{:-010G}'"), nan_neg);
+  check(STR("answer is '      -NAN'"), STR("answer is '{:+010G}'"), nan_neg);
+  check(STR("answer is '      -NAN'"), STR("answer is '{: 010G}'"), nan_neg);
+
+  // *** precision ***
+  check(STR("answer is '0.03'"), STR("answer is '{:.0G}'"), 0.03125);
+  check(STR("answer is '0.03'"), STR("answer is '{:.1G}'"), 0.03125);
+  check(STR("answer is '0.031'"), STR("answer is '{:.2G}'"), 0.03125);
+  check(STR("answer is '0.0312'"), STR("answer is '{:.3G}'"), 0.03125);
+  check(STR("answer is '0.03125'"), STR("answer is '{:.4G}'"), 0.03125);
+  check(STR("answer is '0.03125'"), STR("answer is '{:.5G}'"), 0.03125);
+  check(STR("answer is '0.03125'"), STR("answer is '{:.10G}'"), 0.03125);
+
+  // *** locale-specific form ***
+  // See locale-specific_form.pass.cpp
+}
+
+template <class F, class CharT, class TestFunction>
+void format_test_floating_point_default(TestFunction check) {
+  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
+  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"
+
+  // *** align-fill & width ***
+  check(STR("answer is '   0.25'"), STR("answer is '{:7}'"), F(0.25));
+  check(STR("answer is '   0.25'"), STR("answer is '{:>7}'"), F(0.25));
+  check(STR("answer is '0.25   '"), STR("answer is '{:<7}'"), F(0.25));
+  check(STR("answer is ' 0.25  '"), STR("answer is '{:^7}'"), F(0.25));
+
+  check(STR("answer is '---0.125'"), STR("answer is '{:->8}'"), F(125e-3));
+  check(STR("answer is '0.125---'"), STR("answer is '{:-<8}'"), F(125e-3));
+  check(STR("answer is '-0.125--'"), STR("answer is '{:-^8}'"), F(125e-3));
+
+  check(STR("answer is '***inf'"), STR("answer is '{:*>6}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'inf***'"), STR("answer is '{:*<6}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '*inf**'"), STR("answer is '{:*^6}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '###-inf'"), STR("answer is '{:#>7}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf###'"), STR("answer is '{:#<7}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '#-inf##'"), STR("answer is '{:#^7}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '^^^nan'"), STR("answer is '{:^>6}'"), nan_pos);
+  check(STR("answer is 'nan^^^'"), STR("answer is '{:^<6}'"), nan_pos);
+  check(STR("answer is '^nan^^'"), STR("answer is '{:^^6}'"), nan_pos);
+
+  check(STR("answer is '000-nan'"), STR("answer is '{:0>7}'"), nan_neg);
+  check(STR("answer is '-nan000'"), STR("answer is '{:0<7}'"), nan_neg);
+  check(STR("answer is '0-nan00'"), STR("answer is '{:0^7}'"), nan_neg);
+
+  // Test whether zero padding is ignored
+  check(STR("answer is '   0.25'"), STR("answer is '{:>07}'"), F(0.25));
+  check(STR("answer is '0.25   '"), STR("answer is '{:<07}'"), F(0.25));
+  check(STR("answer is ' 0.25  '"), STR("answer is '{:^07}'"), F(0.25));
+
+  // *** Sign ***
+  check(STR("answer is '0'"), STR("answer is '{:}'"), F(0));
+  check(STR("answer is '0'"), STR("answer is '{:-}'"), F(0));
+  check(STR("answer is '+0'"), STR("answer is '{:+}'"), F(0));
+  check(STR("answer is ' 0'"), STR("answer is '{: }'"), F(0));
+
+  check(STR("answer is '-0'"), STR("answer is '{:}'"), F(-0.));
+  check(STR("answer is '-0'"), STR("answer is '{:-}'"), F(-0.));
+  check(STR("answer is '-0'"), STR("answer is '{:+}'"), F(-0.));
+  check(STR("answer is '-0'"), STR("answer is '{: }'"), F(-0.));
+
+  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
+  check(STR("answer is 'inf'"), STR("answer is '{:}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'inf'"), STR("answer is '{:-}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '+inf'"), STR("answer is '{:+}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is ' inf'"), STR("answer is '{: }'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '-inf'"), STR("answer is '{:}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:-}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:+}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{: }'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'nan'"), STR("answer is '{:}'"), nan_pos);
+  check(STR("answer is 'nan'"), STR("answer is '{:-}'"), nan_pos);
+  check(STR("answer is '+nan'"), STR("answer is '{:+}'"), nan_pos);
+  check(STR("answer is ' nan'"), STR("answer is '{: }'"), nan_pos);
+
+  check(STR("answer is '-nan'"), STR("answer is '{:}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{:-}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{:+}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{: }'"), nan_neg);
+
+  // *** alternate form ***
+  check(STR("answer is '0.'"), STR("answer is '{:#}'"), F(0));
+  check(STR("answer is '2.5'"), STR("answer is '{:#}'"), F(2.5));
+
+  check(STR("answer is 'inf'"), STR("answer is '{:#}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:#}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'nan'"), STR("answer is '{:#}'"), nan_pos);
+  check(STR("answer is '-nan'"), STR("answer is '{:#}'"), nan_neg);
+
+  // *** zero-padding & width ***
+  check(STR("answer is '0.03125'"), STR("answer is '{:07}'"), 0.03125);
+  check(STR("answer is '+0.03125'"), STR("answer is '{:+07}'"), 0.03125);
+  check(STR("answer is '+0.03125'"), STR("answer is '{:+08}'"), 0.03125);
+  check(STR("answer is '+00.03125'"), STR("answer is '{:+09}'"), 0.03125);
+
+  check(STR("answer is '0000.03125'"), STR("answer is '{:010}'"), 0.03125);
+  check(STR("answer is '0000.03125'"), STR("answer is '{:-010}'"), 0.03125);
+  check(STR("answer is '+000.03125'"), STR("answer is '{:+010}'"), 0.03125);
+  check(STR("answer is ' 000.03125'"), STR("answer is '{: 010}'"), 0.03125);
+
+  check(STR("answer is '       inf'"), STR("answer is '{:010}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       inf'"), STR("answer is '{:-010}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '      +inf'"), STR("answer is '{:+010}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       inf'"), STR("answer is '{: 010}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '      -inf'"), STR("answer is '{:010}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{:-010}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{:+010}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{: 010}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '       nan'"), STR("answer is '{:010}'"), nan_pos);
+  check(STR("answer is '       nan'"), STR("answer is '{:-010}'"), nan_pos);
+  check(STR("answer is '      +nan'"), STR("answer is '{:+010}'"), nan_pos);
+  check(STR("answer is '       nan'"), STR("answer is '{: 010}'"), nan_pos);
+
+  check(STR("answer is '      -nan'"), STR("answer is '{:010}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{:-010}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{:+010}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{: 010}'"), nan_neg);
+
+  // *** precision ***
+  // See format_test_floating_point_default_precision
+
+  // *** locale-specific form ***
+  // See locale-specific_form.pass.cpp
+}
+
+template <class F, class CharT, class TestFunction>
+void format_test_floating_point_default_precision(TestFunction check) {
+
+  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
+  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"
+
+  // *** align-fill & width ***
+  check(STR("answer is '   0.25'"), STR("answer is '{:7.6}'"), F(0.25));
+  check(STR("answer is '   0.25'"), STR("answer is '{:>7.6}'"), F(0.25));
+  check(STR("answer is '0.25   '"), STR("answer is '{:<7.6}'"), F(0.25));
+  check(STR("answer is ' 0.25  '"), STR("answer is '{:^7.6}'"), F(0.25));
+
+  check(STR("answer is '---0.125'"), STR("answer is '{:->8.6}'"), F(125e-3));
+  check(STR("answer is '0.125---'"), STR("answer is '{:-<8.6}'"), F(125e-3));
+  check(STR("answer is '-0.125--'"), STR("answer is '{:-^8.6}'"), F(125e-3));
+
+  check(STR("answer is '***inf'"), STR("answer is '{:*>6.6}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'inf***'"), STR("answer is '{:*<6.6}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '*inf**'"), STR("answer is '{:*^6.6}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '###-inf'"), STR("answer is '{:#>7.6}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf###'"), STR("answer is '{:#<7.6}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '#-inf##'"), STR("answer is '{:#^7.6}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '^^^nan'"), STR("answer is '{:^>6.6}'"), nan_pos);
+  check(STR("answer is 'nan^^^'"), STR("answer is '{:^<6.6}'"), nan_pos);
+  check(STR("answer is '^nan^^'"), STR("answer is '{:^^6.6}'"), nan_pos);
+
+  check(STR("answer is '000-nan'"), STR("answer is '{:0>7.6}'"), nan_neg);
+  check(STR("answer is '-nan000'"), STR("answer is '{:0<7.6}'"), nan_neg);
+  check(STR("answer is '0-nan00'"), STR("answer is '{:0^7.6}'"), nan_neg);
+
+  // Test whether zero padding is ignored
+  check(STR("answer is '   0.25'"), STR("answer is '{:>07.6}'"), F(0.25));
+  check(STR("answer is '0.25   '"), STR("answer is '{:<07.6}'"), F(0.25));
+  check(STR("answer is ' 0.25  '"), STR("answer is '{:^07.6}'"), F(0.25));
+
+  // *** Sign ***
+  check(STR("answer is '0'"), STR("answer is '{:.6}'"), F(0));
+  check(STR("answer is '0'"), STR("answer is '{:-.6}'"), F(0));
+  check(STR("answer is '+0'"), STR("answer is '{:+.6}'"), F(0));
+  check(STR("answer is ' 0'"), STR("answer is '{: .6}'"), F(0));
+
+  check(STR("answer is '-0'"), STR("answer is '{:.6}'"), F(-0.));
+  check(STR("answer is '-0'"), STR("answer is '{:-.6}'"), F(-0.));
+  check(STR("answer is '-0'"), STR("answer is '{:+.6}'"), F(-0.));
+  check(STR("answer is '-0'"), STR("answer is '{: .6}'"), F(-0.));
+
+  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
+  check(STR("answer is 'inf'"), STR("answer is '{:.6}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is 'inf'"), STR("answer is '{:-.6}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '+inf'"), STR("answer is '{:+.6}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is ' inf'"), STR("answer is '{: .6}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '-inf'"), STR("answer is '{:.6}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:-.6}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:+.6}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{: .6}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'nan'"), STR("answer is '{:.6}'"), nan_pos);
+  check(STR("answer is 'nan'"), STR("answer is '{:-.6}'"), nan_pos);
+  check(STR("answer is '+nan'"), STR("answer is '{:+.6}'"), nan_pos);
+  check(STR("answer is ' nan'"), STR("answer is '{: .6}'"), nan_pos);
+
+  check(STR("answer is '-nan'"), STR("answer is '{:.6}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{:-.6}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{:+.6}'"), nan_neg);
+  check(STR("answer is '-nan'"), STR("answer is '{: .6}'"), nan_neg);
+
+  // *** alternate form **
+  // When precision is zero there's no decimal point except when the alternate form is specified.
+  check(STR("answer is '0'"), STR("answer is '{:.0}'"), F(0));
+  check(STR("answer is '0.'"), STR("answer is '{:#.0}'"), F(0));
+
+  check(STR("answer is '0.'"), STR("answer is '{:#.6}'"), F(0));
+  check(STR("answer is '2.5'"), STR("answer is '{:#.6}'"), F(2.5));
+
+  check(STR("answer is 'inf'"), STR("answer is '{:#.6}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '-inf'"), STR("answer is '{:#.6}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is 'nan'"), STR("answer is '{:#.6}'"), nan_pos);
+  check(STR("answer is '-nan'"), STR("answer is '{:#.6}'"), nan_neg);
+
+  // *** zero-padding & width ***
+  check(STR("answer is '0.03125'"), STR("answer is '{:06.6}'"), 0.03125);
+  check(STR("answer is '+0.03125'"), STR("answer is '{:+06.6}'"), 0.03125);
+  check(STR("answer is '+0.03125'"), STR("answer is '{:+07.6}'"), 0.03125);
+  check(STR("answer is '+0.03125'"), STR("answer is '{:+08.6}'"), 0.03125);
+
+  check(STR("answer is '000.03125'"), STR("answer is '{:09.6}'"), 0.03125);
+  check(STR("answer is '000.03125'"), STR("answer is '{:-09.6}'"), 0.03125);
+  check(STR("answer is '+00.03125'"), STR("answer is '{:+09.6}'"), 0.03125);
+  check(STR("answer is ' 00.03125'"), STR("answer is '{: 09.6}'"), 0.03125);
+
+  check(STR("answer is '       inf'"), STR("answer is '{:010.6}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       inf'"), STR("answer is '{:-010.6}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '      +inf'"), STR("answer is '{:+010.6}'"), std::numeric_limits<F>::infinity());
+  check(STR("answer is '       inf'"), STR("answer is '{: 010.6}'"), std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '      -inf'"), STR("answer is '{:010.6}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{:-010.6}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{:+010.6}'"), -std::numeric_limits<F>::infinity());
+  check(STR("answer is '      -inf'"), STR("answer is '{: 010.6}'"), -std::numeric_limits<F>::infinity());
+
+  check(STR("answer is '       nan'"), STR("answer is '{:010.6}'"), nan_pos);
+  check(STR("answer is '       nan'"), STR("answer is '{:-010.6}'"), nan_pos);
+  check(STR("answer is '      +nan'"), STR("answer is '{:+010.6}'"), nan_pos);
+  check(STR("answer is '       nan'"), STR("answer is '{: 010.6}'"), nan_pos);
+
+  check(STR("answer is '      -nan'"), STR("answer is '{:010.6}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{:-010.6}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{:+010.6}'"), nan_neg);
+  check(STR("answer is '      -nan'"), STR("answer is '{: 010.6}'"), nan_neg);
+
+  // *** precision ***
+  check(STR("answer is '0.03'"), STR("answer is '{:.0}'"), 0.03125);
+  check(STR("answer is '0.03'"), STR("answer is '{:.1}'"), 0.03125);
+  check(STR("answer is '0.031'"), STR("answer is '{:.2}'"), 0.03125);
+  check(STR("answer is '0.0312'"), STR("answer is '{:.3}'"), 0.03125);
+  check(STR("answer is '0.03125'"), STR("answer is '{:.4}'"), 0.03125);
+  check(STR("answer is '0.03125'"), STR("answer is '{:.5}'"), 0.03125);
+  check(STR("answer is '0.03125'"), STR("answer is '{:.10}'"), 0.03125);
+
+  // *** locale-specific form ***
+  // See locale-specific_form.pass.cpp
+}
+
+template <class F, class CharT, class TestFunction, class ExceptionTest>
+void format_test_floating_point(TestFunction check, ExceptionTest check_exception) {
+  format_test_floating_point_hex_lower_case<F, CharT>(check);
+  format_test_floating_point_hex_upper_case<F, CharT>(check);
+  format_test_floating_point_hex_lower_case_precision<F, CharT>(check);
+  format_test_floating_point_hex_upper_case_precision<F, CharT>(check);
+
+  format_test_floating_point_scientific_lower_case<F, CharT>(check);
+  format_test_floating_point_scientific_upper_case<F, CharT>(check);
+
+  format_test_floating_point_fixed_lower_case<F, CharT>(check);
+  format_test_floating_point_fixed_upper_case<F, CharT>(check);
+
+  format_test_floating_point_general_lower_case<F, CharT>(check);
+  format_test_floating_point_general_upper_case<F, CharT>(check);
+
+  format_test_floating_point_default<F, CharT>(check);
+  format_test_floating_point_default_precision<F, CharT>(check);
+
+  // *** type ***
+  for (const auto& fmt : invalid_types<CharT>("aAeEfFgG"))
+    check_exception("The format-spec type has a type not supported for a floating-point argument", fmt, F(1));
+}
+
+template <class CharT, class TestFunction, class ExceptionTest>
+void format_test_floating_point(TestFunction check, ExceptionTest check_exception) {
+  format_test_floating_point<float, CharT>(check, check_exception);
+  format_test_floating_point<double, CharT>(check, check_exception);
+  format_test_floating_point<long double, CharT>(check, check_exception);
+}
+
 template <class CharT, class TestFunction, class ExceptionTest>
 void format_tests(TestFunction check, ExceptionTest check_exception) {
   // *** Test escaping  ***
@@ -1115,12 +2607,10 @@ void format_tests(TestFunction check, ExceptionTest check_exception) {
   format_test_unsigned_integer<CharT>(check, check_exception);
 
   // *** Test floating point format argument ***
-// TODO FMT Enable after floating-point support has been enabled
-#if 0
-  check(STR("hello 42.000000"), STR("hello {}"), static_cast<float>(42));
-  check(STR("hello 42.000000"), STR("hello {}"), static_cast<double>(42));
-  check(STR("hello 42.000000"), STR("hello {}"), static_cast<long double>(42));
-#endif
+  check(STR("hello 42"), STR("hello {}"), static_cast<float>(42));
+  check(STR("hello 42"), STR("hello {}"), static_cast<double>(42));
+  check(STR("hello 42"), STR("hello {}"), static_cast<long double>(42));
+  format_test_floating_point<CharT>(check, check_exception);
 }
 
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS

diff  --git a/libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp b/libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp
index 7fe6907f2f4bd..5d86e46be7e6b 100644
--- a/libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp
@@ -110,6 +110,7 @@ struct numpunct<char> : std::numpunct<char> {
 
   std::string do_grouping() const override { return "\1\2\3\2\1"; };
   char do_thousands_sep() const override { return '_'; }
+  char do_decimal_point() const override { return '#'; }
 };
 
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
@@ -120,6 +121,7 @@ struct numpunct<wchar_t> : std::numpunct<wchar_t> {
 
   std::string do_grouping() const override { return "\1\2\3\2\1"; };
   wchar_t do_thousands_sep() const override { return L'_'; }
+  wchar_t do_decimal_point() const override { return L'#'; }
 };
 #endif
 
@@ -607,10 +609,1725 @@ void test_integer() {
   test(STR("-0X004_A"), loc, STR("{:#08LX}"), -0x4a);
 }
 
+template <class F, class CharT>
+void test_floating_point_hex_lower_case() {
+  std::locale loc = std::locale(std::locale(), new numpunct<CharT>());
+  std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+  // *** Basic ***
+  std::locale::global(en_US);
+  test(STR("1.23456p-3"), STR("{:La}"), F(0x1.23456p-3));
+  test(STR("1.23456p-2"), STR("{:La}"), F(0x1.23456p-2));
+  test(STR("1.23456p-1"), STR("{:La}"), F(0x1.23456p-1));
+  test(STR("1.23456p+0"), STR("{:La}"), F(0x1.23456p0));
+  test(STR("1.23456p+1"), STR("{:La}"), F(0x1.23456p+1));
+  test(STR("1.23456p+2"), STR("{:La}"), F(0x1.23456p+2));
+  test(STR("1.23456p+3"), STR("{:La}"), F(0x1.23456p+3));
+  test(STR("1.23456p+20"), STR("{:La}"), F(0x1.23456p+20));
+
+  std::locale::global(loc);
+  test(STR("1#23456p-3"), STR("{:La}"), F(0x1.23456p-3));
+  test(STR("1#23456p-2"), STR("{:La}"), F(0x1.23456p-2));
+  test(STR("1#23456p-1"), STR("{:La}"), F(0x1.23456p-1));
+  test(STR("1#23456p+0"), STR("{:La}"), F(0x1.23456p0));
+  test(STR("1#23456p+1"), STR("{:La}"), F(0x1.23456p+1));
+  test(STR("1#23456p+2"), STR("{:La}"), F(0x1.23456p+2));
+  test(STR("1#23456p+3"), STR("{:La}"), F(0x1.23456p+3));
+  test(STR("1#23456p+20"), STR("{:La}"), F(0x1.23456p+20));
+
+  test(STR("1.23456p-3"), en_US, STR("{:La}"), F(0x1.23456p-3));
+  test(STR("1.23456p-2"), en_US, STR("{:La}"), F(0x1.23456p-2));
+  test(STR("1.23456p-1"), en_US, STR("{:La}"), F(0x1.23456p-1));
+  test(STR("1.23456p+0"), en_US, STR("{:La}"), F(0x1.23456p0));
+  test(STR("1.23456p+1"), en_US, STR("{:La}"), F(0x1.23456p+1));
+  test(STR("1.23456p+2"), en_US, STR("{:La}"), F(0x1.23456p+2));
+  test(STR("1.23456p+3"), en_US, STR("{:La}"), F(0x1.23456p+3));
+  test(STR("1.23456p+20"), en_US, STR("{:La}"), F(0x1.23456p+20));
+
+  std::locale::global(en_US);
+  test(STR("1#23456p-3"), loc, STR("{:La}"), F(0x1.23456p-3));
+  test(STR("1#23456p-2"), loc, STR("{:La}"), F(0x1.23456p-2));
+  test(STR("1#23456p-1"), loc, STR("{:La}"), F(0x1.23456p-1));
+  test(STR("1#23456p+0"), loc, STR("{:La}"), F(0x1.23456p0));
+  test(STR("1#23456p+1"), loc, STR("{:La}"), F(0x1.23456p+1));
+  test(STR("1#23456p+2"), loc, STR("{:La}"), F(0x1.23456p+2));
+  test(STR("1#23456p+3"), loc, STR("{:La}"), F(0x1.23456p+3));
+  test(STR("1#23456p+20"), loc, STR("{:La}"), F(0x1.23456p+20));
+
+  // *** Fill, align, zero padding ***
+  std::locale::global(en_US);
+  test(STR("1.23456p+3$$$"), STR("{:$<13La}"), F(0x1.23456p3));
+  test(STR("$$$1.23456p+3"), STR("{:$>13La}"), F(0x1.23456p3));
+  test(STR("$1.23456p+3$$"), STR("{:$^13La}"), F(0x1.23456p3));
+  test(STR("0001.23456p+3"), STR("{:013La}"), F(0x1.23456p3));
+  test(STR("-1.23456p+3$$$"), STR("{:$<14La}"), F(-0x1.23456p3));
+  test(STR("$$$-1.23456p+3"), STR("{:$>14La}"), F(-0x1.23456p3));
+  test(STR("$-1.23456p+3$$"), STR("{:$^14La}"), F(-0x1.23456p3));
+  test(STR("-0001.23456p+3"), STR("{:014La}"), F(-0x1.23456p3));
+
+  std::locale::global(loc);
+  test(STR("1#23456p+3$$$"), STR("{:$<13La}"), F(0x1.23456p3));
+  test(STR("$$$1#23456p+3"), STR("{:$>13La}"), F(0x1.23456p3));
+  test(STR("$1#23456p+3$$"), STR("{:$^13La}"), F(0x1.23456p3));
+  test(STR("0001#23456p+3"), STR("{:013La}"), F(0x1.23456p3));
+  test(STR("-1#23456p+3$$$"), STR("{:$<14La}"), F(-0x1.23456p3));
+  test(STR("$$$-1#23456p+3"), STR("{:$>14La}"), F(-0x1.23456p3));
+  test(STR("$-1#23456p+3$$"), STR("{:$^14La}"), F(-0x1.23456p3));
+  test(STR("-0001#23456p+3"), STR("{:014La}"), F(-0x1.23456p3));
+
+  test(STR("1.23456p+3$$$"), en_US, STR("{:$<13La}"), F(0x1.23456p3));
+  test(STR("$$$1.23456p+3"), en_US, STR("{:$>13La}"), F(0x1.23456p3));
+  test(STR("$1.23456p+3$$"), en_US, STR("{:$^13La}"), F(0x1.23456p3));
+  test(STR("0001.23456p+3"), en_US, STR("{:013La}"), F(0x1.23456p3));
+  test(STR("-1.23456p+3$$$"), en_US, STR("{:$<14La}"), F(-0x1.23456p3));
+  test(STR("$$$-1.23456p+3"), en_US, STR("{:$>14La}"), F(-0x1.23456p3));
+  test(STR("$-1.23456p+3$$"), en_US, STR("{:$^14La}"), F(-0x1.23456p3));
+  test(STR("-0001.23456p+3"), en_US, STR("{:014La}"), F(-0x1.23456p3));
+
+  std::locale::global(en_US);
+  test(STR("1#23456p+3$$$"), loc, STR("{:$<13La}"), F(0x1.23456p3));
+  test(STR("$$$1#23456p+3"), loc, STR("{:$>13La}"), F(0x1.23456p3));
+  test(STR("$1#23456p+3$$"), loc, STR("{:$^13La}"), F(0x1.23456p3));
+  test(STR("0001#23456p+3"), loc, STR("{:013La}"), F(0x1.23456p3));
+  test(STR("-1#23456p+3$$$"), loc, STR("{:$<14La}"), F(-0x1.23456p3));
+  test(STR("$$$-1#23456p+3"), loc, STR("{:$>14La}"), F(-0x1.23456p3));
+  test(STR("$-1#23456p+3$$"), loc, STR("{:$^14La}"), F(-0x1.23456p3));
+  test(STR("-0001#23456p+3"), loc, STR("{:014La}"), F(-0x1.23456p3));
+}
+
+template <class F, class CharT>
+void test_floating_point_hex_upper_case() {
+  std::locale loc = std::locale(std::locale(), new numpunct<CharT>());
+  std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+  // *** Basic ***
+  std::locale::global(en_US);
+  test(STR("1.23456P-3"), STR("{:LA}"), F(0x1.23456p-3));
+  test(STR("1.23456P-2"), STR("{:LA}"), F(0x1.23456p-2));
+  test(STR("1.23456P-1"), STR("{:LA}"), F(0x1.23456p-1));
+  test(STR("1.23456P+0"), STR("{:LA}"), F(0x1.23456p0));
+  test(STR("1.23456P+1"), STR("{:LA}"), F(0x1.23456p+1));
+  test(STR("1.23456P+2"), STR("{:LA}"), F(0x1.23456p+2));
+  test(STR("1.23456P+3"), STR("{:LA}"), F(0x1.23456p+3));
+  test(STR("1.23456P+20"), STR("{:LA}"), F(0x1.23456p+20));
+
+  std::locale::global(loc);
+  test(STR("1#23456P-3"), STR("{:LA}"), F(0x1.23456p-3));
+  test(STR("1#23456P-2"), STR("{:LA}"), F(0x1.23456p-2));
+  test(STR("1#23456P-1"), STR("{:LA}"), F(0x1.23456p-1));
+  test(STR("1#23456P+0"), STR("{:LA}"), F(0x1.23456p0));
+  test(STR("1#23456P+1"), STR("{:LA}"), F(0x1.23456p+1));
+  test(STR("1#23456P+2"), STR("{:LA}"), F(0x1.23456p+2));
+  test(STR("1#23456P+3"), STR("{:LA}"), F(0x1.23456p+3));
+  test(STR("1#23456P+20"), STR("{:LA}"), F(0x1.23456p+20));
+
+  test(STR("1.23456P-3"), en_US, STR("{:LA}"), F(0x1.23456p-3));
+  test(STR("1.23456P-2"), en_US, STR("{:LA}"), F(0x1.23456p-2));
+  test(STR("1.23456P-1"), en_US, STR("{:LA}"), F(0x1.23456p-1));
+  test(STR("1.23456P+0"), en_US, STR("{:LA}"), F(0x1.23456p0));
+  test(STR("1.23456P+1"), en_US, STR("{:LA}"), F(0x1.23456p+1));
+  test(STR("1.23456P+2"), en_US, STR("{:LA}"), F(0x1.23456p+2));
+  test(STR("1.23456P+3"), en_US, STR("{:LA}"), F(0x1.23456p+3));
+  test(STR("1.23456P+20"), en_US, STR("{:LA}"), F(0x1.23456p+20));
+
+  std::locale::global(en_US);
+  test(STR("1#23456P-3"), loc, STR("{:LA}"), F(0x1.23456p-3));
+  test(STR("1#23456P-2"), loc, STR("{:LA}"), F(0x1.23456p-2));
+  test(STR("1#23456P-1"), loc, STR("{:LA}"), F(0x1.23456p-1));
+  test(STR("1#23456P+0"), loc, STR("{:LA}"), F(0x1.23456p0));
+  test(STR("1#23456P+1"), loc, STR("{:LA}"), F(0x1.23456p+1));
+  test(STR("1#23456P+2"), loc, STR("{:LA}"), F(0x1.23456p+2));
+  test(STR("1#23456P+3"), loc, STR("{:LA}"), F(0x1.23456p+3));
+  test(STR("1#23456P+20"), loc, STR("{:LA}"), F(0x1.23456p+20));
+
+  // *** Fill, align, zero Padding ***
+  std::locale::global(en_US);
+  test(STR("1.23456P+3$$$"), STR("{:$<13LA}"), F(0x1.23456p3));
+  test(STR("$$$1.23456P+3"), STR("{:$>13LA}"), F(0x1.23456p3));
+  test(STR("$1.23456P+3$$"), STR("{:$^13LA}"), F(0x1.23456p3));
+  test(STR("0001.23456P+3"), STR("{:013LA}"), F(0x1.23456p3));
+  test(STR("-1.23456P+3$$$"), STR("{:$<14LA}"), F(-0x1.23456p3));
+  test(STR("$$$-1.23456P+3"), STR("{:$>14LA}"), F(-0x1.23456p3));
+  test(STR("$-1.23456P+3$$"), STR("{:$^14LA}"), F(-0x1.23456p3));
+  test(STR("-0001.23456P+3"), STR("{:014LA}"), F(-0x1.23456p3));
+
+  std::locale::global(loc);
+  test(STR("1#23456P+3$$$"), STR("{:$<13LA}"), F(0x1.23456p3));
+  test(STR("$$$1#23456P+3"), STR("{:$>13LA}"), F(0x1.23456p3));
+  test(STR("$1#23456P+3$$"), STR("{:$^13LA}"), F(0x1.23456p3));
+  test(STR("0001#23456P+3"), STR("{:013LA}"), F(0x1.23456p3));
+  test(STR("-1#23456P+3$$$"), STR("{:$<14LA}"), F(-0x1.23456p3));
+  test(STR("$$$-1#23456P+3"), STR("{:$>14LA}"), F(-0x1.23456p3));
+  test(STR("$-1#23456P+3$$"), STR("{:$^14LA}"), F(-0x1.23456p3));
+  test(STR("-0001#23456P+3"), STR("{:014LA}"), F(-0x1.23456p3));
+
+  test(STR("1.23456P+3$$$"), en_US, STR("{:$<13LA}"), F(0x1.23456p3));
+  test(STR("$$$1.23456P+3"), en_US, STR("{:$>13LA}"), F(0x1.23456p3));
+  test(STR("$1.23456P+3$$"), en_US, STR("{:$^13LA}"), F(0x1.23456p3));
+  test(STR("0001.23456P+3"), en_US, STR("{:013LA}"), F(0x1.23456p3));
+  test(STR("-1.23456P+3$$$"), en_US, STR("{:$<14LA}"), F(-0x1.23456p3));
+  test(STR("$$$-1.23456P+3"), en_US, STR("{:$>14LA}"), F(-0x1.23456p3));
+  test(STR("$-1.23456P+3$$"), en_US, STR("{:$^14LA}"), F(-0x1.23456p3));
+  test(STR("-0001.23456P+3"), en_US, STR("{:014LA}"), F(-0x1.23456p3));
+
+  std::locale::global(en_US);
+  test(STR("1#23456P+3$$$"), loc, STR("{:$<13LA}"), F(0x1.23456p3));
+  test(STR("$$$1#23456P+3"), loc, STR("{:$>13LA}"), F(0x1.23456p3));
+  test(STR("$1#23456P+3$$"), loc, STR("{:$^13LA}"), F(0x1.23456p3));
+  test(STR("0001#23456P+3"), loc, STR("{:013LA}"), F(0x1.23456p3));
+  test(STR("-1#23456P+3$$$"), loc, STR("{:$<14LA}"), F(-0x1.23456p3));
+  test(STR("$$$-1#23456P+3"), loc, STR("{:$>14LA}"), F(-0x1.23456p3));
+  test(STR("$-1#23456P+3$$"), loc, STR("{:$^14LA}"), F(-0x1.23456p3));
+  test(STR("-0001#23456P+3"), loc, STR("{:014LA}"), F(-0x1.23456p3));
+}
+
+template <class F, class CharT>
+void test_floating_point_hex_lower_case_precision() {
+  std::locale loc = std::locale(std::locale(), new numpunct<CharT>());
+  std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+  // *** Basic ***
+  std::locale::global(en_US);
+  test(STR("1.234560p-3"), STR("{:.6La}"), F(0x1.23456p-3));
+  test(STR("1.234560p-2"), STR("{:.6La}"), F(0x1.23456p-2));
+  test(STR("1.234560p-1"), STR("{:.6La}"), F(0x1.23456p-1));
+  test(STR("1.234560p+0"), STR("{:.6La}"), F(0x1.23456p0));
+  test(STR("1.234560p+1"), STR("{:.6La}"), F(0x1.23456p+1));
+  test(STR("1.234560p+2"), STR("{:.6La}"), F(0x1.23456p+2));
+  test(STR("1.234560p+3"), STR("{:.6La}"), F(0x1.23456p+3));
+  test(STR("1.234560p+20"), STR("{:.6La}"), F(0x1.23456p+20));
+
+  std::locale::global(loc);
+  test(STR("1#234560p-3"), STR("{:.6La}"), F(0x1.23456p-3));
+  test(STR("1#234560p-2"), STR("{:.6La}"), F(0x1.23456p-2));
+  test(STR("1#234560p-1"), STR("{:.6La}"), F(0x1.23456p-1));
+  test(STR("1#234560p+0"), STR("{:.6La}"), F(0x1.23456p0));
+  test(STR("1#234560p+1"), STR("{:.6La}"), F(0x1.23456p+1));
+  test(STR("1#234560p+2"), STR("{:.6La}"), F(0x1.23456p+2));
+  test(STR("1#234560p+3"), STR("{:.6La}"), F(0x1.23456p+3));
+  test(STR("1#234560p+20"), STR("{:.6La}"), F(0x1.23456p+20));
+
+  test(STR("1.234560p-3"), en_US, STR("{:.6La}"), F(0x1.23456p-3));
+  test(STR("1.234560p-2"), en_US, STR("{:.6La}"), F(0x1.23456p-2));
+  test(STR("1.234560p-1"), en_US, STR("{:.6La}"), F(0x1.23456p-1));
+  test(STR("1.234560p+0"), en_US, STR("{:.6La}"), F(0x1.23456p0));
+  test(STR("1.234560p+1"), en_US, STR("{:.6La}"), F(0x1.23456p+1));
+  test(STR("1.234560p+2"), en_US, STR("{:.6La}"), F(0x1.23456p+2));
+  test(STR("1.234560p+3"), en_US, STR("{:.6La}"), F(0x1.23456p+3));
+  test(STR("1.234560p+20"), en_US, STR("{:.6La}"), F(0x1.23456p+20));
+
+  std::locale::global(en_US);
+  test(STR("1#234560p-3"), loc, STR("{:.6La}"), F(0x1.23456p-3));
+  test(STR("1#234560p-2"), loc, STR("{:.6La}"), F(0x1.23456p-2));
+  test(STR("1#234560p-1"), loc, STR("{:.6La}"), F(0x1.23456p-1));
+  test(STR("1#234560p+0"), loc, STR("{:.6La}"), F(0x1.23456p0));
+  test(STR("1#234560p+1"), loc, STR("{:.6La}"), F(0x1.23456p+1));
+  test(STR("1#234560p+2"), loc, STR("{:.6La}"), F(0x1.23456p+2));
+  test(STR("1#234560p+3"), loc, STR("{:.6La}"), F(0x1.23456p+3));
+  test(STR("1#234560p+20"), loc, STR("{:.6La}"), F(0x1.23456p+20));
+
+  // *** Fill, align, zero padding ***
+  std::locale::global(en_US);
+  test(STR("1.234560p+3$$$"), STR("{:$<14.6La}"), F(0x1.23456p3));
+  test(STR("$$$1.234560p+3"), STR("{:$>14.6La}"), F(0x1.23456p3));
+  test(STR("$1.234560p+3$$"), STR("{:$^14.6La}"), F(0x1.23456p3));
+  test(STR("0001.234560p+3"), STR("{:014.6La}"), F(0x1.23456p3));
+  test(STR("-1.234560p+3$$$"), STR("{:$<15.6La}"), F(-0x1.23456p3));
+  test(STR("$$$-1.234560p+3"), STR("{:$>15.6La}"), F(-0x1.23456p3));
+  test(STR("$-1.234560p+3$$"), STR("{:$^15.6La}"), F(-0x1.23456p3));
+  test(STR("-0001.234560p+3"), STR("{:015.6La}"), F(-0x1.23456p3));
+
+  std::locale::global(loc);
+  test(STR("1#234560p+3$$$"), STR("{:$<14.6La}"), F(0x1.23456p3));
+  test(STR("$$$1#234560p+3"), STR("{:$>14.6La}"), F(0x1.23456p3));
+  test(STR("$1#234560p+3$$"), STR("{:$^14.6La}"), F(0x1.23456p3));
+  test(STR("0001#234560p+3"), STR("{:014.6La}"), F(0x1.23456p3));
+  test(STR("-1#234560p+3$$$"), STR("{:$<15.6La}"), F(-0x1.23456p3));
+  test(STR("$$$-1#234560p+3"), STR("{:$>15.6La}"), F(-0x1.23456p3));
+  test(STR("$-1#234560p+3$$"), STR("{:$^15.6La}"), F(-0x1.23456p3));
+  test(STR("-0001#234560p+3"), STR("{:015.6La}"), F(-0x1.23456p3));
+
+  test(STR("1.234560p+3$$$"), en_US, STR("{:$<14.6La}"), F(0x1.23456p3));
+  test(STR("$$$1.234560p+3"), en_US, STR("{:$>14.6La}"), F(0x1.23456p3));
+  test(STR("$1.234560p+3$$"), en_US, STR("{:$^14.6La}"), F(0x1.23456p3));
+  test(STR("0001.234560p+3"), en_US, STR("{:014.6La}"), F(0x1.23456p3));
+  test(STR("-1.234560p+3$$$"), en_US, STR("{:$<15.6La}"), F(-0x1.23456p3));
+  test(STR("$$$-1.234560p+3"), en_US, STR("{:$>15.6La}"), F(-0x1.23456p3));
+  test(STR("$-1.234560p+3$$"), en_US, STR("{:$^15.6La}"), F(-0x1.23456p3));
+  test(STR("-0001.234560p+3"), en_US, STR("{:015.6La}"), F(-0x1.23456p3));
+
+  std::locale::global(en_US);
+  test(STR("1#234560p+3$$$"), loc, STR("{:$<14.6La}"), F(0x1.23456p3));
+  test(STR("$$$1#234560p+3"), loc, STR("{:$>14.6La}"), F(0x1.23456p3));
+  test(STR("$1#234560p+3$$"), loc, STR("{:$^14.6La}"), F(0x1.23456p3));
+  test(STR("0001#234560p+3"), loc, STR("{:014.6La}"), F(0x1.23456p3));
+  test(STR("-1#234560p+3$$$"), loc, STR("{:$<15.6La}"), F(-0x1.23456p3));
+  test(STR("$$$-1#234560p+3"), loc, STR("{:$>15.6La}"), F(-0x1.23456p3));
+  test(STR("$-1#234560p+3$$"), loc, STR("{:$^15.6La}"), F(-0x1.23456p3));
+  test(STR("-0001#234560p+3"), loc, STR("{:015.6La}"), F(-0x1.23456p3));
+}
+
+template <class F, class CharT>
+void test_floating_point_hex_upper_case_precision() {
+  std::locale loc = std::locale(std::locale(), new numpunct<CharT>());
+  std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+  // *** Basic ***
+  std::locale::global(en_US);
+  test(STR("1.234560P-3"), STR("{:.6LA}"), F(0x1.23456p-3));
+  test(STR("1.234560P-2"), STR("{:.6LA}"), F(0x1.23456p-2));
+  test(STR("1.234560P-1"), STR("{:.6LA}"), F(0x1.23456p-1));
+  test(STR("1.234560P+0"), STR("{:.6LA}"), F(0x1.23456p0));
+  test(STR("1.234560P+1"), STR("{:.6LA}"), F(0x1.23456p+1));
+  test(STR("1.234560P+2"), STR("{:.6LA}"), F(0x1.23456p+2));
+  test(STR("1.234560P+3"), STR("{:.6LA}"), F(0x1.23456p+3));
+  test(STR("1.234560P+20"), STR("{:.6LA}"), F(0x1.23456p+20));
+
+  std::locale::global(loc);
+  test(STR("1#234560P-3"), STR("{:.6LA}"), F(0x1.23456p-3));
+  test(STR("1#234560P-2"), STR("{:.6LA}"), F(0x1.23456p-2));
+  test(STR("1#234560P-1"), STR("{:.6LA}"), F(0x1.23456p-1));
+  test(STR("1#234560P+0"), STR("{:.6LA}"), F(0x1.23456p0));
+  test(STR("1#234560P+1"), STR("{:.6LA}"), F(0x1.23456p+1));
+  test(STR("1#234560P+2"), STR("{:.6LA}"), F(0x1.23456p+2));
+  test(STR("1#234560P+3"), STR("{:.6LA}"), F(0x1.23456p+3));
+  test(STR("1#234560P+20"), STR("{:.6LA}"), F(0x1.23456p+20));
+
+  test(STR("1.234560P-3"), en_US, STR("{:.6LA}"), F(0x1.23456p-3));
+  test(STR("1.234560P-2"), en_US, STR("{:.6LA}"), F(0x1.23456p-2));
+  test(STR("1.234560P-1"), en_US, STR("{:.6LA}"), F(0x1.23456p-1));
+  test(STR("1.234560P+0"), en_US, STR("{:.6LA}"), F(0x1.23456p0));
+  test(STR("1.234560P+1"), en_US, STR("{:.6LA}"), F(0x1.23456p+1));
+  test(STR("1.234560P+2"), en_US, STR("{:.6LA}"), F(0x1.23456p+2));
+  test(STR("1.234560P+3"), en_US, STR("{:.6LA}"), F(0x1.23456p+3));
+  test(STR("1.234560P+20"), en_US, STR("{:.6LA}"), F(0x1.23456p+20));
+
+  std::locale::global(en_US);
+  test(STR("1#234560P-3"), loc, STR("{:.6LA}"), F(0x1.23456p-3));
+  test(STR("1#234560P-2"), loc, STR("{:.6LA}"), F(0x1.23456p-2));
+  test(STR("1#234560P-1"), loc, STR("{:.6LA}"), F(0x1.23456p-1));
+  test(STR("1#234560P+0"), loc, STR("{:.6LA}"), F(0x1.23456p0));
+  test(STR("1#234560P+1"), loc, STR("{:.6LA}"), F(0x1.23456p+1));
+  test(STR("1#234560P+2"), loc, STR("{:.6LA}"), F(0x1.23456p+2));
+  test(STR("1#234560P+3"), loc, STR("{:.6LA}"), F(0x1.23456p+3));
+  test(STR("1#234560P+20"), loc, STR("{:.6LA}"), F(0x1.23456p+20));
+
+  // *** Fill, align, zero Padding ***
+  std::locale::global(en_US);
+  test(STR("1.234560P+3$$$"), STR("{:$<14.6LA}"), F(0x1.23456p3));
+  test(STR("$$$1.234560P+3"), STR("{:$>14.6LA}"), F(0x1.23456p3));
+  test(STR("$1.234560P+3$$"), STR("{:$^14.6LA}"), F(0x1.23456p3));
+  test(STR("0001.234560P+3"), STR("{:014.6LA}"), F(0x1.23456p3));
+  test(STR("-1.234560P+3$$$"), STR("{:$<15.6LA}"), F(-0x1.23456p3));
+  test(STR("$$$-1.234560P+3"), STR("{:$>15.6LA}"), F(-0x1.23456p3));
+  test(STR("$-1.234560P+3$$"), STR("{:$^15.6LA}"), F(-0x1.23456p3));
+  test(STR("-0001.234560P+3"), STR("{:015.6LA}"), F(-0x1.23456p3));
+
+  std::locale::global(loc);
+  test(STR("1#234560P+3$$$"), STR("{:$<14.6LA}"), F(0x1.23456p3));
+  test(STR("$$$1#234560P+3"), STR("{:$>14.6LA}"), F(0x1.23456p3));
+  test(STR("$1#234560P+3$$"), STR("{:$^14.6LA}"), F(0x1.23456p3));
+  test(STR("0001#234560P+3"), STR("{:014.6LA}"), F(0x1.23456p3));
+  test(STR("-1#234560P+3$$$"), STR("{:$<15.6LA}"), F(-0x1.23456p3));
+  test(STR("$$$-1#234560P+3"), STR("{:$>15.6LA}"), F(-0x1.23456p3));
+  test(STR("$-1#234560P+3$$"), STR("{:$^15.6LA}"), F(-0x1.23456p3));
+  test(STR("-0001#234560P+3"), STR("{:015.6LA}"), F(-0x1.23456p3));
+
+  test(STR("1.234560P+3$$$"), en_US, STR("{:$<14.6LA}"), F(0x1.23456p3));
+  test(STR("$$$1.234560P+3"), en_US, STR("{:$>14.6LA}"), F(0x1.23456p3));
+  test(STR("$1.234560P+3$$"), en_US, STR("{:$^14.6LA}"), F(0x1.23456p3));
+  test(STR("0001.234560P+3"), en_US, STR("{:014.6LA}"), F(0x1.23456p3));
+  test(STR("-1.234560P+3$$$"), en_US, STR("{:$<15.6LA}"), F(-0x1.23456p3));
+  test(STR("$$$-1.234560P+3"), en_US, STR("{:$>15.6LA}"), F(-0x1.23456p3));
+  test(STR("$-1.234560P+3$$"), en_US, STR("{:$^15.6LA}"), F(-0x1.23456p3));
+  test(STR("-0001.234560P+3"), en_US, STR("{:015.6LA}"), F(-0x1.23456p3));
+
+  std::locale::global(en_US);
+  test(STR("1#234560P+3$$$"), loc, STR("{:$<14.6LA}"), F(0x1.23456p3));
+  test(STR("$$$1#234560P+3"), loc, STR("{:$>14.6LA}"), F(0x1.23456p3));
+  test(STR("$1#234560P+3$$"), loc, STR("{:$^14.6LA}"), F(0x1.23456p3));
+  test(STR("0001#234560P+3"), loc, STR("{:014.6LA}"), F(0x1.23456p3));
+  test(STR("-1#234560P+3$$$"), loc, STR("{:$<15.6LA}"), F(-0x1.23456p3));
+  test(STR("$$$-1#234560P+3"), loc, STR("{:$>15.6LA}"), F(-0x1.23456p3));
+  test(STR("$-1#234560P+3$$"), loc, STR("{:$^15.6LA}"), F(-0x1.23456p3));
+  test(STR("-0001#234560P+3"), loc, STR("{:015.6LA}"), F(-0x1.23456p3));
+}
+
+template <class F, class CharT>
+void test_floating_point_scientific_lower_case() {
+  std::locale loc = std::locale(std::locale(), new numpunct<CharT>());
+  std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+  // *** Basic ***
+  std::locale::global(en_US);
+  test(STR("1.234567e-03"), STR("{:.6Le}"), F(1.234567e-3));
+  test(STR("1.234567e-02"), STR("{:.6Le}"), F(1.234567e-2));
+  test(STR("1.234567e-01"), STR("{:.6Le}"), F(1.234567e-1));
+  test(STR("1.234567e+00"), STR("{:.6Le}"), F(1.234567e0));
+  test(STR("1.234567e+01"), STR("{:.6Le}"), F(1.234567e1));
+  test(STR("1.234567e+02"), STR("{:.6Le}"), F(1.234567e2));
+  test(STR("1.234567e+03"), STR("{:.6Le}"), F(1.234567e3));
+  test(STR("1.234567e+20"), STR("{:.6Le}"), F(1.234567e20));
+  test(STR("-1.234567e-03"), STR("{:.6Le}"), F(-1.234567e-3));
+  test(STR("-1.234567e-02"), STR("{:.6Le}"), F(-1.234567e-2));
+  test(STR("-1.234567e-01"), STR("{:.6Le}"), F(-1.234567e-1));
+  test(STR("-1.234567e+00"), STR("{:.6Le}"), F(-1.234567e0));
+  test(STR("-1.234567e+01"), STR("{:.6Le}"), F(-1.234567e1));
+  test(STR("-1.234567e+02"), STR("{:.6Le}"), F(-1.234567e2));
+  test(STR("-1.234567e+03"), STR("{:.6Le}"), F(-1.234567e3));
+  test(STR("-1.234567e+20"), STR("{:.6Le}"), F(-1.234567e20));
+
+  std::locale::global(loc);
+  test(STR("1#234567e-03"), STR("{:.6Le}"), F(1.234567e-3));
+  test(STR("1#234567e-02"), STR("{:.6Le}"), F(1.234567e-2));
+  test(STR("1#234567e-01"), STR("{:.6Le}"), F(1.234567e-1));
+  test(STR("1#234567e+00"), STR("{:.6Le}"), F(1.234567e0));
+  test(STR("1#234567e+01"), STR("{:.6Le}"), F(1.234567e1));
+  test(STR("1#234567e+02"), STR("{:.6Le}"), F(1.234567e2));
+  test(STR("1#234567e+03"), STR("{:.6Le}"), F(1.234567e3));
+  test(STR("1#234567e+20"), STR("{:.6Le}"), F(1.234567e20));
+  test(STR("-1#234567e-03"), STR("{:.6Le}"), F(-1.234567e-3));
+  test(STR("-1#234567e-02"), STR("{:.6Le}"), F(-1.234567e-2));
+  test(STR("-1#234567e-01"), STR("{:.6Le}"), F(-1.234567e-1));
+  test(STR("-1#234567e+00"), STR("{:.6Le}"), F(-1.234567e0));
+  test(STR("-1#234567e+01"), STR("{:.6Le}"), F(-1.234567e1));
+  test(STR("-1#234567e+02"), STR("{:.6Le}"), F(-1.234567e2));
+  test(STR("-1#234567e+03"), STR("{:.6Le}"), F(-1.234567e3));
+  test(STR("-1#234567e+20"), STR("{:.6Le}"), F(-1.234567e20));
+
+  test(STR("1.234567e-03"), en_US, STR("{:.6Le}"), F(1.234567e-3));
+  test(STR("1.234567e-02"), en_US, STR("{:.6Le}"), F(1.234567e-2));
+  test(STR("1.234567e-01"), en_US, STR("{:.6Le}"), F(1.234567e-1));
+  test(STR("1.234567e+00"), en_US, STR("{:.6Le}"), F(1.234567e0));
+  test(STR("1.234567e+01"), en_US, STR("{:.6Le}"), F(1.234567e1));
+  test(STR("1.234567e+02"), en_US, STR("{:.6Le}"), F(1.234567e2));
+  test(STR("1.234567e+03"), en_US, STR("{:.6Le}"), F(1.234567e3));
+  test(STR("1.234567e+20"), en_US, STR("{:.6Le}"), F(1.234567e20));
+  test(STR("-1.234567e-03"), en_US, STR("{:.6Le}"), F(-1.234567e-3));
+  test(STR("-1.234567e-02"), en_US, STR("{:.6Le}"), F(-1.234567e-2));
+  test(STR("-1.234567e-01"), en_US, STR("{:.6Le}"), F(-1.234567e-1));
+  test(STR("-1.234567e+00"), en_US, STR("{:.6Le}"), F(-1.234567e0));
+  test(STR("-1.234567e+01"), en_US, STR("{:.6Le}"), F(-1.234567e1));
+  test(STR("-1.234567e+02"), en_US, STR("{:.6Le}"), F(-1.234567e2));
+  test(STR("-1.234567e+03"), en_US, STR("{:.6Le}"), F(-1.234567e3));
+  test(STR("-1.234567e+20"), en_US, STR("{:.6Le}"), F(-1.234567e20));
+
+  std::locale::global(en_US);
+  test(STR("1#234567e-03"), loc, STR("{:.6Le}"), F(1.234567e-3));
+  test(STR("1#234567e-02"), loc, STR("{:.6Le}"), F(1.234567e-2));
+  test(STR("1#234567e-01"), loc, STR("{:.6Le}"), F(1.234567e-1));
+  test(STR("1#234567e+00"), loc, STR("{:.6Le}"), F(1.234567e0));
+  test(STR("1#234567e+01"), loc, STR("{:.6Le}"), F(1.234567e1));
+  test(STR("1#234567e+02"), loc, STR("{:.6Le}"), F(1.234567e2));
+  test(STR("1#234567e+03"), loc, STR("{:.6Le}"), F(1.234567e3));
+  test(STR("1#234567e+20"), loc, STR("{:.6Le}"), F(1.234567e20));
+  test(STR("-1#234567e-03"), loc, STR("{:.6Le}"), F(-1.234567e-3));
+  test(STR("-1#234567e-02"), loc, STR("{:.6Le}"), F(-1.234567e-2));
+  test(STR("-1#234567e-01"), loc, STR("{:.6Le}"), F(-1.234567e-1));
+  test(STR("-1#234567e+00"), loc, STR("{:.6Le}"), F(-1.234567e0));
+  test(STR("-1#234567e+01"), loc, STR("{:.6Le}"), F(-1.234567e1));
+  test(STR("-1#234567e+02"), loc, STR("{:.6Le}"), F(-1.234567e2));
+  test(STR("-1#234567e+03"), loc, STR("{:.6Le}"), F(-1.234567e3));
+  test(STR("-1#234567e+20"), loc, STR("{:.6Le}"), F(-1.234567e20));
+
+  // *** Fill, align, zero padding ***
+  std::locale::global(en_US);
+  test(STR("1.234567e+03$$$"), STR("{:$<15.6Le}"), F(1.234567e3));
+  test(STR("$$$1.234567e+03"), STR("{:$>15.6Le}"), F(1.234567e3));
+  test(STR("$1.234567e+03$$"), STR("{:$^15.6Le}"), F(1.234567e3));
+  test(STR("0001.234567e+03"), STR("{:015.6Le}"), F(1.234567e3));
+  test(STR("-1.234567e+03$$$"), STR("{:$<16.6Le}"), F(-1.234567e3));
+  test(STR("$$$-1.234567e+03"), STR("{:$>16.6Le}"), F(-1.234567e3));
+  test(STR("$-1.234567e+03$$"), STR("{:$^16.6Le}"), F(-1.234567e3));
+  test(STR("-0001.234567e+03"), STR("{:016.6Le}"), F(-1.234567e3));
+
+  std::locale::global(loc);
+  test(STR("1#234567e+03$$$"), STR("{:$<15.6Le}"), F(1.234567e3));
+  test(STR("$$$1#234567e+03"), STR("{:$>15.6Le}"), F(1.234567e3));
+  test(STR("$1#234567e+03$$"), STR("{:$^15.6Le}"), F(1.234567e3));
+  test(STR("0001#234567e+03"), STR("{:015.6Le}"), F(1.234567e3));
+  test(STR("-1#234567e+03$$$"), STR("{:$<16.6Le}"), F(-1.234567e3));
+  test(STR("$$$-1#234567e+03"), STR("{:$>16.6Le}"), F(-1.234567e3));
+  test(STR("$-1#234567e+03$$"), STR("{:$^16.6Le}"), F(-1.234567e3));
+  test(STR("-0001#234567e+03"), STR("{:016.6Le}"), F(-1.234567e3));
+
+  test(STR("1.234567e+03$$$"), en_US, STR("{:$<15.6Le}"), F(1.234567e3));
+  test(STR("$$$1.234567e+03"), en_US, STR("{:$>15.6Le}"), F(1.234567e3));
+  test(STR("$1.234567e+03$$"), en_US, STR("{:$^15.6Le}"), F(1.234567e3));
+  test(STR("0001.234567e+03"), en_US, STR("{:015.6Le}"), F(1.234567e3));
+  test(STR("-1.234567e+03$$$"), en_US, STR("{:$<16.6Le}"), F(-1.234567e3));
+  test(STR("$$$-1.234567e+03"), en_US, STR("{:$>16.6Le}"), F(-1.234567e3));
+  test(STR("$-1.234567e+03$$"), en_US, STR("{:$^16.6Le}"), F(-1.234567e3));
+  test(STR("-0001.234567e+03"), en_US, STR("{:016.6Le}"), F(-1.234567e3));
+
+  std::locale::global(en_US);
+  test(STR("1#234567e+03$$$"), loc, STR("{:$<15.6Le}"), F(1.234567e3));
+  test(STR("$$$1#234567e+03"), loc, STR("{:$>15.6Le}"), F(1.234567e3));
+  test(STR("$1#234567e+03$$"), loc, STR("{:$^15.6Le}"), F(1.234567e3));
+  test(STR("0001#234567e+03"), loc, STR("{:015.6Le}"), F(1.234567e3));
+  test(STR("-1#234567e+03$$$"), loc, STR("{:$<16.6Le}"), F(-1.234567e3));
+  test(STR("$$$-1#234567e+03"), loc, STR("{:$>16.6Le}"), F(-1.234567e3));
+  test(STR("$-1#234567e+03$$"), loc, STR("{:$^16.6Le}"), F(-1.234567e3));
+  test(STR("-0001#234567e+03"), loc, STR("{:016.6Le}"), F(-1.234567e3));
+}
+
+template <class F, class CharT>
+void test_floating_point_scientific_upper_case() {
+  std::locale loc = std::locale(std::locale(), new numpunct<CharT>());
+  std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+  // *** Basic ***
+  std::locale::global(en_US);
+  test(STR("1.234567E-03"), STR("{:.6LE}"), F(1.234567e-3));
+  test(STR("1.234567E-02"), STR("{:.6LE}"), F(1.234567e-2));
+  test(STR("1.234567E-01"), STR("{:.6LE}"), F(1.234567e-1));
+  test(STR("1.234567E+00"), STR("{:.6LE}"), F(1.234567e0));
+  test(STR("1.234567E+01"), STR("{:.6LE}"), F(1.234567e1));
+  test(STR("1.234567E+02"), STR("{:.6LE}"), F(1.234567e2));
+  test(STR("1.234567E+03"), STR("{:.6LE}"), F(1.234567e3));
+  test(STR("1.234567E+20"), STR("{:.6LE}"), F(1.234567e20));
+  test(STR("-1.234567E-03"), STR("{:.6LE}"), F(-1.234567e-3));
+  test(STR("-1.234567E-02"), STR("{:.6LE}"), F(-1.234567e-2));
+  test(STR("-1.234567E-01"), STR("{:.6LE}"), F(-1.234567e-1));
+  test(STR("-1.234567E+00"), STR("{:.6LE}"), F(-1.234567e0));
+  test(STR("-1.234567E+01"), STR("{:.6LE}"), F(-1.234567e1));
+  test(STR("-1.234567E+02"), STR("{:.6LE}"), F(-1.234567e2));
+  test(STR("-1.234567E+03"), STR("{:.6LE}"), F(-1.234567e3));
+  test(STR("-1.234567E+20"), STR("{:.6LE}"), F(-1.234567e20));
+
+  std::locale::global(loc);
+  test(STR("1#234567E-03"), STR("{:.6LE}"), F(1.234567e-3));
+  test(STR("1#234567E-02"), STR("{:.6LE}"), F(1.234567e-2));
+  test(STR("1#234567E-01"), STR("{:.6LE}"), F(1.234567e-1));
+  test(STR("1#234567E+00"), STR("{:.6LE}"), F(1.234567e0));
+  test(STR("1#234567E+01"), STR("{:.6LE}"), F(1.234567e1));
+  test(STR("1#234567E+02"), STR("{:.6LE}"), F(1.234567e2));
+  test(STR("1#234567E+03"), STR("{:.6LE}"), F(1.234567e3));
+  test(STR("1#234567E+20"), STR("{:.6LE}"), F(1.234567e20));
+  test(STR("-1#234567E-03"), STR("{:.6LE}"), F(-1.234567e-3));
+  test(STR("-1#234567E-02"), STR("{:.6LE}"), F(-1.234567e-2));
+  test(STR("-1#234567E-01"), STR("{:.6LE}"), F(-1.234567e-1));
+  test(STR("-1#234567E+00"), STR("{:.6LE}"), F(-1.234567e0));
+  test(STR("-1#234567E+01"), STR("{:.6LE}"), F(-1.234567e1));
+  test(STR("-1#234567E+02"), STR("{:.6LE}"), F(-1.234567e2));
+  test(STR("-1#234567E+03"), STR("{:.6LE}"), F(-1.234567e3));
+  test(STR("-1#234567E+20"), STR("{:.6LE}"), F(-1.234567e20));
+
+  test(STR("1.234567E-03"), en_US, STR("{:.6LE}"), F(1.234567e-3));
+  test(STR("1.234567E-02"), en_US, STR("{:.6LE}"), F(1.234567e-2));
+  test(STR("1.234567E-01"), en_US, STR("{:.6LE}"), F(1.234567e-1));
+  test(STR("1.234567E+00"), en_US, STR("{:.6LE}"), F(1.234567e0));
+  test(STR("1.234567E+01"), en_US, STR("{:.6LE}"), F(1.234567e1));
+  test(STR("1.234567E+02"), en_US, STR("{:.6LE}"), F(1.234567e2));
+  test(STR("1.234567E+03"), en_US, STR("{:.6LE}"), F(1.234567e3));
+  test(STR("1.234567E+20"), en_US, STR("{:.6LE}"), F(1.234567e20));
+  test(STR("-1.234567E-03"), en_US, STR("{:.6LE}"), F(-1.234567e-3));
+  test(STR("-1.234567E-02"), en_US, STR("{:.6LE}"), F(-1.234567e-2));
+  test(STR("-1.234567E-01"), en_US, STR("{:.6LE}"), F(-1.234567e-1));
+  test(STR("-1.234567E+00"), en_US, STR("{:.6LE}"), F(-1.234567e0));
+  test(STR("-1.234567E+01"), en_US, STR("{:.6LE}"), F(-1.234567e1));
+  test(STR("-1.234567E+02"), en_US, STR("{:.6LE}"), F(-1.234567e2));
+  test(STR("-1.234567E+03"), en_US, STR("{:.6LE}"), F(-1.234567e3));
+  test(STR("-1.234567E+20"), en_US, STR("{:.6LE}"), F(-1.234567e20));
+
+  std::locale::global(en_US);
+  test(STR("1#234567E-03"), loc, STR("{:.6LE}"), F(1.234567e-3));
+  test(STR("1#234567E-02"), loc, STR("{:.6LE}"), F(1.234567e-2));
+  test(STR("1#234567E-01"), loc, STR("{:.6LE}"), F(1.234567e-1));
+  test(STR("1#234567E+00"), loc, STR("{:.6LE}"), F(1.234567e0));
+  test(STR("1#234567E+01"), loc, STR("{:.6LE}"), F(1.234567e1));
+  test(STR("1#234567E+02"), loc, STR("{:.6LE}"), F(1.234567e2));
+  test(STR("1#234567E+03"), loc, STR("{:.6LE}"), F(1.234567e3));
+  test(STR("1#234567E+20"), loc, STR("{:.6LE}"), F(1.234567e20));
+  test(STR("-1#234567E-03"), loc, STR("{:.6LE}"), F(-1.234567e-3));
+  test(STR("-1#234567E-02"), loc, STR("{:.6LE}"), F(-1.234567e-2));
+  test(STR("-1#234567E-01"), loc, STR("{:.6LE}"), F(-1.234567e-1));
+  test(STR("-1#234567E+00"), loc, STR("{:.6LE}"), F(-1.234567e0));
+  test(STR("-1#234567E+01"), loc, STR("{:.6LE}"), F(-1.234567e1));
+  test(STR("-1#234567E+02"), loc, STR("{:.6LE}"), F(-1.234567e2));
+  test(STR("-1#234567E+03"), loc, STR("{:.6LE}"), F(-1.234567e3));
+  test(STR("-1#234567E+20"), loc, STR("{:.6LE}"), F(-1.234567e20));
+
+  // *** Fill, align, zero padding ***
+  std::locale::global(en_US);
+  test(STR("1.234567E+03$$$"), STR("{:$<15.6LE}"), F(1.234567e3));
+  test(STR("$$$1.234567E+03"), STR("{:$>15.6LE}"), F(1.234567e3));
+  test(STR("$1.234567E+03$$"), STR("{:$^15.6LE}"), F(1.234567e3));
+  test(STR("0001.234567E+03"), STR("{:015.6LE}"), F(1.234567e3));
+  test(STR("-1.234567E+03$$$"), STR("{:$<16.6LE}"), F(-1.234567e3));
+  test(STR("$$$-1.234567E+03"), STR("{:$>16.6LE}"), F(-1.234567e3));
+  test(STR("$-1.234567E+03$$"), STR("{:$^16.6LE}"), F(-1.234567e3));
+  test(STR("-0001.234567E+03"), STR("{:016.6LE}"), F(-1.234567e3));
+
+  std::locale::global(loc);
+  test(STR("1#234567E+03$$$"), STR("{:$<15.6LE}"), F(1.234567e3));
+  test(STR("$$$1#234567E+03"), STR("{:$>15.6LE}"), F(1.234567e3));
+  test(STR("$1#234567E+03$$"), STR("{:$^15.6LE}"), F(1.234567e3));
+  test(STR("0001#234567E+03"), STR("{:015.6LE}"), F(1.234567e3));
+  test(STR("-1#234567E+03$$$"), STR("{:$<16.6LE}"), F(-1.234567e3));
+  test(STR("$$$-1#234567E+03"), STR("{:$>16.6LE}"), F(-1.234567e3));
+  test(STR("$-1#234567E+03$$"), STR("{:$^16.6LE}"), F(-1.234567e3));
+  test(STR("-0001#234567E+03"), STR("{:016.6LE}"), F(-1.234567e3));
+
+  test(STR("1.234567E+03$$$"), en_US, STR("{:$<15.6LE}"), F(1.234567e3));
+  test(STR("$$$1.234567E+03"), en_US, STR("{:$>15.6LE}"), F(1.234567e3));
+  test(STR("$1.234567E+03$$"), en_US, STR("{:$^15.6LE}"), F(1.234567e3));
+  test(STR("0001.234567E+03"), en_US, STR("{:015.6LE}"), F(1.234567e3));
+  test(STR("-1.234567E+03$$$"), en_US, STR("{:$<16.6LE}"), F(-1.234567e3));
+  test(STR("$$$-1.234567E+03"), en_US, STR("{:$>16.6LE}"), F(-1.234567e3));
+  test(STR("$-1.234567E+03$$"), en_US, STR("{:$^16.6LE}"), F(-1.234567e3));
+  test(STR("-0001.234567E+03"), en_US, STR("{:016.6LE}"), F(-1.234567e3));
+
+  std::locale::global(en_US);
+  test(STR("1#234567E+03$$$"), loc, STR("{:$<15.6LE}"), F(1.234567e3));
+  test(STR("$$$1#234567E+03"), loc, STR("{:$>15.6LE}"), F(1.234567e3));
+  test(STR("$1#234567E+03$$"), loc, STR("{:$^15.6LE}"), F(1.234567e3));
+  test(STR("0001#234567E+03"), loc, STR("{:015.6LE}"), F(1.234567e3));
+  test(STR("-1#234567E+03$$$"), loc, STR("{:$<16.6LE}"), F(-1.234567e3));
+  test(STR("$$$-1#234567E+03"), loc, STR("{:$>16.6LE}"), F(-1.234567e3));
+  test(STR("$-1#234567E+03$$"), loc, STR("{:$^16.6LE}"), F(-1.234567e3));
+  test(STR("-0001#234567E+03"), loc, STR("{:016.6LE}"), F(-1.234567e3));
+}
+
+template <class F, class CharT>
+void test_floating_point_fixed_lower_case() {
+  std::locale loc = std::locale(std::locale(), new numpunct<CharT>());
+  std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+  // *** Basic ***
+  std::locale::global(en_US);
+  test(STR("0.000001"), STR("{:.6Lf}"), F(1.234567e-6));
+  test(STR("0.000012"), STR("{:.6Lf}"), F(1.234567e-5));
+  test(STR("0.000123"), STR("{:.6Lf}"), F(1.234567e-4));
+  test(STR("0.001235"), STR("{:.6Lf}"), F(1.234567e-3));
+  test(STR("0.012346"), STR("{:.6Lf}"), F(1.234567e-2));
+  test(STR("0.123457"), STR("{:.6Lf}"), F(1.234567e-1));
+  test(STR("1.234567"), STR("{:.6Lf}"), F(1.234567e0));
+  test(STR("12.345670"), STR("{:.6Lf}"), F(1.234567e1));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("123.456700"), STR("{:.6Lf}"), F(1.234567e2));
+    test(STR("1,234.567000"), STR("{:.6Lf}"), F(1.234567e3));
+    test(STR("12,345.670000"), STR("{:.6Lf}"), F(1.234567e4));
+    test(STR("123,456.700000"), STR("{:.6Lf}"), F(1.234567e5));
+    test(STR("1,234,567.000000"), STR("{:.6Lf}"), F(1.234567e6));
+    test(STR("12,345,670.000000"), STR("{:.6Lf}"), F(1.234567e7));
+    test(STR("123,456,700,000,000,000,000.000000"), STR("{:.6Lf}"), F(1.234567e20));
+  }
+  test(STR("-0.000001"), STR("{:.6Lf}"), F(-1.234567e-6));
+  test(STR("-0.000012"), STR("{:.6Lf}"), F(-1.234567e-5));
+  test(STR("-0.000123"), STR("{:.6Lf}"), F(-1.234567e-4));
+  test(STR("-0.001235"), STR("{:.6Lf}"), F(-1.234567e-3));
+  test(STR("-0.012346"), STR("{:.6Lf}"), F(-1.234567e-2));
+  test(STR("-0.123457"), STR("{:.6Lf}"), F(-1.234567e-1));
+  test(STR("-1.234567"), STR("{:.6Lf}"), F(-1.234567e0));
+  test(STR("-12.345670"), STR("{:.6Lf}"), F(-1.234567e1));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("-123.456700"), STR("{:.6Lf}"), F(-1.234567e2));
+    test(STR("-1,234.567000"), STR("{:.6Lf}"), F(-1.234567e3));
+    test(STR("-12,345.670000"), STR("{:.6Lf}"), F(-1.234567e4));
+    test(STR("-123,456.700000"), STR("{:.6Lf}"), F(-1.234567e5));
+    test(STR("-1,234,567.000000"), STR("{:.6Lf}"), F(-1.234567e6));
+    test(STR("-12,345,670.000000"), STR("{:.6Lf}"), F(-1.234567e7));
+    test(STR("-123,456,700,000,000,000,000.000000"), STR("{:.6Lf}"), F(-1.234567e20));
+  }
+
+  std::locale::global(loc);
+  test(STR("0#000001"), STR("{:.6Lf}"), F(1.234567e-6));
+  test(STR("0#000012"), STR("{:.6Lf}"), F(1.234567e-5));
+  test(STR("0#000123"), STR("{:.6Lf}"), F(1.234567e-4));
+  test(STR("0#001235"), STR("{:.6Lf}"), F(1.234567e-3));
+  test(STR("0#012346"), STR("{:.6Lf}"), F(1.234567e-2));
+  test(STR("0#123457"), STR("{:.6Lf}"), F(1.234567e-1));
+  test(STR("1#234567"), STR("{:.6Lf}"), F(1.234567e0));
+  test(STR("1_2#345670"), STR("{:.6Lf}"), F(1.234567e1));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("12_3#456700"), STR("{:.6Lf}"), F(1.234567e2));
+    test(STR("1_23_4#567000"), STR("{:.6Lf}"), F(1.234567e3));
+    test(STR("12_34_5#670000"), STR("{:.6Lf}"), F(1.234567e4));
+    test(STR("123_45_6#700000"), STR("{:.6Lf}"), F(1.234567e5));
+    test(STR("1_234_56_7#000000"), STR("{:.6Lf}"), F(1.234567e6));
+    test(STR("12_345_67_0#000000"), STR("{:.6Lf}"), F(1.234567e7));
+    test(STR("1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000"), STR("{:.6Lf}"), F(1.234567e20));
+  }
+  test(STR("-0#000001"), STR("{:.6Lf}"), F(-1.234567e-6));
+  test(STR("-0#000012"), STR("{:.6Lf}"), F(-1.234567e-5));
+  test(STR("-0#000123"), STR("{:.6Lf}"), F(-1.234567e-4));
+  test(STR("-0#001235"), STR("{:.6Lf}"), F(-1.234567e-3));
+  test(STR("-0#012346"), STR("{:.6Lf}"), F(-1.234567e-2));
+  test(STR("-0#123457"), STR("{:.6Lf}"), F(-1.234567e-1));
+  test(STR("-1#234567"), STR("{:.6Lf}"), F(-1.234567e0));
+  test(STR("-1_2#345670"), STR("{:.6Lf}"), F(-1.234567e1));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("-12_3#456700"), STR("{:.6Lf}"), F(-1.234567e2));
+    test(STR("-1_23_4#567000"), STR("{:.6Lf}"), F(-1.234567e3));
+    test(STR("-12_34_5#670000"), STR("{:.6Lf}"), F(-1.234567e4));
+    test(STR("-123_45_6#700000"), STR("{:.6Lf}"), F(-1.234567e5));
+    test(STR("-1_234_56_7#000000"), STR("{:.6Lf}"), F(-1.234567e6));
+    test(STR("-12_345_67_0#000000"), STR("{:.6Lf}"), F(-1.234567e7));
+    test(STR("-1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000"), STR("{:.6Lf}"), F(-1.234567e20));
+  }
+
+  test(STR("0.000001"), en_US, STR("{:.6Lf}"), F(1.234567e-6));
+  test(STR("0.000012"), en_US, STR("{:.6Lf}"), F(1.234567e-5));
+  test(STR("0.000123"), en_US, STR("{:.6Lf}"), F(1.234567e-4));
+  test(STR("0.001235"), en_US, STR("{:.6Lf}"), F(1.234567e-3));
+  test(STR("0.012346"), en_US, STR("{:.6Lf}"), F(1.234567e-2));
+  test(STR("0.123457"), en_US, STR("{:.6Lf}"), F(1.234567e-1));
+  test(STR("1.234567"), en_US, STR("{:.6Lf}"), F(1.234567e0));
+  test(STR("12.345670"), en_US, STR("{:.6Lf}"), F(1.234567e1));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("123.456700"), en_US, STR("{:.6Lf}"), F(1.234567e2));
+    test(STR("1,234.567000"), en_US, STR("{:.6Lf}"), F(1.234567e3));
+    test(STR("12,345.670000"), en_US, STR("{:.6Lf}"), F(1.234567e4));
+    test(STR("123,456.700000"), en_US, STR("{:.6Lf}"), F(1.234567e5));
+    test(STR("1,234,567.000000"), en_US, STR("{:.6Lf}"), F(1.234567e6));
+    test(STR("12,345,670.000000"), en_US, STR("{:.6Lf}"), F(1.234567e7));
+    test(STR("123,456,700,000,000,000,000.000000"), en_US, STR("{:.6Lf}"), F(1.234567e20));
+  }
+  test(STR("-0.000001"), en_US, STR("{:.6Lf}"), F(-1.234567e-6));
+  test(STR("-0.000012"), en_US, STR("{:.6Lf}"), F(-1.234567e-5));
+  test(STR("-0.000123"), en_US, STR("{:.6Lf}"), F(-1.234567e-4));
+  test(STR("-0.001235"), en_US, STR("{:.6Lf}"), F(-1.234567e-3));
+  test(STR("-0.012346"), en_US, STR("{:.6Lf}"), F(-1.234567e-2));
+  test(STR("-0.123457"), en_US, STR("{:.6Lf}"), F(-1.234567e-1));
+  test(STR("-1.234567"), en_US, STR("{:.6Lf}"), F(-1.234567e0));
+  test(STR("-12.345670"), en_US, STR("{:.6Lf}"), F(-1.234567e1));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("-123.456700"), en_US, STR("{:.6Lf}"), F(-1.234567e2));
+    test(STR("-1,234.567000"), en_US, STR("{:.6Lf}"), F(-1.234567e3));
+    test(STR("-12,345.670000"), en_US, STR("{:.6Lf}"), F(-1.234567e4));
+    test(STR("-123,456.700000"), en_US, STR("{:.6Lf}"), F(-1.234567e5));
+    test(STR("-1,234,567.000000"), en_US, STR("{:.6Lf}"), F(-1.234567e6));
+    test(STR("-12,345,670.000000"), en_US, STR("{:.6Lf}"), F(-1.234567e7));
+    test(STR("-123,456,700,000,000,000,000.000000"), en_US, STR("{:.6Lf}"), F(-1.234567e20));
+  }
+
+  std::locale::global(en_US);
+  test(STR("0#000001"), loc, STR("{:.6Lf}"), F(1.234567e-6));
+  test(STR("0#000012"), loc, STR("{:.6Lf}"), F(1.234567e-5));
+  test(STR("0#000123"), loc, STR("{:.6Lf}"), F(1.234567e-4));
+  test(STR("0#001235"), loc, STR("{:.6Lf}"), F(1.234567e-3));
+  test(STR("0#012346"), loc, STR("{:.6Lf}"), F(1.234567e-2));
+  test(STR("0#123457"), loc, STR("{:.6Lf}"), F(1.234567e-1));
+  test(STR("1#234567"), loc, STR("{:.6Lf}"), F(1.234567e0));
+  test(STR("1_2#345670"), loc, STR("{:.6Lf}"), F(1.234567e1));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("12_3#456700"), loc, STR("{:.6Lf}"), F(1.234567e2));
+    test(STR("1_23_4#567000"), loc, STR("{:.6Lf}"), F(1.234567e3));
+    test(STR("12_34_5#670000"), loc, STR("{:.6Lf}"), F(1.234567e4));
+    test(STR("123_45_6#700000"), loc, STR("{:.6Lf}"), F(1.234567e5));
+    test(STR("1_234_56_7#000000"), loc, STR("{:.6Lf}"), F(1.234567e6));
+    test(STR("12_345_67_0#000000"), loc, STR("{:.6Lf}"), F(1.234567e7));
+    test(STR("1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000"), loc, STR("{:.6Lf}"), F(1.234567e20));
+  }
+  test(STR("-0#000001"), loc, STR("{:.6Lf}"), F(-1.234567e-6));
+  test(STR("-0#000012"), loc, STR("{:.6Lf}"), F(-1.234567e-5));
+  test(STR("-0#000123"), loc, STR("{:.6Lf}"), F(-1.234567e-4));
+  test(STR("-0#001235"), loc, STR("{:.6Lf}"), F(-1.234567e-3));
+  test(STR("-0#012346"), loc, STR("{:.6Lf}"), F(-1.234567e-2));
+  test(STR("-0#123457"), loc, STR("{:.6Lf}"), F(-1.234567e-1));
+  test(STR("-1#234567"), loc, STR("{:.6Lf}"), F(-1.234567e0));
+  test(STR("-1_2#345670"), loc, STR("{:.6Lf}"), F(-1.234567e1));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("-12_3#456700"), loc, STR("{:.6Lf}"), F(-1.234567e2));
+    test(STR("-1_23_4#567000"), loc, STR("{:.6Lf}"), F(-1.234567e3));
+    test(STR("-12_34_5#670000"), loc, STR("{:.6Lf}"), F(-1.234567e4));
+    test(STR("-123_45_6#700000"), loc, STR("{:.6Lf}"), F(-1.234567e5));
+    test(STR("-1_234_56_7#000000"), loc, STR("{:.6Lf}"), F(-1.234567e6));
+    test(STR("-12_345_67_0#000000"), loc, STR("{:.6Lf}"), F(-1.234567e7));
+    test(STR("-1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000"), loc, STR("{:.6Lf}"), F(-1.234567e20));
+  }
+
+  // *** Fill, align, zero padding ***
+  if constexpr (sizeof(F) > sizeof(float)) {
+    std::locale::global(en_US);
+    test(STR("1,234.567000$$$"), STR("{:$<15.6Lf}"), F(1.234567e3));
+    test(STR("$$$1,234.567000"), STR("{:$>15.6Lf}"), F(1.234567e3));
+    test(STR("$1,234.567000$$"), STR("{:$^15.6Lf}"), F(1.234567e3));
+    test(STR("0001,234.567000"), STR("{:015.6Lf}"), F(1.234567e3));
+    test(STR("-1,234.567000$$$"), STR("{:$<16.6Lf}"), F(-1.234567e3));
+    test(STR("$$$-1,234.567000"), STR("{:$>16.6Lf}"), F(-1.234567e3));
+    test(STR("$-1,234.567000$$"), STR("{:$^16.6Lf}"), F(-1.234567e3));
+    test(STR("-0001,234.567000"), STR("{:016.6Lf}"), F(-1.234567e3));
+
+    std::locale::global(loc);
+    test(STR("1_23_4#567000$$$"), STR("{:$<16.6Lf}"), F(1.234567e3));
+    test(STR("$$$1_23_4#567000"), STR("{:$>16.6Lf}"), F(1.234567e3));
+    test(STR("$1_23_4#567000$$"), STR("{:$^16.6Lf}"), F(1.234567e3));
+    test(STR("0001_23_4#567000"), STR("{:016.6Lf}"), F(1.234567e3));
+    test(STR("-1_23_4#567000$$$"), STR("{:$<17.6Lf}"), F(-1.234567e3));
+    test(STR("$$$-1_23_4#567000"), STR("{:$>17.6Lf}"), F(-1.234567e3));
+    test(STR("$-1_23_4#567000$$"), STR("{:$^17.6Lf}"), F(-1.234567e3));
+    test(STR("-0001_23_4#567000"), STR("{:017.6Lf}"), F(-1.234567e3));
+
+    test(STR("1,234.567000$$$"), en_US, STR("{:$<15.6Lf}"), F(1.234567e3));
+    test(STR("$$$1,234.567000"), en_US, STR("{:$>15.6Lf}"), F(1.234567e3));
+    test(STR("$1,234.567000$$"), en_US, STR("{:$^15.6Lf}"), F(1.234567e3));
+    test(STR("0001,234.567000"), en_US, STR("{:015.6Lf}"), F(1.234567e3));
+    test(STR("-1,234.567000$$$"), en_US, STR("{:$<16.6Lf}"), F(-1.234567e3));
+    test(STR("$$$-1,234.567000"), en_US, STR("{:$>16.6Lf}"), F(-1.234567e3));
+    test(STR("$-1,234.567000$$"), en_US, STR("{:$^16.6Lf}"), F(-1.234567e3));
+    test(STR("-0001,234.567000"), en_US, STR("{:016.6Lf}"), F(-1.234567e3));
+
+    std::locale::global(en_US);
+    test(STR("1_23_4#567000$$$"), loc, STR("{:$<16.6Lf}"), F(1.234567e3));
+    test(STR("$$$1_23_4#567000"), loc, STR("{:$>16.6Lf}"), F(1.234567e3));
+    test(STR("$1_23_4#567000$$"), loc, STR("{:$^16.6Lf}"), F(1.234567e3));
+    test(STR("0001_23_4#567000"), loc, STR("{:016.6Lf}"), F(1.234567e3));
+    test(STR("-1_23_4#567000$$$"), loc, STR("{:$<17.6Lf}"), F(-1.234567e3));
+    test(STR("$$$-1_23_4#567000"), loc, STR("{:$>17.6Lf}"), F(-1.234567e3));
+    test(STR("$-1_23_4#567000$$"), loc, STR("{:$^17.6Lf}"), F(-1.234567e3));
+    test(STR("-0001_23_4#567000"), loc, STR("{:017.6Lf}"), F(-1.234567e3));
+  }
+}
+
+template <class F, class CharT>
+void test_floating_point_fixed_upper_case() {
+  std::locale loc = std::locale(std::locale(), new numpunct<CharT>());
+  std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+  // *** Basic ***
+  std::locale::global(en_US);
+  test(STR("0.000001"), STR("{:.6Lf}"), F(1.234567e-6));
+  test(STR("0.000012"), STR("{:.6Lf}"), F(1.234567e-5));
+  test(STR("0.000123"), STR("{:.6Lf}"), F(1.234567e-4));
+  test(STR("0.001235"), STR("{:.6Lf}"), F(1.234567e-3));
+  test(STR("0.012346"), STR("{:.6Lf}"), F(1.234567e-2));
+  test(STR("0.123457"), STR("{:.6Lf}"), F(1.234567e-1));
+  test(STR("1.234567"), STR("{:.6Lf}"), F(1.234567e0));
+  test(STR("12.345670"), STR("{:.6Lf}"), F(1.234567e1));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("123.456700"), STR("{:.6Lf}"), F(1.234567e2));
+    test(STR("1,234.567000"), STR("{:.6Lf}"), F(1.234567e3));
+    test(STR("12,345.670000"), STR("{:.6Lf}"), F(1.234567e4));
+    test(STR("123,456.700000"), STR("{:.6Lf}"), F(1.234567e5));
+    test(STR("1,234,567.000000"), STR("{:.6Lf}"), F(1.234567e6));
+    test(STR("12,345,670.000000"), STR("{:.6Lf}"), F(1.234567e7));
+    test(STR("123,456,700,000,000,000,000.000000"), STR("{:.6Lf}"), F(1.234567e20));
+  }
+  test(STR("-0.000001"), STR("{:.6Lf}"), F(-1.234567e-6));
+  test(STR("-0.000012"), STR("{:.6Lf}"), F(-1.234567e-5));
+  test(STR("-0.000123"), STR("{:.6Lf}"), F(-1.234567e-4));
+  test(STR("-0.001235"), STR("{:.6Lf}"), F(-1.234567e-3));
+  test(STR("-0.012346"), STR("{:.6Lf}"), F(-1.234567e-2));
+  test(STR("-0.123457"), STR("{:.6Lf}"), F(-1.234567e-1));
+  test(STR("-1.234567"), STR("{:.6Lf}"), F(-1.234567e0));
+  test(STR("-12.345670"), STR("{:.6Lf}"), F(-1.234567e1));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("-123.456700"), STR("{:.6Lf}"), F(-1.234567e2));
+    test(STR("-1,234.567000"), STR("{:.6Lf}"), F(-1.234567e3));
+    test(STR("-12,345.670000"), STR("{:.6Lf}"), F(-1.234567e4));
+    test(STR("-123,456.700000"), STR("{:.6Lf}"), F(-1.234567e5));
+    test(STR("-1,234,567.000000"), STR("{:.6Lf}"), F(-1.234567e6));
+    test(STR("-12,345,670.000000"), STR("{:.6Lf}"), F(-1.234567e7));
+    test(STR("-123,456,700,000,000,000,000.000000"), STR("{:.6Lf}"), F(-1.234567e20));
+  }
+
+  std::locale::global(loc);
+  test(STR("0#000001"), STR("{:.6Lf}"), F(1.234567e-6));
+  test(STR("0#000012"), STR("{:.6Lf}"), F(1.234567e-5));
+  test(STR("0#000123"), STR("{:.6Lf}"), F(1.234567e-4));
+  test(STR("0#001235"), STR("{:.6Lf}"), F(1.234567e-3));
+  test(STR("0#012346"), STR("{:.6Lf}"), F(1.234567e-2));
+  test(STR("0#123457"), STR("{:.6Lf}"), F(1.234567e-1));
+  test(STR("1#234567"), STR("{:.6Lf}"), F(1.234567e0));
+  test(STR("1_2#345670"), STR("{:.6Lf}"), F(1.234567e1));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("12_3#456700"), STR("{:.6Lf}"), F(1.234567e2));
+    test(STR("1_23_4#567000"), STR("{:.6Lf}"), F(1.234567e3));
+    test(STR("12_34_5#670000"), STR("{:.6Lf}"), F(1.234567e4));
+    test(STR("123_45_6#700000"), STR("{:.6Lf}"), F(1.234567e5));
+    test(STR("1_234_56_7#000000"), STR("{:.6Lf}"), F(1.234567e6));
+    test(STR("12_345_67_0#000000"), STR("{:.6Lf}"), F(1.234567e7));
+    test(STR("1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000"), STR("{:.6Lf}"), F(1.234567e20));
+  }
+  test(STR("-0#000001"), STR("{:.6Lf}"), F(-1.234567e-6));
+  test(STR("-0#000012"), STR("{:.6Lf}"), F(-1.234567e-5));
+  test(STR("-0#000123"), STR("{:.6Lf}"), F(-1.234567e-4));
+  test(STR("-0#001235"), STR("{:.6Lf}"), F(-1.234567e-3));
+  test(STR("-0#012346"), STR("{:.6Lf}"), F(-1.234567e-2));
+  test(STR("-0#123457"), STR("{:.6Lf}"), F(-1.234567e-1));
+  test(STR("-1#234567"), STR("{:.6Lf}"), F(-1.234567e0));
+  test(STR("-1_2#345670"), STR("{:.6Lf}"), F(-1.234567e1));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("-12_3#456700"), STR("{:.6Lf}"), F(-1.234567e2));
+    test(STR("-1_23_4#567000"), STR("{:.6Lf}"), F(-1.234567e3));
+    test(STR("-12_34_5#670000"), STR("{:.6Lf}"), F(-1.234567e4));
+    test(STR("-123_45_6#700000"), STR("{:.6Lf}"), F(-1.234567e5));
+    test(STR("-1_234_56_7#000000"), STR("{:.6Lf}"), F(-1.234567e6));
+    test(STR("-12_345_67_0#000000"), STR("{:.6Lf}"), F(-1.234567e7));
+    test(STR("-1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000"), STR("{:.6Lf}"), F(-1.234567e20));
+  }
+
+  test(STR("0.000001"), en_US, STR("{:.6Lf}"), F(1.234567e-6));
+  test(STR("0.000012"), en_US, STR("{:.6Lf}"), F(1.234567e-5));
+  test(STR("0.000123"), en_US, STR("{:.6Lf}"), F(1.234567e-4));
+  test(STR("0.001235"), en_US, STR("{:.6Lf}"), F(1.234567e-3));
+  test(STR("0.012346"), en_US, STR("{:.6Lf}"), F(1.234567e-2));
+  test(STR("0.123457"), en_US, STR("{:.6Lf}"), F(1.234567e-1));
+  test(STR("1.234567"), en_US, STR("{:.6Lf}"), F(1.234567e0));
+  test(STR("12.345670"), en_US, STR("{:.6Lf}"), F(1.234567e1));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("123.456700"), en_US, STR("{:.6Lf}"), F(1.234567e2));
+    test(STR("1,234.567000"), en_US, STR("{:.6Lf}"), F(1.234567e3));
+    test(STR("12,345.670000"), en_US, STR("{:.6Lf}"), F(1.234567e4));
+    test(STR("123,456.700000"), en_US, STR("{:.6Lf}"), F(1.234567e5));
+    test(STR("1,234,567.000000"), en_US, STR("{:.6Lf}"), F(1.234567e6));
+    test(STR("12,345,670.000000"), en_US, STR("{:.6Lf}"), F(1.234567e7));
+    test(STR("123,456,700,000,000,000,000.000000"), en_US, STR("{:.6Lf}"), F(1.234567e20));
+  }
+  test(STR("-0.000001"), en_US, STR("{:.6Lf}"), F(-1.234567e-6));
+  test(STR("-0.000012"), en_US, STR("{:.6Lf}"), F(-1.234567e-5));
+  test(STR("-0.000123"), en_US, STR("{:.6Lf}"), F(-1.234567e-4));
+  test(STR("-0.001235"), en_US, STR("{:.6Lf}"), F(-1.234567e-3));
+  test(STR("-0.012346"), en_US, STR("{:.6Lf}"), F(-1.234567e-2));
+  test(STR("-0.123457"), en_US, STR("{:.6Lf}"), F(-1.234567e-1));
+  test(STR("-1.234567"), en_US, STR("{:.6Lf}"), F(-1.234567e0));
+  test(STR("-12.345670"), en_US, STR("{:.6Lf}"), F(-1.234567e1));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("-123.456700"), en_US, STR("{:.6Lf}"), F(-1.234567e2));
+    test(STR("-1,234.567000"), en_US, STR("{:.6Lf}"), F(-1.234567e3));
+    test(STR("-12,345.670000"), en_US, STR("{:.6Lf}"), F(-1.234567e4));
+    test(STR("-123,456.700000"), en_US, STR("{:.6Lf}"), F(-1.234567e5));
+    test(STR("-1,234,567.000000"), en_US, STR("{:.6Lf}"), F(-1.234567e6));
+    test(STR("-12,345,670.000000"), en_US, STR("{:.6Lf}"), F(-1.234567e7));
+    test(STR("-123,456,700,000,000,000,000.000000"), en_US, STR("{:.6Lf}"), F(-1.234567e20));
+  }
+
+  std::locale::global(en_US);
+  test(STR("0#000001"), loc, STR("{:.6Lf}"), F(1.234567e-6));
+  test(STR("0#000012"), loc, STR("{:.6Lf}"), F(1.234567e-5));
+  test(STR("0#000123"), loc, STR("{:.6Lf}"), F(1.234567e-4));
+  test(STR("0#001235"), loc, STR("{:.6Lf}"), F(1.234567e-3));
+  test(STR("0#012346"), loc, STR("{:.6Lf}"), F(1.234567e-2));
+  test(STR("0#123457"), loc, STR("{:.6Lf}"), F(1.234567e-1));
+  test(STR("1#234567"), loc, STR("{:.6Lf}"), F(1.234567e0));
+  test(STR("1_2#345670"), loc, STR("{:.6Lf}"), F(1.234567e1));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("12_3#456700"), loc, STR("{:.6Lf}"), F(1.234567e2));
+    test(STR("1_23_4#567000"), loc, STR("{:.6Lf}"), F(1.234567e3));
+    test(STR("12_34_5#670000"), loc, STR("{:.6Lf}"), F(1.234567e4));
+    test(STR("123_45_6#700000"), loc, STR("{:.6Lf}"), F(1.234567e5));
+    test(STR("1_234_56_7#000000"), loc, STR("{:.6Lf}"), F(1.234567e6));
+    test(STR("12_345_67_0#000000"), loc, STR("{:.6Lf}"), F(1.234567e7));
+    test(STR("1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000"), loc, STR("{:.6Lf}"), F(1.234567e20));
+  }
+  test(STR("-0#000001"), loc, STR("{:.6Lf}"), F(-1.234567e-6));
+  test(STR("-0#000012"), loc, STR("{:.6Lf}"), F(-1.234567e-5));
+  test(STR("-0#000123"), loc, STR("{:.6Lf}"), F(-1.234567e-4));
+  test(STR("-0#001235"), loc, STR("{:.6Lf}"), F(-1.234567e-3));
+  test(STR("-0#012346"), loc, STR("{:.6Lf}"), F(-1.234567e-2));
+  test(STR("-0#123457"), loc, STR("{:.6Lf}"), F(-1.234567e-1));
+  test(STR("-1#234567"), loc, STR("{:.6Lf}"), F(-1.234567e0));
+  test(STR("-1_2#345670"), loc, STR("{:.6Lf}"), F(-1.234567e1));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("-12_3#456700"), loc, STR("{:.6Lf}"), F(-1.234567e2));
+    test(STR("-1_23_4#567000"), loc, STR("{:.6Lf}"), F(-1.234567e3));
+    test(STR("-12_34_5#670000"), loc, STR("{:.6Lf}"), F(-1.234567e4));
+    test(STR("-123_45_6#700000"), loc, STR("{:.6Lf}"), F(-1.234567e5));
+    test(STR("-1_234_56_7#000000"), loc, STR("{:.6Lf}"), F(-1.234567e6));
+    test(STR("-12_345_67_0#000000"), loc, STR("{:.6Lf}"), F(-1.234567e7));
+    test(STR("-1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000"), loc, STR("{:.6Lf}"), F(-1.234567e20));
+  }
+
+  // *** Fill, align, zero padding ***
+  if constexpr (sizeof(F) > sizeof(float)) {
+    std::locale::global(en_US);
+    test(STR("1,234.567000$$$"), STR("{:$<15.6Lf}"), F(1.234567e3));
+    test(STR("$$$1,234.567000"), STR("{:$>15.6Lf}"), F(1.234567e3));
+    test(STR("$1,234.567000$$"), STR("{:$^15.6Lf}"), F(1.234567e3));
+    test(STR("0001,234.567000"), STR("{:015.6Lf}"), F(1.234567e3));
+    test(STR("-1,234.567000$$$"), STR("{:$<16.6Lf}"), F(-1.234567e3));
+    test(STR("$$$-1,234.567000"), STR("{:$>16.6Lf}"), F(-1.234567e3));
+    test(STR("$-1,234.567000$$"), STR("{:$^16.6Lf}"), F(-1.234567e3));
+    test(STR("-0001,234.567000"), STR("{:016.6Lf}"), F(-1.234567e3));
+
+    std::locale::global(loc);
+    test(STR("1_23_4#567000$$$"), STR("{:$<16.6Lf}"), F(1.234567e3));
+    test(STR("$$$1_23_4#567000"), STR("{:$>16.6Lf}"), F(1.234567e3));
+    test(STR("$1_23_4#567000$$"), STR("{:$^16.6Lf}"), F(1.234567e3));
+    test(STR("0001_23_4#567000"), STR("{:016.6Lf}"), F(1.234567e3));
+    test(STR("-1_23_4#567000$$$"), STR("{:$<17.6Lf}"), F(-1.234567e3));
+    test(STR("$$$-1_23_4#567000"), STR("{:$>17.6Lf}"), F(-1.234567e3));
+    test(STR("$-1_23_4#567000$$"), STR("{:$^17.6Lf}"), F(-1.234567e3));
+    test(STR("-0001_23_4#567000"), STR("{:017.6Lf}"), F(-1.234567e3));
+
+    test(STR("1,234.567000$$$"), en_US, STR("{:$<15.6Lf}"), F(1.234567e3));
+    test(STR("$$$1,234.567000"), en_US, STR("{:$>15.6Lf}"), F(1.234567e3));
+    test(STR("$1,234.567000$$"), en_US, STR("{:$^15.6Lf}"), F(1.234567e3));
+    test(STR("0001,234.567000"), en_US, STR("{:015.6Lf}"), F(1.234567e3));
+    test(STR("-1,234.567000$$$"), en_US, STR("{:$<16.6Lf}"), F(-1.234567e3));
+    test(STR("$$$-1,234.567000"), en_US, STR("{:$>16.6Lf}"), F(-1.234567e3));
+    test(STR("$-1,234.567000$$"), en_US, STR("{:$^16.6Lf}"), F(-1.234567e3));
+    test(STR("-0001,234.567000"), en_US, STR("{:016.6Lf}"), F(-1.234567e3));
+
+    std::locale::global(en_US);
+    test(STR("1_23_4#567000$$$"), loc, STR("{:$<16.6Lf}"), F(1.234567e3));
+    test(STR("$$$1_23_4#567000"), loc, STR("{:$>16.6Lf}"), F(1.234567e3));
+    test(STR("$1_23_4#567000$$"), loc, STR("{:$^16.6Lf}"), F(1.234567e3));
+    test(STR("0001_23_4#567000"), loc, STR("{:016.6Lf}"), F(1.234567e3));
+    test(STR("-1_23_4#567000$$$"), loc, STR("{:$<17.6Lf}"), F(-1.234567e3));
+    test(STR("$$$-1_23_4#567000"), loc, STR("{:$>17.6Lf}"), F(-1.234567e3));
+    test(STR("$-1_23_4#567000$$"), loc, STR("{:$^17.6Lf}"), F(-1.234567e3));
+    test(STR("-0001_23_4#567000"), loc, STR("{:017.6Lf}"), F(-1.234567e3));
+  }
+}
+
+template <class F, class CharT>
+void test_floating_point_general_lower_case() {
+  std::locale loc = std::locale(std::locale(), new numpunct<CharT>());
+  std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+  // *** Basic ***
+  std::locale::global(en_US);
+  test(STR("1.23457e-06"), STR("{:.6Lg}"), F(1.234567e-6));
+  test(STR("1.23457e-05"), STR("{:.6Lg}"), F(1.234567e-5));
+  test(STR("0.000123457"), STR("{:.6Lg}"), F(1.234567e-4));
+  test(STR("0.00123457"), STR("{:.6Lg}"), F(1.234567e-3));
+  test(STR("0.0123457"), STR("{:.6Lg}"), F(1.234567e-2));
+  test(STR("0.123457"), STR("{:.6Lg}"), F(1.234567e-1));
+  test(STR("1.23457"), STR("{:.6Lg}"), F(1.234567e0));
+  test(STR("12.3457"), STR("{:.6Lg}"), F(1.234567e1));
+  test(STR("123.457"), STR("{:.6Lg}"), F(1.234567e2));
+  test(STR("1,234.57"), STR("{:.6Lg}"), F(1.234567e3));
+  test(STR("12,345.7"), STR("{:.6Lg}"), F(1.234567e4));
+  test(STR("123,457"), STR("{:.6Lg}"), F(1.234567e5));
+  test(STR("1.23457e+06"), STR("{:.6Lg}"), F(1.234567e6));
+  test(STR("1.23457e+07"), STR("{:.6Lg}"), F(1.234567e7));
+  test(STR("-1.23457e-06"), STR("{:.6Lg}"), F(-1.234567e-6));
+  test(STR("-1.23457e-05"), STR("{:.6Lg}"), F(-1.234567e-5));
+  test(STR("-0.000123457"), STR("{:.6Lg}"), F(-1.234567e-4));
+  test(STR("-0.00123457"), STR("{:.6Lg}"), F(-1.234567e-3));
+  test(STR("-0.0123457"), STR("{:.6Lg}"), F(-1.234567e-2));
+  test(STR("-0.123457"), STR("{:.6Lg}"), F(-1.234567e-1));
+  test(STR("-1.23457"), STR("{:.6Lg}"), F(-1.234567e0));
+  test(STR("-12.3457"), STR("{:.6Lg}"), F(-1.234567e1));
+  test(STR("-123.457"), STR("{:.6Lg}"), F(-1.234567e2));
+  test(STR("-1,234.57"), STR("{:.6Lg}"), F(-1.234567e3));
+  test(STR("-12,345.7"), STR("{:.6Lg}"), F(-1.234567e4));
+  test(STR("-123,457"), STR("{:.6Lg}"), F(-1.234567e5));
+  test(STR("-1.23457e+06"), STR("{:.6Lg}"), F(-1.234567e6));
+  test(STR("-1.23457e+07"), STR("{:.6Lg}"), F(-1.234567e7));
+
+  std::locale::global(loc);
+  test(STR("1#23457e-06"), STR("{:.6Lg}"), F(1.234567e-6));
+  test(STR("1#23457e-05"), STR("{:.6Lg}"), F(1.234567e-5));
+  test(STR("0#000123457"), STR("{:.6Lg}"), F(1.234567e-4));
+  test(STR("0#00123457"), STR("{:.6Lg}"), F(1.234567e-3));
+  test(STR("0#0123457"), STR("{:.6Lg}"), F(1.234567e-2));
+  test(STR("0#123457"), STR("{:.6Lg}"), F(1.234567e-1));
+  test(STR("1#23457"), STR("{:.6Lg}"), F(1.234567e0));
+  test(STR("1_2#3457"), STR("{:.6Lg}"), F(1.234567e1));
+  test(STR("12_3#457"), STR("{:.6Lg}"), F(1.234567e2));
+  test(STR("1_23_4#57"), STR("{:.6Lg}"), F(1.234567e3));
+  test(STR("12_34_5#7"), STR("{:.6Lg}"), F(1.234567e4));
+  test(STR("123_45_7"), STR("{:.6Lg}"), F(1.234567e5));
+  test(STR("1#23457e+06"), STR("{:.6Lg}"), F(1.234567e6));
+  test(STR("1#23457e+07"), STR("{:.6Lg}"), F(1.234567e7));
+  test(STR("-1#23457e-06"), STR("{:.6Lg}"), F(-1.234567e-6));
+  test(STR("-1#23457e-05"), STR("{:.6Lg}"), F(-1.234567e-5));
+  test(STR("-0#000123457"), STR("{:.6Lg}"), F(-1.234567e-4));
+  test(STR("-0#00123457"), STR("{:.6Lg}"), F(-1.234567e-3));
+  test(STR("-0#0123457"), STR("{:.6Lg}"), F(-1.234567e-2));
+  test(STR("-0#123457"), STR("{:.6Lg}"), F(-1.234567e-1));
+  test(STR("-1#23457"), STR("{:.6Lg}"), F(-1.234567e0));
+  test(STR("-1_2#3457"), STR("{:.6Lg}"), F(-1.234567e1));
+  test(STR("-12_3#457"), STR("{:.6Lg}"), F(-1.234567e2));
+  test(STR("-1_23_4#57"), STR("{:.6Lg}"), F(-1.234567e3));
+  test(STR("-12_34_5#7"), STR("{:.6Lg}"), F(-1.234567e4));
+  test(STR("-123_45_7"), STR("{:.6Lg}"), F(-1.234567e5));
+  test(STR("-1#23457e+06"), STR("{:.6Lg}"), F(-1.234567e6));
+  test(STR("-1#23457e+07"), STR("{:.6Lg}"), F(-1.234567e7));
+
+  test(STR("1.23457e-06"), en_US, STR("{:.6Lg}"), F(1.234567e-6));
+  test(STR("1.23457e-05"), en_US, STR("{:.6Lg}"), F(1.234567e-5));
+  test(STR("0.000123457"), en_US, STR("{:.6Lg}"), F(1.234567e-4));
+  test(STR("0.00123457"), en_US, STR("{:.6Lg}"), F(1.234567e-3));
+  test(STR("0.0123457"), en_US, STR("{:.6Lg}"), F(1.234567e-2));
+  test(STR("0.123457"), en_US, STR("{:.6Lg}"), F(1.234567e-1));
+  test(STR("1.23457"), en_US, STR("{:.6Lg}"), F(1.234567e0));
+  test(STR("12.3457"), en_US, STR("{:.6Lg}"), F(1.234567e1));
+  test(STR("123.457"), en_US, STR("{:.6Lg}"), F(1.234567e2));
+  test(STR("1,234.57"), en_US, STR("{:.6Lg}"), F(1.234567e3));
+  test(STR("12,345.7"), en_US, STR("{:.6Lg}"), F(1.234567e4));
+  test(STR("123,457"), en_US, STR("{:.6Lg}"), F(1.234567e5));
+  test(STR("1.23457e+06"), en_US, STR("{:.6Lg}"), F(1.234567e6));
+  test(STR("1.23457e+07"), en_US, STR("{:.6Lg}"), F(1.234567e7));
+  test(STR("-1.23457e-06"), en_US, STR("{:.6Lg}"), F(-1.234567e-6));
+  test(STR("-1.23457e-05"), en_US, STR("{:.6Lg}"), F(-1.234567e-5));
+  test(STR("-0.000123457"), en_US, STR("{:.6Lg}"), F(-1.234567e-4));
+  test(STR("-0.00123457"), en_US, STR("{:.6Lg}"), F(-1.234567e-3));
+  test(STR("-0.0123457"), en_US, STR("{:.6Lg}"), F(-1.234567e-2));
+  test(STR("-0.123457"), en_US, STR("{:.6Lg}"), F(-1.234567e-1));
+  test(STR("-1.23457"), en_US, STR("{:.6Lg}"), F(-1.234567e0));
+  test(STR("-12.3457"), en_US, STR("{:.6Lg}"), F(-1.234567e1));
+  test(STR("-123.457"), en_US, STR("{:.6Lg}"), F(-1.234567e2));
+  test(STR("-1,234.57"), en_US, STR("{:.6Lg}"), F(-1.234567e3));
+  test(STR("-12,345.7"), en_US, STR("{:.6Lg}"), F(-1.234567e4));
+  test(STR("-123,457"), en_US, STR("{:.6Lg}"), F(-1.234567e5));
+  test(STR("-1.23457e+06"), en_US, STR("{:.6Lg}"), F(-1.234567e6));
+  test(STR("-1.23457e+07"), en_US, STR("{:.6Lg}"), F(-1.234567e7));
+
+  std::locale::global(en_US);
+  test(STR("1#23457e-06"), loc, STR("{:.6Lg}"), F(1.234567e-6));
+  test(STR("1#23457e-05"), loc, STR("{:.6Lg}"), F(1.234567e-5));
+  test(STR("0#000123457"), loc, STR("{:.6Lg}"), F(1.234567e-4));
+  test(STR("0#00123457"), loc, STR("{:.6Lg}"), F(1.234567e-3));
+  test(STR("0#0123457"), loc, STR("{:.6Lg}"), F(1.234567e-2));
+  test(STR("0#123457"), loc, STR("{:.6Lg}"), F(1.234567e-1));
+  test(STR("1#23457"), loc, STR("{:.6Lg}"), F(1.234567e0));
+  test(STR("1_2#3457"), loc, STR("{:.6Lg}"), F(1.234567e1));
+  test(STR("12_3#457"), loc, STR("{:.6Lg}"), F(1.234567e2));
+  test(STR("1_23_4#57"), loc, STR("{:.6Lg}"), F(1.234567e3));
+  test(STR("12_34_5#7"), loc, STR("{:.6Lg}"), F(1.234567e4));
+  test(STR("123_45_7"), loc, STR("{:.6Lg}"), F(1.234567e5));
+  test(STR("1#23457e+06"), loc, STR("{:.6Lg}"), F(1.234567e6));
+  test(STR("1#23457e+07"), loc, STR("{:.6Lg}"), F(1.234567e7));
+  test(STR("-1#23457e-06"), loc, STR("{:.6Lg}"), F(-1.234567e-6));
+  test(STR("-1#23457e-05"), loc, STR("{:.6Lg}"), F(-1.234567e-5));
+  test(STR("-0#000123457"), loc, STR("{:.6Lg}"), F(-1.234567e-4));
+  test(STR("-0#00123457"), loc, STR("{:.6Lg}"), F(-1.234567e-3));
+  test(STR("-0#0123457"), loc, STR("{:.6Lg}"), F(-1.234567e-2));
+  test(STR("-0#123457"), loc, STR("{:.6Lg}"), F(-1.234567e-1));
+  test(STR("-1#23457"), loc, STR("{:.6Lg}"), F(-1.234567e0));
+  test(STR("-1_2#3457"), loc, STR("{:.6Lg}"), F(-1.234567e1));
+  test(STR("-12_3#457"), loc, STR("{:.6Lg}"), F(-1.234567e2));
+  test(STR("-1_23_4#57"), loc, STR("{:.6Lg}"), F(-1.234567e3));
+  test(STR("-12_34_5#7"), loc, STR("{:.6Lg}"), F(-1.234567e4));
+  test(STR("-123_45_7"), loc, STR("{:.6Lg}"), F(-1.234567e5));
+  test(STR("-1#23457e+06"), loc, STR("{:.6Lg}"), F(-1.234567e6));
+  test(STR("-1#23457e+07"), loc, STR("{:.6Lg}"), F(-1.234567e7));
+
+  // *** Fill, align, zero padding ***
+  std::locale::global(en_US);
+  test(STR("1,234.57$$$"), STR("{:$<11.6Lg}"), F(1.234567e3));
+  test(STR("$$$1,234.57"), STR("{:$>11.6Lg}"), F(1.234567e3));
+  test(STR("$1,234.57$$"), STR("{:$^11.6Lg}"), F(1.234567e3));
+  test(STR("0001,234.57"), STR("{:011.6Lg}"), F(1.234567e3));
+  test(STR("-1,234.57$$$"), STR("{:$<12.6Lg}"), F(-1.234567e3));
+  test(STR("$$$-1,234.57"), STR("{:$>12.6Lg}"), F(-1.234567e3));
+  test(STR("$-1,234.57$$"), STR("{:$^12.6Lg}"), F(-1.234567e3));
+  test(STR("-0001,234.57"), STR("{:012.6Lg}"), F(-1.234567e3));
+
+  std::locale::global(loc);
+  test(STR("1_23_4#57$$$"), STR("{:$<12.6Lg}"), F(1.234567e3));
+  test(STR("$$$1_23_4#57"), STR("{:$>12.6Lg}"), F(1.234567e3));
+  test(STR("$1_23_4#57$$"), STR("{:$^12.6Lg}"), F(1.234567e3));
+  test(STR("0001_23_4#57"), STR("{:012.6Lg}"), F(1.234567e3));
+  test(STR("-1_23_4#57$$$"), STR("{:$<13.6Lg}"), F(-1.234567e3));
+  test(STR("$$$-1_23_4#57"), STR("{:$>13.6Lg}"), F(-1.234567e3));
+  test(STR("$-1_23_4#57$$"), STR("{:$^13.6Lg}"), F(-1.234567e3));
+  test(STR("-0001_23_4#57"), STR("{:013.6Lg}"), F(-1.234567e3));
+
+  test(STR("1,234.57$$$"), en_US, STR("{:$<11.6Lg}"), F(1.234567e3));
+  test(STR("$$$1,234.57"), en_US, STR("{:$>11.6Lg}"), F(1.234567e3));
+  test(STR("$1,234.57$$"), en_US, STR("{:$^11.6Lg}"), F(1.234567e3));
+  test(STR("0001,234.57"), en_US, STR("{:011.6Lg}"), F(1.234567e3));
+  test(STR("-1,234.57$$$"), en_US, STR("{:$<12.6Lg}"), F(-1.234567e3));
+  test(STR("$$$-1,234.57"), en_US, STR("{:$>12.6Lg}"), F(-1.234567e3));
+  test(STR("$-1,234.57$$"), en_US, STR("{:$^12.6Lg}"), F(-1.234567e3));
+  test(STR("-0001,234.57"), en_US, STR("{:012.6Lg}"), F(-1.234567e3));
+
+  std::locale::global(en_US);
+  test(STR("1_23_4#57$$$"), loc, STR("{:$<12.6Lg}"), F(1.234567e3));
+  test(STR("$$$1_23_4#57"), loc, STR("{:$>12.6Lg}"), F(1.234567e3));
+  test(STR("$1_23_4#57$$"), loc, STR("{:$^12.6Lg}"), F(1.234567e3));
+  test(STR("0001_23_4#57"), loc, STR("{:012.6Lg}"), F(1.234567e3));
+  test(STR("-1_23_4#57$$$"), loc, STR("{:$<13.6Lg}"), F(-1.234567e3));
+  test(STR("$$$-1_23_4#57"), loc, STR("{:$>13.6Lg}"), F(-1.234567e3));
+  test(STR("$-1_23_4#57$$"), loc, STR("{:$^13.6Lg}"), F(-1.234567e3));
+  test(STR("-0001_23_4#57"), loc, STR("{:013.6Lg}"), F(-1.234567e3));
+}
+
+template <class F, class CharT>
+void test_floating_point_general_upper_case() {
+  std::locale loc = std::locale(std::locale(), new numpunct<CharT>());
+  std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+  // *** Basic ***
+  std::locale::global(en_US);
+  test(STR("1.23457E-06"), STR("{:.6LG}"), F(1.234567e-6));
+  test(STR("1.23457E-05"), STR("{:.6LG}"), F(1.234567e-5));
+  test(STR("0.000123457"), STR("{:.6LG}"), F(1.234567e-4));
+  test(STR("0.00123457"), STR("{:.6LG}"), F(1.234567e-3));
+  test(STR("0.0123457"), STR("{:.6LG}"), F(1.234567e-2));
+  test(STR("0.123457"), STR("{:.6LG}"), F(1.234567e-1));
+  test(STR("1.23457"), STR("{:.6LG}"), F(1.234567e0));
+  test(STR("12.3457"), STR("{:.6LG}"), F(1.234567e1));
+  test(STR("123.457"), STR("{:.6LG}"), F(1.234567e2));
+  test(STR("1,234.57"), STR("{:.6LG}"), F(1.234567e3));
+  test(STR("12,345.7"), STR("{:.6LG}"), F(1.234567e4));
+  test(STR("123,457"), STR("{:.6LG}"), F(1.234567e5));
+  test(STR("1.23457E+06"), STR("{:.6LG}"), F(1.234567e6));
+  test(STR("1.23457E+07"), STR("{:.6LG}"), F(1.234567e7));
+  test(STR("-1.23457E-06"), STR("{:.6LG}"), F(-1.234567e-6));
+  test(STR("-1.23457E-05"), STR("{:.6LG}"), F(-1.234567e-5));
+  test(STR("-0.000123457"), STR("{:.6LG}"), F(-1.234567e-4));
+  test(STR("-0.00123457"), STR("{:.6LG}"), F(-1.234567e-3));
+  test(STR("-0.0123457"), STR("{:.6LG}"), F(-1.234567e-2));
+  test(STR("-0.123457"), STR("{:.6LG}"), F(-1.234567e-1));
+  test(STR("-1.23457"), STR("{:.6LG}"), F(-1.234567e0));
+  test(STR("-12.3457"), STR("{:.6LG}"), F(-1.234567e1));
+  test(STR("-123.457"), STR("{:.6LG}"), F(-1.234567e2));
+  test(STR("-1,234.57"), STR("{:.6LG}"), F(-1.234567e3));
+  test(STR("-12,345.7"), STR("{:.6LG}"), F(-1.234567e4));
+  test(STR("-123,457"), STR("{:.6LG}"), F(-1.234567e5));
+  test(STR("-1.23457E+06"), STR("{:.6LG}"), F(-1.234567e6));
+  test(STR("-1.23457E+07"), STR("{:.6LG}"), F(-1.234567e7));
+
+  std::locale::global(loc);
+  test(STR("1#23457E-06"), STR("{:.6LG}"), F(1.234567e-6));
+  test(STR("1#23457E-05"), STR("{:.6LG}"), F(1.234567e-5));
+  test(STR("0#000123457"), STR("{:.6LG}"), F(1.234567e-4));
+  test(STR("0#00123457"), STR("{:.6LG}"), F(1.234567e-3));
+  test(STR("0#0123457"), STR("{:.6LG}"), F(1.234567e-2));
+  test(STR("0#123457"), STR("{:.6LG}"), F(1.234567e-1));
+  test(STR("1#23457"), STR("{:.6LG}"), F(1.234567e0));
+  test(STR("1_2#3457"), STR("{:.6LG}"), F(1.234567e1));
+  test(STR("12_3#457"), STR("{:.6LG}"), F(1.234567e2));
+  test(STR("1_23_4#57"), STR("{:.6LG}"), F(1.234567e3));
+  test(STR("12_34_5#7"), STR("{:.6LG}"), F(1.234567e4));
+  test(STR("123_45_7"), STR("{:.6LG}"), F(1.234567e5));
+  test(STR("1#23457E+06"), STR("{:.6LG}"), F(1.234567e6));
+  test(STR("1#23457E+07"), STR("{:.6LG}"), F(1.234567e7));
+  test(STR("-1#23457E-06"), STR("{:.6LG}"), F(-1.234567e-6));
+  test(STR("-1#23457E-05"), STR("{:.6LG}"), F(-1.234567e-5));
+  test(STR("-0#000123457"), STR("{:.6LG}"), F(-1.234567e-4));
+  test(STR("-0#00123457"), STR("{:.6LG}"), F(-1.234567e-3));
+  test(STR("-0#0123457"), STR("{:.6LG}"), F(-1.234567e-2));
+  test(STR("-0#123457"), STR("{:.6LG}"), F(-1.234567e-1));
+  test(STR("-1#23457"), STR("{:.6LG}"), F(-1.234567e0));
+  test(STR("-1_2#3457"), STR("{:.6LG}"), F(-1.234567e1));
+  test(STR("-12_3#457"), STR("{:.6LG}"), F(-1.234567e2));
+  test(STR("-1_23_4#57"), STR("{:.6LG}"), F(-1.234567e3));
+  test(STR("-12_34_5#7"), STR("{:.6LG}"), F(-1.234567e4));
+  test(STR("-123_45_7"), STR("{:.6LG}"), F(-1.234567e5));
+  test(STR("-1#23457E+06"), STR("{:.6LG}"), F(-1.234567e6));
+  test(STR("-1#23457E+07"), STR("{:.6LG}"), F(-1.234567e7));
+
+  test(STR("1.23457E-06"), en_US, STR("{:.6LG}"), F(1.234567e-6));
+  test(STR("1.23457E-05"), en_US, STR("{:.6LG}"), F(1.234567e-5));
+  test(STR("0.000123457"), en_US, STR("{:.6LG}"), F(1.234567e-4));
+  test(STR("0.00123457"), en_US, STR("{:.6LG}"), F(1.234567e-3));
+  test(STR("0.0123457"), en_US, STR("{:.6LG}"), F(1.234567e-2));
+  test(STR("0.123457"), en_US, STR("{:.6LG}"), F(1.234567e-1));
+  test(STR("1.23457"), en_US, STR("{:.6LG}"), F(1.234567e0));
+  test(STR("12.3457"), en_US, STR("{:.6LG}"), F(1.234567e1));
+  test(STR("123.457"), en_US, STR("{:.6LG}"), F(1.234567e2));
+  test(STR("1,234.57"), en_US, STR("{:.6LG}"), F(1.234567e3));
+  test(STR("12,345.7"), en_US, STR("{:.6LG}"), F(1.234567e4));
+  test(STR("123,457"), en_US, STR("{:.6LG}"), F(1.234567e5));
+  test(STR("1.23457E+06"), en_US, STR("{:.6LG}"), F(1.234567e6));
+  test(STR("1.23457E+07"), en_US, STR("{:.6LG}"), F(1.234567e7));
+  test(STR("-1.23457E-06"), en_US, STR("{:.6LG}"), F(-1.234567e-6));
+  test(STR("-1.23457E-05"), en_US, STR("{:.6LG}"), F(-1.234567e-5));
+  test(STR("-0.000123457"), en_US, STR("{:.6LG}"), F(-1.234567e-4));
+  test(STR("-0.00123457"), en_US, STR("{:.6LG}"), F(-1.234567e-3));
+  test(STR("-0.0123457"), en_US, STR("{:.6LG}"), F(-1.234567e-2));
+  test(STR("-0.123457"), en_US, STR("{:.6LG}"), F(-1.234567e-1));
+  test(STR("-1.23457"), en_US, STR("{:.6LG}"), F(-1.234567e0));
+  test(STR("-12.3457"), en_US, STR("{:.6LG}"), F(-1.234567e1));
+  test(STR("-123.457"), en_US, STR("{:.6LG}"), F(-1.234567e2));
+  test(STR("-1,234.57"), en_US, STR("{:.6LG}"), F(-1.234567e3));
+  test(STR("-12,345.7"), en_US, STR("{:.6LG}"), F(-1.234567e4));
+  test(STR("-123,457"), en_US, STR("{:.6LG}"), F(-1.234567e5));
+  test(STR("-1.23457E+06"), en_US, STR("{:.6LG}"), F(-1.234567e6));
+  test(STR("-1.23457E+07"), en_US, STR("{:.6LG}"), F(-1.234567e7));
+
+  std::locale::global(en_US);
+  test(STR("1#23457E-06"), loc, STR("{:.6LG}"), F(1.234567e-6));
+  test(STR("1#23457E-05"), loc, STR("{:.6LG}"), F(1.234567e-5));
+  test(STR("0#000123457"), loc, STR("{:.6LG}"), F(1.234567e-4));
+  test(STR("0#00123457"), loc, STR("{:.6LG}"), F(1.234567e-3));
+  test(STR("0#0123457"), loc, STR("{:.6LG}"), F(1.234567e-2));
+  test(STR("0#123457"), loc, STR("{:.6LG}"), F(1.234567e-1));
+  test(STR("1#23457"), loc, STR("{:.6LG}"), F(1.234567e0));
+  test(STR("1_2#3457"), loc, STR("{:.6LG}"), F(1.234567e1));
+  test(STR("12_3#457"), loc, STR("{:.6LG}"), F(1.234567e2));
+  test(STR("1_23_4#57"), loc, STR("{:.6LG}"), F(1.234567e3));
+  test(STR("12_34_5#7"), loc, STR("{:.6LG}"), F(1.234567e4));
+  test(STR("123_45_7"), loc, STR("{:.6LG}"), F(1.234567e5));
+  test(STR("1#23457E+06"), loc, STR("{:.6LG}"), F(1.234567e6));
+  test(STR("1#23457E+07"), loc, STR("{:.6LG}"), F(1.234567e7));
+  test(STR("-1#23457E-06"), loc, STR("{:.6LG}"), F(-1.234567e-6));
+  test(STR("-1#23457E-05"), loc, STR("{:.6LG}"), F(-1.234567e-5));
+  test(STR("-0#000123457"), loc, STR("{:.6LG}"), F(-1.234567e-4));
+  test(STR("-0#00123457"), loc, STR("{:.6LG}"), F(-1.234567e-3));
+  test(STR("-0#0123457"), loc, STR("{:.6LG}"), F(-1.234567e-2));
+  test(STR("-0#123457"), loc, STR("{:.6LG}"), F(-1.234567e-1));
+  test(STR("-1#23457"), loc, STR("{:.6LG}"), F(-1.234567e0));
+  test(STR("-1_2#3457"), loc, STR("{:.6LG}"), F(-1.234567e1));
+  test(STR("-12_3#457"), loc, STR("{:.6LG}"), F(-1.234567e2));
+  test(STR("-1_23_4#57"), loc, STR("{:.6LG}"), F(-1.234567e3));
+  test(STR("-12_34_5#7"), loc, STR("{:.6LG}"), F(-1.234567e4));
+  test(STR("-123_45_7"), loc, STR("{:.6LG}"), F(-1.234567e5));
+  test(STR("-1#23457E+06"), loc, STR("{:.6LG}"), F(-1.234567e6));
+  test(STR("-1#23457E+07"), loc, STR("{:.6LG}"), F(-1.234567e7));
+
+  // *** Fill, align, zero padding ***
+  std::locale::global(en_US);
+  test(STR("1,234.57$$$"), STR("{:$<11.6LG}"), F(1.234567e3));
+  test(STR("$$$1,234.57"), STR("{:$>11.6LG}"), F(1.234567e3));
+  test(STR("$1,234.57$$"), STR("{:$^11.6LG}"), F(1.234567e3));
+  test(STR("0001,234.57"), STR("{:011.6LG}"), F(1.234567e3));
+  test(STR("-1,234.57$$$"), STR("{:$<12.6LG}"), F(-1.234567e3));
+  test(STR("$$$-1,234.57"), STR("{:$>12.6LG}"), F(-1.234567e3));
+  test(STR("$-1,234.57$$"), STR("{:$^12.6LG}"), F(-1.234567e3));
+  test(STR("-0001,234.57"), STR("{:012.6LG}"), F(-1.234567e3));
+
+  std::locale::global(loc);
+  test(STR("1_23_4#57$$$"), STR("{:$<12.6LG}"), F(1.234567e3));
+  test(STR("$$$1_23_4#57"), STR("{:$>12.6LG}"), F(1.234567e3));
+  test(STR("$1_23_4#57$$"), STR("{:$^12.6LG}"), F(1.234567e3));
+  test(STR("0001_23_4#57"), STR("{:012.6LG}"), F(1.234567e3));
+  test(STR("-1_23_4#57$$$"), STR("{:$<13.6LG}"), F(-1.234567e3));
+  test(STR("$$$-1_23_4#57"), STR("{:$>13.6LG}"), F(-1.234567e3));
+  test(STR("$-1_23_4#57$$"), STR("{:$^13.6LG}"), F(-1.234567e3));
+  test(STR("-0001_23_4#57"), STR("{:013.6LG}"), F(-1.234567e3));
+
+  test(STR("1,234.57$$$"), en_US, STR("{:$<11.6LG}"), F(1.234567e3));
+  test(STR("$$$1,234.57"), en_US, STR("{:$>11.6LG}"), F(1.234567e3));
+  test(STR("$1,234.57$$"), en_US, STR("{:$^11.6LG}"), F(1.234567e3));
+  test(STR("0001,234.57"), en_US, STR("{:011.6LG}"), F(1.234567e3));
+  test(STR("-1,234.57$$$"), en_US, STR("{:$<12.6LG}"), F(-1.234567e3));
+  test(STR("$$$-1,234.57"), en_US, STR("{:$>12.6LG}"), F(-1.234567e3));
+  test(STR("$-1,234.57$$"), en_US, STR("{:$^12.6LG}"), F(-1.234567e3));
+  test(STR("-0001,234.57"), en_US, STR("{:012.6LG}"), F(-1.234567e3));
+
+  std::locale::global(en_US);
+  test(STR("1_23_4#57$$$"), loc, STR("{:$<12.6LG}"), F(1.234567e3));
+  test(STR("$$$1_23_4#57"), loc, STR("{:$>12.6LG}"), F(1.234567e3));
+  test(STR("$1_23_4#57$$"), loc, STR("{:$^12.6LG}"), F(1.234567e3));
+  test(STR("0001_23_4#57"), loc, STR("{:012.6LG}"), F(1.234567e3));
+  test(STR("-1_23_4#57$$$"), loc, STR("{:$<13.6LG}"), F(-1.234567e3));
+  test(STR("$$$-1_23_4#57"), loc, STR("{:$>13.6LG}"), F(-1.234567e3));
+  test(STR("$-1_23_4#57$$"), loc, STR("{:$^13.6LG}"), F(-1.234567e3));
+  test(STR("-0001_23_4#57"), loc, STR("{:013.6LG}"), F(-1.234567e3));
+}
+
+template <class F, class CharT>
+void test_floating_point_default() {
+  std::locale loc = std::locale(std::locale(), new numpunct<CharT>());
+  std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+  // *** Basic ***
+  std::locale::global(en_US);
+  test(STR("1.234567e-06"), STR("{:L}"), F(1.234567e-6));
+  test(STR("1.234567e-05"), STR("{:L}"), F(1.234567e-5));
+  test(STR("0.0001234567"), STR("{:L}"), F(1.234567e-4));
+  test(STR("0.001234567"), STR("{:L}"), F(1.234567e-3));
+  test(STR("0.01234567"), STR("{:L}"), F(1.234567e-2));
+  test(STR("0.1234567"), STR("{:L}"), F(1.234567e-1));
+  test(STR("1.234567"), STR("{:L}"), F(1.234567e0));
+  test(STR("12.34567"), STR("{:L}"), F(1.234567e1));
+  test(STR("123.4567"), STR("{:L}"), F(1.234567e2));
+  test(STR("1,234.567"), STR("{:L}"), F(1.234567e3));
+  test(STR("12,345.67"), STR("{:L}"), F(1.234567e4));
+  test(STR("123,456.7"), STR("{:L}"), F(1.234567e5));
+  test(STR("1,234,567"), STR("{:L}"), F(1.234567e6));
+  test(STR("12,345,670"), STR("{:L}"), F(1.234567e7));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("123,456,700"), STR("{:L}"), F(1.234567e8));
+    test(STR("1,234,567,000"), STR("{:L}"), F(1.234567e9));
+    test(STR("12,345,670,000"), STR("{:L}"), F(1.234567e10));
+    test(STR("123,456,700,000"), STR("{:L}"), F(1.234567e11));
+    test(STR("1.234567e+12"), STR("{:L}"), F(1.234567e12));
+    test(STR("1.234567e+13"), STR("{:L}"), F(1.234567e13));
+  }
+  test(STR("-1.234567e-06"), STR("{:L}"), F(-1.234567e-6));
+  test(STR("-1.234567e-05"), STR("{:L}"), F(-1.234567e-5));
+  test(STR("-0.0001234567"), STR("{:L}"), F(-1.234567e-4));
+  test(STR("-0.001234567"), STR("{:L}"), F(-1.234567e-3));
+  test(STR("-0.01234567"), STR("{:L}"), F(-1.234567e-2));
+  test(STR("-0.1234567"), STR("{:L}"), F(-1.234567e-1));
+  test(STR("-1.234567"), STR("{:L}"), F(-1.234567e0));
+  test(STR("-12.34567"), STR("{:L}"), F(-1.234567e1));
+  test(STR("-123.4567"), STR("{:L}"), F(-1.234567e2));
+  test(STR("-1,234.567"), STR("{:L}"), F(-1.234567e3));
+  test(STR("-12,345.67"), STR("{:L}"), F(-1.234567e4));
+  test(STR("-123,456.7"), STR("{:L}"), F(-1.234567e5));
+  test(STR("-1,234,567"), STR("{:L}"), F(-1.234567e6));
+  test(STR("-12,345,670"), STR("{:L}"), F(-1.234567e7));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("-123,456,700"), STR("{:L}"), F(-1.234567e8));
+    test(STR("-1,234,567,000"), STR("{:L}"), F(-1.234567e9));
+    test(STR("-12,345,670,000"), STR("{:L}"), F(-1.234567e10));
+    test(STR("-123,456,700,000"), STR("{:L}"), F(-1.234567e11));
+    test(STR("-1.234567e+12"), STR("{:L}"), F(-1.234567e12));
+    test(STR("-1.234567e+13"), STR("{:L}"), F(-1.234567e13));
+  }
+
+  std::locale::global(loc);
+  test(STR("1#234567e-06"), STR("{:L}"), F(1.234567e-6));
+  test(STR("1#234567e-05"), STR("{:L}"), F(1.234567e-5));
+  test(STR("0#0001234567"), STR("{:L}"), F(1.234567e-4));
+  test(STR("0#001234567"), STR("{:L}"), F(1.234567e-3));
+  test(STR("0#01234567"), STR("{:L}"), F(1.234567e-2));
+  test(STR("0#1234567"), STR("{:L}"), F(1.234567e-1));
+  test(STR("1#234567"), STR("{:L}"), F(1.234567e0));
+  test(STR("1_2#34567"), STR("{:L}"), F(1.234567e1));
+  test(STR("12_3#4567"), STR("{:L}"), F(1.234567e2));
+  test(STR("1_23_4#567"), STR("{:L}"), F(1.234567e3));
+  test(STR("12_34_5#67"), STR("{:L}"), F(1.234567e4));
+  test(STR("123_45_6#7"), STR("{:L}"), F(1.234567e5));
+  test(STR("1_234_56_7"), STR("{:L}"), F(1.234567e6));
+  test(STR("12_345_67_0"), STR("{:L}"), F(1.234567e7));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("1_23_456_70_0"), STR("{:L}"), F(1.234567e8));
+    test(STR("1_2_34_567_00_0"), STR("{:L}"), F(1.234567e9));
+    test(STR("1_2_3_45_670_00_0"), STR("{:L}"), F(1.234567e10));
+    test(STR("1_2_3_4_56_700_00_0"), STR("{:L}"), F(1.234567e11));
+    test(STR("1#234567e+12"), STR("{:L}"), F(1.234567e12));
+    test(STR("1#234567e+13"), STR("{:L}"), F(1.234567e13));
+  }
+  test(STR("-1#234567e-06"), STR("{:L}"), F(-1.234567e-6));
+  test(STR("-1#234567e-05"), STR("{:L}"), F(-1.234567e-5));
+  test(STR("-0#0001234567"), STR("{:L}"), F(-1.234567e-4));
+  test(STR("-0#001234567"), STR("{:L}"), F(-1.234567e-3));
+  test(STR("-0#01234567"), STR("{:L}"), F(-1.234567e-2));
+  test(STR("-0#1234567"), STR("{:L}"), F(-1.234567e-1));
+  test(STR("-1#234567"), STR("{:L}"), F(-1.234567e0));
+  test(STR("-1_2#34567"), STR("{:L}"), F(-1.234567e1));
+  test(STR("-12_3#4567"), STR("{:L}"), F(-1.234567e2));
+  test(STR("-1_23_4#567"), STR("{:L}"), F(-1.234567e3));
+  test(STR("-12_34_5#67"), STR("{:L}"), F(-1.234567e4));
+  test(STR("-123_45_6#7"), STR("{:L}"), F(-1.234567e5));
+  test(STR("-1_234_56_7"), STR("{:L}"), F(-1.234567e6));
+  test(STR("-12_345_67_0"), STR("{:L}"), F(-1.234567e7));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("-1_23_456_70_0"), STR("{:L}"), F(-1.234567e8));
+    test(STR("-1_2_34_567_00_0"), STR("{:L}"), F(-1.234567e9));
+    test(STR("-1_2_3_45_670_00_0"), STR("{:L}"), F(-1.234567e10));
+    test(STR("-1_2_3_4_56_700_00_0"), STR("{:L}"), F(-1.234567e11));
+    test(STR("-1#234567e+12"), STR("{:L}"), F(-1.234567e12));
+    test(STR("-1#234567e+13"), STR("{:L}"), F(-1.234567e13));
+  }
+
+  test(STR("1.234567e-06"), en_US, STR("{:L}"), F(1.234567e-6));
+  test(STR("1.234567e-05"), en_US, STR("{:L}"), F(1.234567e-5));
+  test(STR("0.0001234567"), en_US, STR("{:L}"), F(1.234567e-4));
+  test(STR("0.001234567"), en_US, STR("{:L}"), F(1.234567e-3));
+  test(STR("0.01234567"), en_US, STR("{:L}"), F(1.234567e-2));
+  test(STR("0.1234567"), en_US, STR("{:L}"), F(1.234567e-1));
+  test(STR("1.234567"), en_US, STR("{:L}"), F(1.234567e0));
+  test(STR("12.34567"), en_US, STR("{:L}"), F(1.234567e1));
+  test(STR("123.4567"), en_US, STR("{:L}"), F(1.234567e2));
+  test(STR("1,234.567"), en_US, STR("{:L}"), F(1.234567e3));
+  test(STR("12,345.67"), en_US, STR("{:L}"), F(1.234567e4));
+  test(STR("123,456.7"), en_US, STR("{:L}"), F(1.234567e5));
+  test(STR("1,234,567"), en_US, STR("{:L}"), F(1.234567e6));
+  test(STR("12,345,670"), en_US, STR("{:L}"), F(1.234567e7));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("123,456,700"), en_US, STR("{:L}"), F(1.234567e8));
+    test(STR("1,234,567,000"), en_US, STR("{:L}"), F(1.234567e9));
+    test(STR("12,345,670,000"), en_US, STR("{:L}"), F(1.234567e10));
+    test(STR("123,456,700,000"), en_US, STR("{:L}"), F(1.234567e11));
+    test(STR("1.234567e+12"), en_US, STR("{:L}"), F(1.234567e12));
+    test(STR("1.234567e+13"), en_US, STR("{:L}"), F(1.234567e13));
+  }
+  test(STR("-1.234567e-06"), en_US, STR("{:L}"), F(-1.234567e-6));
+  test(STR("-1.234567e-05"), en_US, STR("{:L}"), F(-1.234567e-5));
+  test(STR("-0.0001234567"), en_US, STR("{:L}"), F(-1.234567e-4));
+  test(STR("-0.001234567"), en_US, STR("{:L}"), F(-1.234567e-3));
+  test(STR("-0.01234567"), en_US, STR("{:L}"), F(-1.234567e-2));
+  test(STR("-0.1234567"), en_US, STR("{:L}"), F(-1.234567e-1));
+  test(STR("-1.234567"), en_US, STR("{:L}"), F(-1.234567e0));
+  test(STR("-12.34567"), en_US, STR("{:L}"), F(-1.234567e1));
+  test(STR("-123.4567"), en_US, STR("{:L}"), F(-1.234567e2));
+  test(STR("-1,234.567"), en_US, STR("{:L}"), F(-1.234567e3));
+  test(STR("-12,345.67"), en_US, STR("{:L}"), F(-1.234567e4));
+  test(STR("-123,456.7"), en_US, STR("{:L}"), F(-1.234567e5));
+  test(STR("-1,234,567"), en_US, STR("{:L}"), F(-1.234567e6));
+  test(STR("-12,345,670"), en_US, STR("{:L}"), F(-1.234567e7));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("-123,456,700"), en_US, STR("{:L}"), F(-1.234567e8));
+    test(STR("-1,234,567,000"), en_US, STR("{:L}"), F(-1.234567e9));
+    test(STR("-12,345,670,000"), en_US, STR("{:L}"), F(-1.234567e10));
+    test(STR("-123,456,700,000"), en_US, STR("{:L}"), F(-1.234567e11));
+    test(STR("-1.234567e+12"), en_US, STR("{:L}"), F(-1.234567e12));
+    test(STR("-1.234567e+13"), en_US, STR("{:L}"), F(-1.234567e13));
+  }
+
+  std::locale::global(en_US);
+  test(STR("1#234567e-06"), loc, STR("{:L}"), F(1.234567e-6));
+  test(STR("1#234567e-05"), loc, STR("{:L}"), F(1.234567e-5));
+  test(STR("0#0001234567"), loc, STR("{:L}"), F(1.234567e-4));
+  test(STR("0#001234567"), loc, STR("{:L}"), F(1.234567e-3));
+  test(STR("0#01234567"), loc, STR("{:L}"), F(1.234567e-2));
+  test(STR("0#1234567"), loc, STR("{:L}"), F(1.234567e-1));
+  test(STR("1#234567"), loc, STR("{:L}"), F(1.234567e0));
+  test(STR("1_2#34567"), loc, STR("{:L}"), F(1.234567e1));
+  test(STR("12_3#4567"), loc, STR("{:L}"), F(1.234567e2));
+  test(STR("1_23_4#567"), loc, STR("{:L}"), F(1.234567e3));
+  test(STR("12_34_5#67"), loc, STR("{:L}"), F(1.234567e4));
+  test(STR("123_45_6#7"), loc, STR("{:L}"), F(1.234567e5));
+  test(STR("1_234_56_7"), loc, STR("{:L}"), F(1.234567e6));
+  test(STR("12_345_67_0"), loc, STR("{:L}"), F(1.234567e7));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("1_23_456_70_0"), loc, STR("{:L}"), F(1.234567e8));
+    test(STR("1_2_34_567_00_0"), loc, STR("{:L}"), F(1.234567e9));
+    test(STR("1_2_3_45_670_00_0"), loc, STR("{:L}"), F(1.234567e10));
+    test(STR("1_2_3_4_56_700_00_0"), loc, STR("{:L}"), F(1.234567e11));
+    test(STR("1#234567e+12"), loc, STR("{:L}"), F(1.234567e12));
+    test(STR("1#234567e+13"), loc, STR("{:L}"), F(1.234567e13));
+  }
+  test(STR("-1#234567e-06"), loc, STR("{:L}"), F(-1.234567e-6));
+  test(STR("-1#234567e-05"), loc, STR("{:L}"), F(-1.234567e-5));
+  test(STR("-0#0001234567"), loc, STR("{:L}"), F(-1.234567e-4));
+  test(STR("-0#001234567"), loc, STR("{:L}"), F(-1.234567e-3));
+  test(STR("-0#01234567"), loc, STR("{:L}"), F(-1.234567e-2));
+  test(STR("-0#1234567"), loc, STR("{:L}"), F(-1.234567e-1));
+  test(STR("-1#234567"), loc, STR("{:L}"), F(-1.234567e0));
+  test(STR("-1_2#34567"), loc, STR("{:L}"), F(-1.234567e1));
+  test(STR("-12_3#4567"), loc, STR("{:L}"), F(-1.234567e2));
+  test(STR("-1_23_4#567"), loc, STR("{:L}"), F(-1.234567e3));
+  test(STR("-12_34_5#67"), loc, STR("{:L}"), F(-1.234567e4));
+  test(STR("-123_45_6#7"), loc, STR("{:L}"), F(-1.234567e5));
+  test(STR("-1_234_56_7"), loc, STR("{:L}"), F(-1.234567e6));
+  test(STR("-12_345_67_0"), loc, STR("{:L}"), F(-1.234567e7));
+  if constexpr (sizeof(F) > sizeof(float)) {
+    test(STR("-1_23_456_70_0"), loc, STR("{:L}"), F(-1.234567e8));
+    test(STR("-1_2_34_567_00_0"), loc, STR("{:L}"), F(-1.234567e9));
+    test(STR("-1_2_3_45_670_00_0"), loc, STR("{:L}"), F(-1.234567e10));
+    test(STR("-1_2_3_4_56_700_00_0"), loc, STR("{:L}"), F(-1.234567e11));
+    test(STR("-1#234567e+12"), loc, STR("{:L}"), F(-1.234567e12));
+    test(STR("-1#234567e+13"), loc, STR("{:L}"), F(-1.234567e13));
+  }
+
+  // *** Fill, align, zero padding ***
+  std::locale::global(en_US);
+  test(STR("1,234.567$$$"), STR("{:$<12L}"), F(1.234567e3));
+  test(STR("$$$1,234.567"), STR("{:$>12L}"), F(1.234567e3));
+  test(STR("$1,234.567$$"), STR("{:$^12L}"), F(1.234567e3));
+  test(STR("0001,234.567"), STR("{:012L}"), F(1.234567e3));
+  test(STR("-1,234.567$$$"), STR("{:$<13L}"), F(-1.234567e3));
+  test(STR("$$$-1,234.567"), STR("{:$>13L}"), F(-1.234567e3));
+  test(STR("$-1,234.567$$"), STR("{:$^13L}"), F(-1.234567e3));
+  test(STR("-0001,234.567"), STR("{:013L}"), F(-1.234567e3));
+
+  std::locale::global(loc);
+  test(STR("1_23_4#567$$$"), STR("{:$<13L}"), F(1.234567e3));
+  test(STR("$$$1_23_4#567"), STR("{:$>13L}"), F(1.234567e3));
+  test(STR("$1_23_4#567$$"), STR("{:$^13L}"), F(1.234567e3));
+  test(STR("0001_23_4#567"), STR("{:013L}"), F(1.234567e3));
+  test(STR("-1_23_4#567$$$"), STR("{:$<14L}"), F(-1.234567e3));
+  test(STR("$$$-1_23_4#567"), STR("{:$>14L}"), F(-1.234567e3));
+  test(STR("$-1_23_4#567$$"), STR("{:$^14L}"), F(-1.234567e3));
+  test(STR("-0001_23_4#567"), STR("{:014L}"), F(-1.234567e3));
+
+  test(STR("1,234.567$$$"), en_US, STR("{:$<12L}"), F(1.234567e3));
+  test(STR("$$$1,234.567"), en_US, STR("{:$>12L}"), F(1.234567e3));
+  test(STR("$1,234.567$$"), en_US, STR("{:$^12L}"), F(1.234567e3));
+  test(STR("0001,234.567"), en_US, STR("{:012L}"), F(1.234567e3));
+  test(STR("-1,234.567$$$"), en_US, STR("{:$<13L}"), F(-1.234567e3));
+  test(STR("$$$-1,234.567"), en_US, STR("{:$>13L}"), F(-1.234567e3));
+  test(STR("$-1,234.567$$"), en_US, STR("{:$^13L}"), F(-1.234567e3));
+  test(STR("-0001,234.567"), en_US, STR("{:013L}"), F(-1.234567e3));
+
+  std::locale::global(en_US);
+  test(STR("1_23_4#567$$$"), loc, STR("{:$<13L}"), F(1.234567e3));
+  test(STR("$$$1_23_4#567"), loc, STR("{:$>13L}"), F(1.234567e3));
+  test(STR("$1_23_4#567$$"), loc, STR("{:$^13L}"), F(1.234567e3));
+  test(STR("0001_23_4#567"), loc, STR("{:013L}"), F(1.234567e3));
+  test(STR("-1_23_4#567$$$"), loc, STR("{:$<14L}"), F(-1.234567e3));
+  test(STR("$$$-1_23_4#567"), loc, STR("{:$>14L}"), F(-1.234567e3));
+  test(STR("$-1_23_4#567$$"), loc, STR("{:$^14L}"), F(-1.234567e3));
+  test(STR("-0001_23_4#567"), loc, STR("{:014L}"), F(-1.234567e3));
+}
+
+template <class F, class CharT>
+void test_floating_point_default_precision() {
+  std::locale loc = std::locale(std::locale(), new numpunct<CharT>());
+  std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+  // *** Basic ***
+  std::locale::global(en_US);
+  test(STR("1.23457e-06"), STR("{:.6L}"), F(1.234567e-6));
+  test(STR("1.23457e-05"), STR("{:.6L}"), F(1.234567e-5));
+  test(STR("0.000123457"), STR("{:.6L}"), F(1.234567e-4));
+  test(STR("0.00123457"), STR("{:.6L}"), F(1.234567e-3));
+  test(STR("0.0123457"), STR("{:.6L}"), F(1.234567e-2));
+  test(STR("0.123457"), STR("{:.6L}"), F(1.234567e-1));
+  test(STR("1.23457"), STR("{:.6L}"), F(1.234567e0));
+  test(STR("12.3457"), STR("{:.6L}"), F(1.234567e1));
+  test(STR("123.457"), STR("{:.6L}"), F(1.234567e2));
+  test(STR("1,234.57"), STR("{:.6L}"), F(1.234567e3));
+  test(STR("12,345.7"), STR("{:.6L}"), F(1.234567e4));
+  test(STR("123,457"), STR("{:.6L}"), F(1.234567e5));
+  test(STR("1.23457e+06"), STR("{:.6L}"), F(1.234567e6));
+  test(STR("1.23457e+07"), STR("{:.6L}"), F(1.234567e7));
+  test(STR("-1.23457e-06"), STR("{:.6L}"), F(-1.234567e-6));
+  test(STR("-1.23457e-05"), STR("{:.6L}"), F(-1.234567e-5));
+  test(STR("-0.000123457"), STR("{:.6L}"), F(-1.234567e-4));
+  test(STR("-0.00123457"), STR("{:.6L}"), F(-1.234567e-3));
+  test(STR("-0.0123457"), STR("{:.6L}"), F(-1.234567e-2));
+  test(STR("-0.123457"), STR("{:.6L}"), F(-1.234567e-1));
+  test(STR("-1.23457"), STR("{:.6L}"), F(-1.234567e0));
+  test(STR("-12.3457"), STR("{:.6L}"), F(-1.234567e1));
+  test(STR("-123.457"), STR("{:.6L}"), F(-1.234567e2));
+  test(STR("-1,234.57"), STR("{:.6L}"), F(-1.234567e3));
+  test(STR("-12,345.7"), STR("{:.6L}"), F(-1.234567e4));
+  test(STR("-123,457"), STR("{:.6L}"), F(-1.234567e5));
+  test(STR("-1.23457e+06"), STR("{:.6L}"), F(-1.234567e6));
+  test(STR("-1.23457e+07"), STR("{:.6L}"), F(-1.234567e7));
+
+  std::locale::global(loc);
+  test(STR("1#23457e-06"), STR("{:.6L}"), F(1.234567e-6));
+  test(STR("1#23457e-05"), STR("{:.6L}"), F(1.234567e-5));
+  test(STR("0#000123457"), STR("{:.6L}"), F(1.234567e-4));
+  test(STR("0#00123457"), STR("{:.6L}"), F(1.234567e-3));
+  test(STR("0#0123457"), STR("{:.6L}"), F(1.234567e-2));
+  test(STR("0#123457"), STR("{:.6L}"), F(1.234567e-1));
+  test(STR("1#23457"), STR("{:.6L}"), F(1.234567e0));
+  test(STR("1_2#3457"), STR("{:.6L}"), F(1.234567e1));
+  test(STR("12_3#457"), STR("{:.6L}"), F(1.234567e2));
+  test(STR("1_23_4#57"), STR("{:.6L}"), F(1.234567e3));
+  test(STR("12_34_5#7"), STR("{:.6L}"), F(1.234567e4));
+  test(STR("123_45_7"), STR("{:.6L}"), F(1.234567e5));
+  test(STR("1#23457e+06"), STR("{:.6L}"), F(1.234567e6));
+  test(STR("1#23457e+07"), STR("{:.6L}"), F(1.234567e7));
+  test(STR("-1#23457e-06"), STR("{:.6L}"), F(-1.234567e-6));
+  test(STR("-1#23457e-05"), STR("{:.6L}"), F(-1.234567e-5));
+  test(STR("-0#000123457"), STR("{:.6L}"), F(-1.234567e-4));
+  test(STR("-0#00123457"), STR("{:.6L}"), F(-1.234567e-3));
+  test(STR("-0#0123457"), STR("{:.6L}"), F(-1.234567e-2));
+  test(STR("-0#123457"), STR("{:.6L}"), F(-1.234567e-1));
+  test(STR("-1#23457"), STR("{:.6L}"), F(-1.234567e0));
+  test(STR("-1_2#3457"), STR("{:.6L}"), F(-1.234567e1));
+  test(STR("-12_3#457"), STR("{:.6L}"), F(-1.234567e2));
+  test(STR("-1_23_4#57"), STR("{:.6L}"), F(-1.234567e3));
+  test(STR("-12_34_5#7"), STR("{:.6L}"), F(-1.234567e4));
+  test(STR("-123_45_7"), STR("{:.6L}"), F(-1.234567e5));
+  test(STR("-1#23457e+06"), STR("{:.6L}"), F(-1.234567e6));
+  test(STR("-1#23457e+07"), STR("{:.6L}"), F(-1.234567e7));
+
+  test(STR("1.23457e-06"), en_US, STR("{:.6L}"), F(1.234567e-6));
+  test(STR("1.23457e-05"), en_US, STR("{:.6L}"), F(1.234567e-5));
+  test(STR("0.000123457"), en_US, STR("{:.6L}"), F(1.234567e-4));
+  test(STR("0.00123457"), en_US, STR("{:.6L}"), F(1.234567e-3));
+  test(STR("0.0123457"), en_US, STR("{:.6L}"), F(1.234567e-2));
+  test(STR("0.123457"), en_US, STR("{:.6L}"), F(1.234567e-1));
+  test(STR("1.23457"), en_US, STR("{:.6L}"), F(1.234567e0));
+  test(STR("12.3457"), en_US, STR("{:.6L}"), F(1.234567e1));
+  test(STR("123.457"), en_US, STR("{:.6L}"), F(1.234567e2));
+  test(STR("1,234.57"), en_US, STR("{:.6L}"), F(1.234567e3));
+  test(STR("12,345.7"), en_US, STR("{:.6L}"), F(1.234567e4));
+  test(STR("123,457"), en_US, STR("{:.6L}"), F(1.234567e5));
+  test(STR("1.23457e+06"), en_US, STR("{:.6L}"), F(1.234567e6));
+  test(STR("1.23457e+07"), en_US, STR("{:.6L}"), F(1.234567e7));
+  test(STR("-1.23457e-06"), en_US, STR("{:.6L}"), F(-1.234567e-6));
+  test(STR("-1.23457e-05"), en_US, STR("{:.6L}"), F(-1.234567e-5));
+  test(STR("-0.000123457"), en_US, STR("{:.6L}"), F(-1.234567e-4));
+  test(STR("-0.00123457"), en_US, STR("{:.6L}"), F(-1.234567e-3));
+  test(STR("-0.0123457"), en_US, STR("{:.6L}"), F(-1.234567e-2));
+  test(STR("-0.123457"), en_US, STR("{:.6L}"), F(-1.234567e-1));
+  test(STR("-1.23457"), en_US, STR("{:.6L}"), F(-1.234567e0));
+  test(STR("-12.3457"), en_US, STR("{:.6L}"), F(-1.234567e1));
+  test(STR("-123.457"), en_US, STR("{:.6L}"), F(-1.234567e2));
+  test(STR("-1,234.57"), en_US, STR("{:.6L}"), F(-1.234567e3));
+  test(STR("-12,345.7"), en_US, STR("{:.6L}"), F(-1.234567e4));
+  test(STR("-123,457"), en_US, STR("{:.6L}"), F(-1.234567e5));
+  test(STR("-1.23457e+06"), en_US, STR("{:.6L}"), F(-1.234567e6));
+  test(STR("-1.23457e+07"), en_US, STR("{:.6L}"), F(-1.234567e7));
+
+  std::locale::global(en_US);
+  test(STR("1#23457e-06"), loc, STR("{:.6L}"), F(1.234567e-6));
+  test(STR("1#23457e-05"), loc, STR("{:.6L}"), F(1.234567e-5));
+  test(STR("0#000123457"), loc, STR("{:.6L}"), F(1.234567e-4));
+  test(STR("0#00123457"), loc, STR("{:.6L}"), F(1.234567e-3));
+  test(STR("0#0123457"), loc, STR("{:.6L}"), F(1.234567e-2));
+  test(STR("0#123457"), loc, STR("{:.6L}"), F(1.234567e-1));
+  test(STR("1#23457"), loc, STR("{:.6L}"), F(1.234567e0));
+  test(STR("1_2#3457"), loc, STR("{:.6L}"), F(1.234567e1));
+  test(STR("12_3#457"), loc, STR("{:.6L}"), F(1.234567e2));
+  test(STR("1_23_4#57"), loc, STR("{:.6L}"), F(1.234567e3));
+  test(STR("12_34_5#7"), loc, STR("{:.6L}"), F(1.234567e4));
+  test(STR("123_45_7"), loc, STR("{:.6L}"), F(1.234567e5));
+  test(STR("1#23457e+06"), loc, STR("{:.6L}"), F(1.234567e6));
+  test(STR("1#23457e+07"), loc, STR("{:.6L}"), F(1.234567e7));
+  test(STR("-1#23457e-06"), loc, STR("{:.6L}"), F(-1.234567e-6));
+  test(STR("-1#23457e-05"), loc, STR("{:.6L}"), F(-1.234567e-5));
+  test(STR("-0#000123457"), loc, STR("{:.6L}"), F(-1.234567e-4));
+  test(STR("-0#00123457"), loc, STR("{:.6L}"), F(-1.234567e-3));
+  test(STR("-0#0123457"), loc, STR("{:.6L}"), F(-1.234567e-2));
+  test(STR("-0#123457"), loc, STR("{:.6L}"), F(-1.234567e-1));
+  test(STR("-1#23457"), loc, STR("{:.6L}"), F(-1.234567e0));
+  test(STR("-1_2#3457"), loc, STR("{:.6L}"), F(-1.234567e1));
+  test(STR("-12_3#457"), loc, STR("{:.6L}"), F(-1.234567e2));
+  test(STR("-1_23_4#57"), loc, STR("{:.6L}"), F(-1.234567e3));
+  test(STR("-12_34_5#7"), loc, STR("{:.6L}"), F(-1.234567e4));
+  test(STR("-123_45_7"), loc, STR("{:.6L}"), F(-1.234567e5));
+  test(STR("-1#23457e+06"), loc, STR("{:.6L}"), F(-1.234567e6));
+  test(STR("-1#23457e+07"), loc, STR("{:.6L}"), F(-1.234567e7));
+
+  // *** Fill, align, zero padding ***
+  std::locale::global(en_US);
+  test(STR("1,234.57$$$"), STR("{:$<11.6L}"), F(1.234567e3));
+  test(STR("$$$1,234.57"), STR("{:$>11.6L}"), F(1.234567e3));
+  test(STR("$1,234.57$$"), STR("{:$^11.6L}"), F(1.234567e3));
+  test(STR("0001,234.57"), STR("{:011.6L}"), F(1.234567e3));
+  test(STR("-1,234.57$$$"), STR("{:$<12.6L}"), F(-1.234567e3));
+  test(STR("$$$-1,234.57"), STR("{:$>12.6L}"), F(-1.234567e3));
+  test(STR("$-1,234.57$$"), STR("{:$^12.6L}"), F(-1.234567e3));
+  test(STR("-0001,234.57"), STR("{:012.6L}"), F(-1.234567e3));
+
+  std::locale::global(loc);
+  test(STR("1_23_4#57$$$"), STR("{:$<12.6L}"), F(1.234567e3));
+  test(STR("$$$1_23_4#57"), STR("{:$>12.6L}"), F(1.234567e3));
+  test(STR("$1_23_4#57$$"), STR("{:$^12.6L}"), F(1.234567e3));
+  test(STR("0001_23_4#57"), STR("{:012.6L}"), F(1.234567e3));
+  test(STR("-1_23_4#57$$$"), STR("{:$<13.6L}"), F(-1.234567e3));
+  test(STR("$$$-1_23_4#57"), STR("{:$>13.6L}"), F(-1.234567e3));
+  test(STR("$-1_23_4#57$$"), STR("{:$^13.6L}"), F(-1.234567e3));
+  test(STR("-0001_23_4#57"), STR("{:013.6L}"), F(-1.234567e3));
+
+  test(STR("1,234.57$$$"), en_US, STR("{:$<11.6L}"), F(1.234567e3));
+  test(STR("$$$1,234.57"), en_US, STR("{:$>11.6L}"), F(1.234567e3));
+  test(STR("$1,234.57$$"), en_US, STR("{:$^11.6L}"), F(1.234567e3));
+  test(STR("0001,234.57"), en_US, STR("{:011.6L}"), F(1.234567e3));
+  test(STR("-1,234.57$$$"), en_US, STR("{:$<12.6L}"), F(-1.234567e3));
+  test(STR("$$$-1,234.57"), en_US, STR("{:$>12.6L}"), F(-1.234567e3));
+  test(STR("$-1,234.57$$"), en_US, STR("{:$^12.6L}"), F(-1.234567e3));
+  test(STR("-0001,234.57"), en_US, STR("{:012.6L}"), F(-1.234567e3));
+
+  std::locale::global(en_US);
+  test(STR("1_23_4#57$$$"), loc, STR("{:$<12.6L}"), F(1.234567e3));
+  test(STR("$$$1_23_4#57"), loc, STR("{:$>12.6L}"), F(1.234567e3));
+  test(STR("$1_23_4#57$$"), loc, STR("{:$^12.6L}"), F(1.234567e3));
+  test(STR("0001_23_4#57"), loc, STR("{:012.6L}"), F(1.234567e3));
+  test(STR("-1_23_4#57$$$"), loc, STR("{:$<13.6L}"), F(-1.234567e3));
+  test(STR("$$$-1_23_4#57"), loc, STR("{:$>13.6L}"), F(-1.234567e3));
+  test(STR("$-1_23_4#57$$"), loc, STR("{:$^13.6L}"), F(-1.234567e3));
+  test(STR("-0001_23_4#57"), loc, STR("{:013.6L}"), F(-1.234567e3));
+}
+
+template <class F, class CharT >
+void test_floating_point() {
+  test_floating_point_hex_lower_case<F, CharT>();
+  test_floating_point_hex_upper_case<F, CharT>();
+  test_floating_point_hex_lower_case_precision<F, CharT>();
+  test_floating_point_hex_upper_case_precision<F, CharT>();
+
+  test_floating_point_scientific_lower_case<F, CharT>();
+  test_floating_point_scientific_upper_case<F, CharT>();
+
+  test_floating_point_fixed_lower_case<F, CharT>();
+  test_floating_point_fixed_upper_case<F, CharT>();
+
+  test_floating_point_general_lower_case<F, CharT>();
+  test_floating_point_general_upper_case<F, CharT>();
+
+  test_floating_point_default<F, CharT>();
+  test_floating_point_default_precision<F, CharT>();
+}
+
 template <class CharT>
 void test() {
   test_bool<CharT>();
   test_integer<CharT>();
+  test_floating_point<float, CharT>();
+  test_floating_point<double, CharT>();
+  test_floating_point<long double, CharT>();
 }
 
 int main(int, char**) {


        


More information about the libcxx-commits mailing list