提问人:p d 提问时间:10/9/2023 最后编辑:Paul Floydp d 更新时间:10/9/2023 访问量:130
C++ 中算术运算和强制转换的机器值
Machine values for arithmetic operations and castings in C++
问:
我是 C++ 编程的新手。我想知道作为 C++ 中以下简单操作的结果,可以获得哪些可能的机器值:
int a = 3;
double inv_a;
inv_a = (double) 1 / (double) a;
std::cout << "a*(1/a) = " << std::setprecision(30) << (double) a * inv_a << std::endl;
例如,我想知道
(double) a * inv_a
对于任何可能的 int 值,始终大于或等于 1.000...0 作为双精度值或不双精度值。是否有可能获得严格小于 1 但非常接近 0.999 的值......?当我将结果转换为 int 时,我担心这种情况。先谢谢你。
我的实验总是给我精确的 1。
答:
例如,我想知道 的输出是否总是大于或等于 1.000...0 作为双精度
(double) a * inv_a
这种关系不成立,因为使用 IEEE-754 binary64(“双精度”)算术产生 0.999999999999999988897769753748434595763683319091796875。1./49*49
当倒数进入低于正常范围时,结果可能大于 1。例如,with = 21023+2971,则为 1+2−52。这是因为次正态结果会降低精度,从而导致更大的误差。在正常范围内,不会发生这种情况。a
1/a*a
当所有涉及的值(包括倒数)都在正常范围内时,反比关系成立; 总是小于或等于 1,有时甚至更小。a * inv_a
在此答案中,代码字体中的表达式表示具有浮点数的计算。非代码字体的表达式表示普通的实数算术。
这里有一个证明,只要我们保持在正常范围内,并使用以 1 为底的浮点格式,四舍五入到最接近,就不可能有大于 1 的结果。考虑一些 x。设 p 为 2 的幂,使得 xp 在 [1, 2] 中。只要我们在正常范围内,= ,其中 = ,由于浮点表示的性质。因此,只有当 [1, 2] 中有这样的 x 时,才存在一个 x,使得 1< 才有这样的 x。1/x*x
1/(xp)*xp
xp
x*p
1/x*x
由于使用四舍五入到最接近,并且 1/2 < 1/x ≤ 1,对于满足 −1/2 u ≤ ε ≤ +1/2 u 的某些ε,= 1/x + ε,其中 u 是 [1/2, 1] 中浮点数的最低精度单位。则 •x = (1/x + ε)x = 1 + ε x。由于 x < 2,−1/2 u ≤ ε ≤ +1/2u 意味着 −u < εx < +u。因此 •x 在 1 的 u 范围内。请注意,u 是 [1/2, 1] 中数字的 ULP,是 [1, 2] 中数字的 ULP 的一半。因此,•x 比 [1, 2] 中下一个较大的数字更接近 1。因此,在计算时,四舍五入到最接近不会产生大于 1 的结果。1/x
1/x
1/x
1/x
1/x*x
For completeness, note that if is zero, a NaN, or an infinity, a NaN will be produced by , so that result will not be less than, equal to, or greater than 1. And, if is subnormal, can produce infinity, so will be an infinity and will compare as greater than 1.a
1/a*a
a
1/a
1/a*a
Note
1 I expect this holds for other bases but do not have a proof at hand.
评论
x * (1/x)
x = 1.124225499393696e308
x * (1/x)
1.0000000000000002
x
评论
C/C++
C
C++
std::cout