From patchwork Fri Sep 12 11:51:26 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cassio Neri X-Patchwork-Id: 120130 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A7B813857C5D for ; Fri, 12 Sep 2025 11:54:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A7B813857C5D Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=gWJIGsv5 X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x429.google.com (mail-wr1-x429.google.com [IPv6:2a00:1450:4864:20::429]) by sourceware.org (Postfix) with ESMTPS id BC9D63857C7A for ; Fri, 12 Sep 2025 11:51:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org BC9D63857C7A Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org BC9D63857C7A Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a00:1450:4864:20::429 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1757677891; cv=none; b=GPtdnFQ6xyOSoyGL/EUJd1qRJRrnpj/eCwzEBt8AOmsyVnPpNae79xNxzsf6zzNJgZ9HKrN3Mxrz8lHu2tJU9w11w6WAhJvBGIPzXCOfxBfWZVgna1/rVHDncDQTwpkI4dEMPGIFLrZVNqH107kWgE2NskhTBh21ePCHljBKz6Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1757677891; c=relaxed/simple; bh=hqStAYfnuO2XVjfSx5jBam6C/I1uhVoyH5XZ7WtP1Kg=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=MlnUylZEvUYofFmXloaQ2H/AIpsVQXwOFLiOE4lDcCH/T2gU+Nbq4pdE+74CzujFIC6Jpb9Brym+HO9Hmb+DkGuxWMIvj9/B0R9yZMdCIAf3/8D3pkGZ+NwyypYZoQXa8NiQ8fCFIvOcx+PFVIuGJcJIHi4LvjWrUzeGJkmQPaw= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BC9D63857C7A Received: by mail-wr1-x429.google.com with SMTP id ffacd0b85a97d-3df726ecff3so1047059f8f.3 for ; Fri, 12 Sep 2025 04:51:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1757677888; x=1758282688; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=GQ9jb4NRLb/RtnDIjvJ/roBndvtUIoTHwFvUshgwP+0=; b=gWJIGsv5HVFBxg/p/wb04OvwLxmf6nid2SdN4zcPK2y5FWZFmiL9bfF6uXxScCUp5P WHQud62U8epTJ+OKNvDHkMRynxPjzA7+lVO8GgUTtFSKJpdw4gBiZvwgM8FqNzbAZAex Bj8hJLvHLqsPslO2HApErGvVVvcXi2RzJF+Lsyc419MYs8KTiD1ySaPncRymvGZsanyg QdZFruCQT8qqi9ziWukYyzSAl7uWg0LAaP7XL5N2wsXewoRxUxkiWNcLkfqsXxikkIud ncmmEbwpJ4l3RpZg6ojRkT3yz4IW1tmR32OZMdNapb6i2q3A31duWXgcu7MMvpggpd5x Eshw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757677888; x=1758282688; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=GQ9jb4NRLb/RtnDIjvJ/roBndvtUIoTHwFvUshgwP+0=; b=wpiRwqykhNC/MwR6Mcwd/3pqNA/DBz4RwILf/Vsy2xTpOeVhyVuVh97LCj7oGBWpUg C/gpU5aWAjwIWdl/X+jyn4x8EbdsTNj5a5x520sfOHcCy0vsw+Fifao2T+7a3SdESlM2 fim0sIv2zrPGyMdne7CSGs9KSFcUSnzdRCwQGB4wSV2xKysvC5mAubZX4leL6YgtTqnS Hv/McF+tyKeBi8gWGLIGrCiZkeIg3jYVY8Kj7gxIojAnDVfdiV1sZr3IzbbA+AOUFYY7 dBM/7EZSyoTQ98gmK+oo9m3OI/B1fhXR0nyKPYg8C9h9qx7YTaSlWMB6eIRz72RUtfpp qtvA== X-Forwarded-Encrypted: i=1; AJvYcCUb45kxSAQlTVmFFr+M67MS2xJxQpK9kS0f4SVBbNUC+mLMPL4jxHAsXVY2+YZAl0MBg32jsNgWqTyYAQ==@gcc.gnu.org X-Gm-Message-State: AOJu0Ywz4jlbWriITqcercGBggN6Cq7DcsS09JFW6MKVlb8sV7uFMV1S peqcP+KoiU8dEjo6JOwL5CUFIsdPLmy0AhOwYPfvviqVDLq1avTvs3zc X-Gm-Gg: ASbGncsUtc59fc5UuODzQizlK2l7vjCOM2qjComVoFfyWZiUcZ7GvdFjcOByvOMlDyI dE5xx2DeLTE+yMQlgFO8TzjRQSIZal+j+Sde8Njpp5a860la96Pk/7qwwFav39+ZRcEiLd4MVoa DyBc7OED/0CsAmAcFu5zSG+SmuQZPpgkWgB4WTHPsjIKiaRR1pV85NhrZnS6GcvN9liWkjdxiJ6 5H0ywfFEVUByxyevl0SOfOZ2LsCzE+nx6N8JE8sSrQH16VY8pzBH9Pijwe4yONQhhiMozbNGaNA PLR9981AQgmwkORfBUGv+yvM73ZV7CsEPmSPPfadCnyt/iZmmViatJxRrGEi2O+1Zd6p/iy4qBy Xn65m/fv3vF1neGhxtwxPwc2Q4MqIYDMIQ/IiSBBqun3Qiuk80q0m8DDjtX1RCStJj1WkHGBMgE /1 X-Google-Smtp-Source: AGHT+IHt3u6zyIYGghTqc32hyfSBOABJq+Jc8vrYmYfMeaAT30NhzOiofDXXZN7MZ7COIFFWqpqyXw== X-Received: by 2002:a05:6000:25c5:b0:3de:daf2:edca with SMTP id ffacd0b85a97d-3e7657931ecmr2927045f8f.21.1757677888116; Fri, 12 Sep 2025 04:51:28 -0700 (PDT) Received: from asterix.home (89.178.198.146.dyn.plus.net. [146.198.178.89]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3e7607cd27dsm6177874f8f.41.2025.09.12.04.51.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Sep 2025 04:51:27 -0700 (PDT) From: Cassio Neri To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Cc: Cassio Neri Subject: [PATCH] libstdc++: Fix generate_canonical for float16_t and float128_t [PR 121926] Date: Fri, 12 Sep 2025 12:51:26 +0100 Message-ID: <20250912115126.21006-1-cassio.neri@gmail.com> X-Mailer: git-send-email 2.51.0 MIME-Version: 1.0 X-Spam-Status: No, score=-11.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, URIBL_ABUSE_SURBL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org The current implementation of generate_canonical yields NAN for float16_t and fails to compile for float128_t on platforms where long double is IBM-128. Indeed, it sets a long double variable based the provided RNG: const long double __r = number_of_elements_in_the_range_of_the_RNG; Later it multiplies __r to a variable __tmp of type _RealType, the provided floating-point type: __tmp *= __r; When _RealType is float16_t the implicit cast from long double to float16_t might yield infinity and subsequent calculations, notably the returned value, become NAN. When _RealType is float128_t (_Float128/__float128) and long double is IBM-128, compilation fails because multiplication of IBM-128 and float128_t is undefined. This patch fixes these issues by performing all intermediate calculations using _CalcType which is the largest between _RealType and double. The end result is cast to _RealType and returned. _CalcType being at least double is probably enough to prevent __r from being infinity. Nevertheless, this is static_asserted and, in case of failure, the user is informed that the combination of _RealType and the provided RNG is invalid. PR libstdc++/121926 libstdc++-v3/ChangeLog: * include/bits/random.h: Prevent narrowing warning in uniform_real_distribution. * include/bits/random.tcc: Fix generate_canonical. * testsuite/26_numerics/random/uniform_real_distribution/cons/stdfloat-c++23.cc: New test. --- libstdc++-v3/include/bits/random.h | 2 +- libstdc++-v3/include/bits/random.tcc | 34 ++++++++--- .../cons/stdfloat-c++23.cc | 60 +++++++++++++++++++ 3 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/cons/stdfloat-c++23.cc diff --git a/libstdc++-v3/include/bits/random.h b/libstdc++-v3/include/bits/random.h index 1fdaf51934f..b6ec07164ac 100644 --- a/libstdc++-v3/include/bits/random.h +++ b/libstdc++-v3/include/bits/random.h @@ -1930,7 +1930,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * * The lower bound is set to 0.0 and the upper bound to 1.0 */ - uniform_real_distribution() : uniform_real_distribution(0.0) { } + uniform_real_distribution() : uniform_real_distribution(_RealType(0)) { } /** * @brief Constructs a uniform_real_distribution object. diff --git a/libstdc++-v3/include/bits/random.tcc b/libstdc++-v3/include/bits/random.tcc index 53ccacb2e38..2c10007d7e8 100644 --- a/libstdc++-v3/include/bits/random.tcc +++ b/libstdc++-v3/include/bits/random.tcc @@ -3357,23 +3357,39 @@ namespace __detail static_assert(std::is_floating_point<_RealType>::value, "template argument must be a floating point type"); + using _CalcType = typename std::conditional< + sizeof(_RealType) >= sizeof(double), _RealType, double>::type; + const size_t __b - = std::min(static_cast(std::numeric_limits<_RealType>::digits), + = std::min(static_cast(std::numeric_limits<_CalcType>::digits), __bits); - const long double __r = static_cast(__urng.max()) - - static_cast(__urng.min()) + 1.0L; - const size_t __log2r = std::log(__r) / std::log(2.0L); + constexpr _CalcType __r = static_cast<_CalcType>(__urng.max()) + - static_cast<_CalcType>(__urng.min()) + + _CalcType(1); + +#if _GLIBCXX_USE_C99_MATH_FUNCS + constexpr bool __is_finite = std::isfinite(__r); +#else + constexpr bool __is_finite = + __r < std::numeric_limits<_CalcType>::infinity(); +#endif + static_assert(__r > _CalcType(0) && __is_finite, + "invalid combination of floating point type and generator"); + + const size_t __log2r = std::log(__r) / std::log(_CalcType(2)); const size_t __m = std::max(1UL, (__b + __log2r - 1UL) / __log2r); - _RealType __ret; - _RealType __sum = _RealType(0); - _RealType __tmp = _RealType(1); + _CalcType __res; + _CalcType __sum = _CalcType(0); + _CalcType __tmp = _CalcType(1); for (size_t __k = __m; __k != 0; --__k) { - __sum += _RealType(__urng() - __urng.min()) * __tmp; + __sum += _CalcType(__urng() - __urng.min()) * __tmp; __tmp *= __r; } - __ret = __sum / __tmp; + __res = __sum / __tmp; + + _RealType __ret = static_cast<_RealType>(__res); if (__builtin_expect(__ret >= _RealType(1), 0)) { #if _GLIBCXX_USE_C99_MATH_FUNCS diff --git a/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/cons/stdfloat-c++23.cc b/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/cons/stdfloat-c++23.cc new file mode 100644 index 00000000000..ce78c17021b --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/cons/stdfloat-c++23.cc @@ -0,0 +1,60 @@ +// { dg-do run { target c++23 } } +// +// Copyright (C) 2008-2025 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +#include +#include +#include + +template + void + test() + { + std::uniform_real_distribution u; + VERIFY( u.a() == Float{0} ); + VERIFY( u.b() == Float{1} ); + VERIFY( u.min() == Float{0} ); + VERIFY( u.max() == Float{1} ); + + auto device = std::mt19937_64{}; + for (unsigned n = 0; n < 10; ++n) + { + auto const x = u(device); + VERIFY( x >= Float{0} ); + VERIFY( x < Float{1} ); + } + } + +int main() +{ +#ifdef __STDCPP_FLOAT16_T__ + test(); +#endif +#ifdef __STDCPP_FLOAT32_T__ + test(); +#endif +#ifdef __STDCPP_FLOAT64_T__ + test(); +#endif +#ifdef __STDCPP_FLOAT128_T__ + test(); +#endif +#ifdef __STDCPP_BFLOAT16_T__ + test(); +#endif +}