x 的平方的平方根等于 x
square root of square of x equals x
给定一个双精度浮点(非负)数x
,它的平方根是否总是等于它本身?
换句话说,如果执行以下操作是否会导致精度损失:
x = <non-negative double>
y = x^2
z = sqrt(y)
这样:
x == z
我对平方变为无穷大或零的情况不感兴趣,只对符合双精度的数字感兴趣。
对一个数求平方,生成的值是原始值位数的两倍。因此,如果 x 太大,则 x^2
中的某些位会丢失,并且 x
无法从 y
中完全恢复 [编辑:仍然可以通过适当的舍入从 y 中获取 x]。在 IEEE-754 双精度的情况下,如果 x
的有效数部分超过 26 位,则 y
的结果将被截断。这是最简单的情况。
如果 x
的有效数位很少,但指数很大或很小,那么 x^2
对于双精度来说可能太大,将变成 inf
或非正规数,在这种情况下无法恢复 x
.
如果 x
不是太大或太小那么 sqrt(y)
将等于 x
因为 IEEE-754 标准要求 +
, -
, *
, /
和 sqrt
适当舍入.
Examples:
#include <iostream>
#include <ios>
#include <iomanip>
#include <cmath>
using std::fixed;
using std::hexfloat;
using std::cout;
int main() {
double x = 1.25e155;
double y = x*x;
cout << hexfloat << "x = " << x << ", y = " << y << ", sqrt(y) = " << sqrt(y) << '\n';
x = 1.25e-155;
y = x*x;
cout << hexfloat << "x = " << x << ", y = " << y << ", sqrt(y) = " << sqrt(y) << '\n';
return 0;
}
#include <stdio.h>
#include <math.h>
int main(void) {
double x = 1.0000000000000001E-160;
double square = x*x;
double root = sqrt(square);
if (root != x) {
printf("%.20g\n", x);
printf("%.20g\n", root);
}
}
产出
1.0000000000000001466e-160
9.9999443357584897793e-161
这里发生的事情是 x
足够大以至于它的平方不为零,但又足够小以至于它的平方只能表示为非规范化数字,这会降低可用精度。
我的印象是@MarkDickinson 对@LưuVĩnhPhúc 的回答的评论在很大程度上是正确的。如果 x
和 x*x
都是正归一化数字,那么即使使用快速蛮力(在几个小范围内),我也无法找到 x != sqrt(x*x)
的示例,尽管这应该不被视为证据。
给定一个双精度浮点(非负)数x
,它的平方根是否总是等于它本身?
换句话说,如果执行以下操作是否会导致精度损失:
x = <non-negative double>
y = x^2
z = sqrt(y)
这样:
x == z
我对平方变为无穷大或零的情况不感兴趣,只对符合双精度的数字感兴趣。
对一个数求平方,生成的值是原始值位数的两倍。因此,如果 x 太大,则 x^2
中的某些位会丢失,并且 x
无法从 y
中完全恢复 [编辑:仍然可以通过适当的舍入从 y 中获取 x]。在 IEEE-754 双精度的情况下,如果 x
的有效数部分超过 26 位,则 y
的结果将被截断。这是最简单的情况。
如果 x
的有效数位很少,但指数很大或很小,那么 x^2
对于双精度来说可能太大,将变成 inf
或非正规数,在这种情况下无法恢复 x
.
如果 x
不是太大或太小那么 sqrt(y)
将等于 x
因为 IEEE-754 标准要求 +
, -
, *
, /
和 sqrt
适当舍入.
Examples:
#include <iostream>
#include <ios>
#include <iomanip>
#include <cmath>
using std::fixed;
using std::hexfloat;
using std::cout;
int main() {
double x = 1.25e155;
double y = x*x;
cout << hexfloat << "x = " << x << ", y = " << y << ", sqrt(y) = " << sqrt(y) << '\n';
x = 1.25e-155;
y = x*x;
cout << hexfloat << "x = " << x << ", y = " << y << ", sqrt(y) = " << sqrt(y) << '\n';
return 0;
}
#include <stdio.h>
#include <math.h>
int main(void) {
double x = 1.0000000000000001E-160;
double square = x*x;
double root = sqrt(square);
if (root != x) {
printf("%.20g\n", x);
printf("%.20g\n", root);
}
}
产出
1.0000000000000001466e-160
9.9999443357584897793e-161
这里发生的事情是 x
足够大以至于它的平方不为零,但又足够小以至于它的平方只能表示为非规范化数字,这会降低可用精度。
我的印象是@MarkDickinson 对@LưuVĩnhPhúc 的回答的评论在很大程度上是正确的。如果 x
和 x*x
都是正归一化数字,那么即使使用快速蛮力(在几个小范围内),我也无法找到 x != sqrt(x*x)
的示例,尽管这应该不被视为证据。