- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这个问题很清楚。下面给出了我认为这些表达式可能产生未定义行为的原因。我想知道我的推理是对还是错,为什么。
短读 :
(IEEE 754) double
不是 Cpp17LessThanComparable,因为 <
由于 NaN
不是严格的弱排序关系.因此,需要 std::min<double>
的元素和 std::max<double>
被侵犯。
长读 :
所有引用文献都遵循 n4800 . std::min
规范和 std::max
在 24.7.8 中给出:
template<class T> constexpr const T& min(const T& a, const T& b);
template<class T> constexpr const T& max(const T& a, const T& b);
Requires: [...] type T shall be Cpp17LessThanComparable (Table 24).
Requirement:
<
is a strict weak ordering relation (24.7)
<
它指出“如果我们将
equiv(a, b)
定义为
!(a < b) && !(b < a)
,那么
equiv(a, b) && equiv(b, c)
意味着
equiv(a, c)
”。
equiv(0.0, NaN) == true
,
equiv(NaN, 1.0) == true
但是
equiv(0.0, 1.0) == false
我们得出的结论是
<
是
不是 严格的弱排序。因此,(IEEE 754)
double
是
不是 Cpp17LessThanComparable 违反了
std::min
的 Requires 条款和
std::max
.
Violation of any preconditions specified in a function’s Requires: element results in undefined behavior [...].
std::min(0.0, 1.0)
未定义,当程序评估此表达式时,任何事情都可能发生。它返回
0.0
.时期。 (我从来没有怀疑过。)
std::min
的规范明确地说“
T
应为Cpp17LessThanComparable”,这意味着
<
是
T
上的严格弱排序.因此,
T
在维基百科页面中扮演集合 S 的角色,当值
T
时,四个要点必须成立。被整体考虑。
std::min
只要不涉及 NaN, double 就可以了。
<
是 S 上的严格弱排序(证明留给读者)。这组值是 C++ 委员会在指定
std::min
时考虑的吗?如“请不要使用任何其他值,否则严格的弱排序将被破坏,
std::min
的行为未定义”?我敢打赌不是,但我更愿意在标准中阅读它而不是推测“某些值”的含义。
std::min
的声明(上)与
clamp
24.7.9:
template<class T>
constexpr const T& clamp(const T& v, const T& lo, const T& hi);
Requires: The value oflo
shall be no greater thanhi
. For the first form, type T shall be Cpp17LessThanComparable (Table 24). [...]
[Note : IfNaN
is avoided, T can be a floating-point type. — end note]
std::clamp
可以用于 double ,前提是不涉及 NaN”。我正在为
std::min
寻找相同类型的句子.
Required operations of any concept defined in this document need not be total functions; that is, some arguments to a required operation may result in the required semantics failing to be satisfied. [Example: The required
<
operator of the StrictTotallyOrdered concept (17.5.4) does not meet the semantic requirements of that concept when operating on NaNs. — end example ] This does not affect whether a type satisfies the concept.
最佳答案
免责声明:我不知道完整的 C++ 标准,我对关于浮点数的说法做了一些研究。我确实了解 IEEE 754-2008 浮点数和 C++。
是的,你是对的,这是 C++17 标准的未定义行为。
简读:
标准没有说std::min(0.0, 1.0);
是未定义的行为,它说 constexpr const double& min(const double& a, const double& b);
是未定义的行为。这意味着,它不是应用未定义的函数,而是未定义的函数声明本身。就像数学上的情况一样:正如您所指出的,在 IEEE 754 浮点数的整个范围内不可能使用最小函数。
但是未定义的行为并不一定意味着崩溃或编译错误。这只是意味着它不是由 C++ 标准定义的,并特别说明它可能“在翻译或程序执行期间以环境特征的文档化方式运行”
为什么不应该使用 std::min
double :
因为我意识到以下长篇阅读部分可能会很无聊,所以这里有一个比较中 NaN 风险的玩具示例(我什至不尝试排序算法......):
#include <iostream>
#include <cmath>
#include <algorithm>
int main(int, char**)
{
double one = 1.0, zero = 0.0, nan = std::nan("");
std::cout << "std::min(1.0, NaN) : " << std::min(one, nan) << std::endl;
std::cout << "std::min(NaN, 1.0) : " << std::min(nan, one) << std::endl;
std::cout << "std::min_element(1.0, 0.0, NaN) : " << std::min({one, zero, nan}) << std::endl;
std::cout << "std::min_element(NaN, 1.0, 0.0) : " << std::min({nan, one, zero}) << std::endl;
std::cout << "std::min(0.0, -0.0) : " << std::min(zero, -zero) << std::endl;
std::cout << "std::min(-0.0, 0.0) : " << std::min(-zero, zero) << std::endl;
}
$ g++ --std=c++17 ./test.cpp
$ ./a.out
std::min(1.0, NaN) : 1
std::min(NaN, 1.0) : nan
std::min_element(1.0, 0.0, NaN) : 0
std::min_element(NaN, 1.0, 0.0) : nan
std::min(0.0, -0.0) : 0
std::min(-0.0, 0.0) : -0
std::min
不对称 当涉及 NaN 时,甚至
-0.0
.并且 NaN 不会传播。短篇故事:这确实让我对之前的项目感到有些痛苦,在那里我不得不实现自己的
min
函数按照项目规范的要求在两侧正确传播 NaN。因为
std::min
double
未定义 !
undefined behavior behavior for which this document imposes no requirements
[Note 1 to entry: Undefined behavior may be expected when this document omits any explicit definition of behavior or when a program uses an erroneous construct or erroneous data. Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). Many erroneous program constructs do not engender undefined behavior; they are required to be diagnosed. Evaluation of a constant expression never exhibits behavior explicitly specified as undefined in Clause 4 through Clause 14 of this document (7.7). —end note]
std::min(0.0, 1.0);
或者它可能会引发警告甚至编译错误,如果您发现一个对浮点数非常小心的编译器!
I do not see anything in the Standard (which is quite big, 1719 pages, and hence this question and the language-lawyer tag) that mathematically leads to the conclusion that std::min is fine with doubles provided that NaNs are not involved.
template<class T> constexpr const T& min(const T& a, const T& b);
的定义
应用于您的新型 将具有定义的行为,并且行为与您对最小函数的期望完全相同。
<
在
double
,它在第 25.8 节浮点类型的数学函数中定义,它说这不是很有帮助:
The classification / comparison functions behave the same as the C macros with the corresponding names defined in the C standard library. Each function is overloaded for the three floating-point types. See also: ISO C 7.12.3, 7.12.4
The relational and equality operators support the usual mathematical relationships between numeric values. For any ordered pair of numeric values exactly one of the relationships — less, greater, and equal — is true. Relational operators may raise the ‘‘invalid’’ floating-point exception when argument values are NaNs. For a NaN and a numeric value, or for two NaNs, just the unordered relationship is true.241)
This annex specifies C language support for the IEC 60559 floating-point standard. The IEC 60559 floating-point standard is specifically Binary floating-point arithmetic for microprocessor systems, second edition (IEC 60559:1989), previously designated IEC 559:1989 and as IEEE Standard for Binary Floating-Point Arithmetic (ANSI/IEEE 754−1985). IEEE Standard for Radix-Independent Floating-Point Arithmetic (ANSI/IEEE854−1987) generalizes the binary standard to remove dependencies on radix and word length. IEC 60559 generally refers to the floating-point standard, as in IEC 60559 operation, IEC 60559 format, etc.
关于c++ - std::min(0.0, 1.0) 和 std::max(0.0, 1.0) 会产生未定义的行为吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55153210/
我在 Chrome 上做了一些测试,requestAnimationFrame 产生了 61 fps 而 setTimeOut( callback, 0 ) 产生了 233 fps。 如果一个人想要超
当我调试代码时,我发现 GCC 和 Clang 都为 0.0/0.0 产生 nan,这是我所期望的,但 GCC 产生的 nan 将符号位设置为 1,而Clang 将其设置为 0(如果我没记错的话,与
Closed. This question does not meet Stack Overflow guidelines。它当前不接受答案。 想改善这个问题吗?更新问题,以便将其作为on-topic
我在 R Studio 中有一个时间序列。现在我想计算这个系列的log()。我尝试了以下方法: i <- (x-y) ii <- log(i) 但是我得到以下信息:Warning message: I
我有兴趣了解 JavaScript 的内部结构.我试图阅读 SpiderMonkey 的来源和 Rhino但是绕过我的头是相当复杂的。 我问的原因是:为什么像 (![]+[])[+!![]+[]] 生
我们在 Delphi 中使用标准 TWebbrowser 组件,该组件在内部使用 mshtml.dll。另外,我们使用注册表来确保页面使用新的渲染引擎( Web-Browser-Control-Spe
我必须实现一个序列化/反序列化类,并且我正在使用 System.Xml.Serialization 。我有一些IList类型属性并希望在 IList 中序列化解码属于具有特定区域性信息的列表的所有十进
我有一个 Java 应用程序,它读取包含 SQL 查询的 JSON 文件,并使用 JDBC 在数据库上触发它们。 现在我有 5 万个这样的文件,我需要生成 5 万个独立线程来读取每个文件并将它们上传到
我正在尝试将 TensorFlow 入门页面上的示例线性回归程序调整为二次回归。为此,我只是添加了另一个变量并更改了函数。然而,这似乎会导致 NaN 值。这是我的代码: import numpy as
申请后KernelPCA到我的数据并将其传递给分类器 ( SVC ) 我收到以下错误: ValueError: Input contains NaN, infinity or a value too
这背后的想法是,如果我的数据库中存在登录名(正确的用户名+密码),我将重定向到一个页面,并且在进行此身份验证后,他们可以将消息存储在文本文件中。代码非常简单尽管我不确定为什么会收到 IllegalSt
我有一个返回 log10 值的函数。在将它们转换为正常数字时,出现溢出错误。 OverflowError: (34, 'Numerical result out of range') 我检查了日志值,
nosetests 抛出一个 ImportError,尽管我认为这是一个正确配置的 virtualenv。 ==============================================
我是这个网站的新手,所以如果我做错了什么,我提前道歉。当我尝试使用 kivy-garden 的 ScrollLabel 时,它给了我一个错误。基本上我正在尝试创建一个控制台日志,并且我需要能够在文本框
任何人都对 MDSJ 有任何经验?以下输入仅产生 NaN 结果,我不明白为什么。文档非常稀少。 import mdsj.Data; import mdsj.MDSJ; public class MDS
我有一个非常简单的 scala jcuda 程序,它添加了一个非常大的数组。一切都编译和运行得很好,直到我想从我的设备复制超过 4 个字节到主机。当我尝试复制超过 4 个字节时,我收到 CUDA_ER
我正在使用 Hero 组件在两个页面之间创建动画。Hero 组件用于包装一个 Image 小部件(没问题)和一个 Container 小部件(有问题)。 抛出以下溢出错误: ══╡ EXCEPTIO
我无法理解页面 https://developer.mozilla.org/en/JavaScript/Reference/Operators/Special/void 中的这一段: This ope
当在 Angular 中使用不立即触发事件的异步管道时(http 请求或任何有延迟的可观察对象),第一个值为 null为什么会这样?如何避免这种情况? 第一个变化: SimpleChange {
如果一个导入的库生成了一个会 panic 的 goroutine 怎么办?在这种情况下,开发人员无法阻止程序退出。 就像在这段代码中一样,使用延迟恢复调用一个错误的库没有帮助,因为该库正在生成一个 p
我是一名优秀的程序员,十分优秀!