size
上面的代码旨在获取整数y的最后一位,奇怪的是foo是shapes
而bar是int y = 89;
int foo = (y / 10.0 - y / 10) * 10;
int bar = (89 / 10.0 - 89 / 10) * 10;
cout << foo << ' ' << bar << '\n';
,为什么会这样?两种版本的表达式有什么区别?
答案 0 :(得分:5)
C ++标准允许实现比标称格式要求的精度更高的精度来评估浮点表达式。例如,可以将float
表达式视为double
或更高,而将double
表达式视为long double
。这种额外的精度可能会导致评估上的差异,尤其是在使用不连续函数(例如转换为int
)的情况下。
例如,给定y = 89
,y / 10.0 - y / 10
的实数运算将为.9,而double
(IEEE-754 binary64)算术则为0.9000000000000003552713678800500929355621337890625和{{{ 1}}(Intel的80位格式)算法,然后乘以10并转换为long double
会分别产生9或8。
在禁用优化的情况下,编译器可能会在运行时使用int
评估表达式,而在编译过程中使用y
评估表达式,并且它们可能使用不同的精度。通过优化,编译器很可能会在第一个表达式中认识到89
实际上是常量y
,并在编译过程中对两个表达式进行求值,并对两者使用相同的方法。
C ++标准要求将强制类型转换和赋值操作转换为名义类型,因此一项测试是否会发生这种情况是插入强制类型转换:
89
如果这导致int foo = (double) ((double) (y / 10.0) - y / 10) * 10;
int bar = (double) ((double) (89 / 10.0) - 89 / 10) * 10;
和foo
相同,则支持该假设。您的编译器可能具有控制如何计算浮点表达式的开关。
另一项测试是包括bar
并打印<cfloat>
的值。如果为0,则该实现要求以其名义类型评估浮点运算,并且不应发生此行为。如果它是1或2,则该实现声明分别使用FLT_EVAL_METHOD
或double
来评估long double
表达式,并且不应再次发生此行为,因为两个表达式将被评估为相同道路。如果为-1,则表示实现未声明这些声明,因此可能会发生该行为。
要获取非负整数的最后一位,请使用double
。