diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
index 6e1e06cb2d0f..855ab1395149 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -1945,12 +1945,10 @@ namespace ranges
 
   struct __shuffle_fn
   {
-    template<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
-	     typename _Gen>
-      requires permutable<_Iter>
-	&& uniform_random_bit_generator<remove_reference_t<_Gen>>
-      _Iter
-      operator()(_Iter __first, _Sent __last, _Gen&& __g) const
+    template<typename _Iter, typename _Sent, typename _Gen>
+      static _Iter
+      _S_impl(_Iter __first, _Sent __last, _Gen&& __g,
+	      iter_difference_t<_Iter> __n)
       {
 	// FIXME: Correctly handle integer-class difference types.
 	if (__first == __last)
@@ -1964,8 +1962,10 @@ namespace ranges
 	using __uc_type
 	  = common_type_t<typename remove_reference_t<_Gen>::result_type, __ud_type>;
 
+	if (__n != -1)
+	  {
 	    const __uc_type __urngrange = __g.max() - __g.min();
-	const __uc_type __urange = __uc_type(__last - __first);
+	    const __uc_type __urange = __uc_type(__n);
 
 	    if (__urngrange / __urange >= __urange)
 	      // I.e. (__urngrange >= __urange * __urange) but without wrap issues.
@@ -1999,6 +1999,7 @@ namespace ranges
 
 		return __i;
 	      }
+	  }
 
 	__distr_type __d;
 
@@ -2009,14 +2010,30 @@ namespace ranges
 	return __i;
       }
 
+    template<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
+	     typename _Gen>
+      requires permutable<_Iter>
+	&& uniform_random_bit_generator<remove_reference_t<_Gen>>
+      _Iter
+      operator()(_Iter __first, _Sent __last, _Gen&& __g) const
+      {
+	iter_difference_t<_Iter> __n = -1;
+	if constexpr (sized_sentinel_for<_Sent, _Iter>)
+	  __n = __last - __first;
+	return _S_impl(__first, __last, std::forward<_Gen>(__g), __n);
+      }
+
     template<random_access_range _Range, typename _Gen>
       requires permutable<iterator_t<_Range>>
 	&& uniform_random_bit_generator<remove_reference_t<_Gen>>
       borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Gen&& __g) const
       {
-	return (*this)(ranges::begin(__r), ranges::end(__r),
-		       std::forward<_Gen>(__g));
+	range_difference_t<_Range> __n = -1;
+	if constexpr (sized_range<_Range>)
+	  __n = ranges::size(__r);
+	return _S_impl(ranges::begin(__r), ranges::end(__r),
+		       std::forward<_Gen>(__g), __n);
       }
   };
 
diff --git a/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc
index 70c6bdfc3d9e..4d633561508b 100644
--- a/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc
@@ -86,9 +86,27 @@ test02()
   ranges::shuffle(w, g);
 }
 
+struct non_default_sentinel_t { };
+
+template<std::input_or_output_iterator I>
+bool operator==(const I& i, non_default_sentinel_t)
+{ return i == std::default_sentinel; }
+
+void
+test03()
+{
+  // PR libstdc++/121917 - ranges::shuffle incorrectly requires its arguments
+  // to model sized_sentinel_for
+  int a[2]{};
+  std::counted_iterator iter(a, 2);
+  std::default_random_engine e;
+  std::ranges::shuffle(iter, non_default_sentinel_t{}, e);
+}
+
 int
 main()
 {
   test01();
   test02();
+  test03();
 }
