diff --git a/libstdc++-v3/include/std/ostream b/libstdc++-v3/include/std/ostream
index d8462efe764d4ebd432de0032021aed8f8be3fe4..a1cb7ce1765e770d926cb25257fd7ca817152fef 100644
--- a/libstdc++-v3/include/std/ostream
+++ b/libstdc++-v3/include/std/ostream
@@ -235,7 +235,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       {
 	// _GLIBCXX_RESOLVE_LIB_DEFECTS
 	// 117. basic_ostream uses nonexistent num_put member functions.
-	return _M_insert(static_cast<double>(__f));
+	return _M_insert(_S_cast_flt<double>(__f));
       }
 
       __ostream_type&
@@ -248,7 +248,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __ostream_type&
       operator<<(_Float16 __f)
       {
-	return _M_insert(static_cast<double>(__f));
+	return _M_insert(_S_cast_flt<double>(__f));
       }
 #endif
 
@@ -257,7 +257,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __ostream_type&
       operator<<(_Float32 __f)
       {
-	return _M_insert(static_cast<double>(__f));
+	return _M_insert(_S_cast_flt<double>(__f));
       }
 #endif
 
@@ -266,7 +266,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __ostream_type&
       operator<<(_Float64 __f)
       {
-	return _M_insert(static_cast<double>(__f));
+	return _M_insert(_S_cast_flt<double>(__f));
       }
 #endif
 
@@ -275,7 +275,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __ostream_type&
       operator<<(_Float128 __f)
       {
-	return _M_insert(static_cast<long double>(__f));
+	return _M_insert(_S_cast_flt<long double>(__f));
       }
 #endif
 
@@ -284,7 +284,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __ostream_type&
       operator<<(__gnu_cxx::__bfloat16_t __f)
       {
-	return _M_insert(static_cast<double>(__f));
+	return _M_insert(_S_cast_flt<double>(__f));
       }
 #endif
 
@@ -475,7 +475,38 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _M_write(const char_type* __s, streamsize __n)
       { std::__ostream_insert(*this, __s, __n); }
 #endif
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions" // for if-constexpr
+      template<typename _To, typename _From>
+	static _To
+	_S_cast_flt(_From __f)
+	{
+	  _To __d = static_cast<_To>(__f);
+	  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+	  // 4101: LWG 117 loses the sign for negative NaN on some arches.
+#if defined __riscv
+	  _To __sign;
+#if __cpp_constexpr && __has_builtin(__builtin_bit_cast)
+	  if constexpr (sizeof(__f) == sizeof(short))
+	    __sign = static_cast<_To>(__builtin_bit_cast(short, __f));
+	  else if constexpr (sizeof(__f) == sizeof(int))
+	    __sign = static_cast<_To>(__builtin_bit_cast(int, __f));
+	  else if constexpr (sizeof(__f) == sizeof(long long))
+	    __sign = static_cast<_To>(__builtin_bit_cast(long long, __f));
+	  else
+#endif
+	  __sign = __builtin_signbit(__f) ? _To(-1.0) : _To(+1.0);
+
+	  if _GLIBCXX17_CONSTEXPR (__is_same(_To, double))
+	    __d = __builtin_copysign(__d, __sign);
+	  else if _GLIBCXX17_CONSTEXPR (__is_same(_To, long double))
+	    __d = __builtin_copysignl(__d, __sign);
+#endif
+	  return __d;
+	}
     };
+#pragma GCC diagnostic pop
 
   /**
    *  @brief  Performs setup work for output streams.
diff --git a/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_arithmetic/lwg4101.cc b/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_arithmetic/lwg4101.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1e1b8e08535df5f389006c04a7065f85aa7f8589
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_arithmetic/lwg4101.cc
@@ -0,0 +1,14 @@
+// { dg-do run }
+// LWG 4101. LWG 117 loses the sign for negative NaN on some architectures
+
+#include <sstream>
+#include <limits>
+#include <testsuite_hooks.h>
+
+int main()
+{
+  float nan = std::numeric_limits<float>::quiet_NaN();
+  std::ostringstream os;
+  os << -nan;
+  VERIFY( os.str()[0] == '-' );
+}