M_PI 不精确
M_PI Imprecision
我正在尝试 printf M_PI 但我认为我没有使用正确的格式说明符。输出应该是:3.14159265358979323846 但我得到 3.14159265358979300000.
int main(void)
{
printf("%.20f\n", M_PI);
return 0;
}
我试过使用 %Lf、%Lg、%e、%g,但是 none 它们都有效,所以我不确定这个错误是来自格式说明符还是它有什么问题处理我正在使用的硬件。
双精度浮点数的精度有限。它少于 20 位数字,因此在某些时候,无论您要求多少位精度,您都会得到无意义的噪音或全为零。
假设您的编译器将 double
浮点类型映射到 IEEE 754 双精度,那么 double
有 53 位二进制精度。浮点数以 2 为基数表示的事实意味着它不是可以表示为 double
并且具有短小数表示的同一组数字。特别是,最接近 π 的 double
的精确值具有紧凑的表示形式,精度仅为 53 位二进制数字,但十进制表示为 3.141592653589793115997963468544185161590576171875。这不是 π 到 50 位十进制数字的近似值!它是 π 的近似值,精度为 53 位二进制数,这意味着大约前 17 位十进制数字是正确的,而其他数字只是因为 M_PI
表示的基数 2 与我们现在正在讨论其价值的基数 10。
这意味着您可以期望 quality printf
实现打印 3.14159265358979311600
。请注意,这并不完全是您在问题中所说的预期字符串,而是 M_PI
实际值的 .
后 20 位的四舍五入十进制表示。无论如何,您可以期望 quality printf
实现打印显示 double
的确切值所需的所有十进制数字,尽管在最坏的情况下there can be 750 or so.
C 标准 does not force 所有 printf
实现都有这个 属性:
For e, E, f, F, g, and G conversions, if the number of significant
decimal digits is at most DECIMAL_DIG, then the result should be
correctly rounded. If the number of significant decimal digits is
more than DECIMAL_DIG but the source value is exactly representable
with DECIMAL_DIG digits, then the result should be an exact
representation with trailing zeros. Otherwise, the source value is
bounded by two adjacent decimal strings L < U, both having DECIMAL_DIG
significant digits; the value of the resultant decimal string D should
satisfy L <= D <= U, with the extra stipulation that the error should
have a correct sign for the current rounding direction.
更容易实现最多打印 double
精确值的前 17 位十进制数字,然后清零,C 标准允许这样的实现。这可能是您的编译器发生的情况。
(采用这种捷径的编译器通常也不会实现“当前舍入方向”约束。)
double
,在大多数遵循 IEEE-754 的架构中实现的只有 64 位,一个用于符号,11 位用于指数,剩下 52 位用于尾数(53,因为第一个有效位是总是 1
,并且由于这个原因不包含在格式中,所以你有 53 位有效数字以 2 为基数),这意味着大致((52+1)/ln(10)*ln(2) ~= 15.95
以 10 为基数的有效数字)[= 的近似值14=] 到那个精度应该类似于.
3.141592653589793
这是你得到的 PI 精确数字的近似值。您得到的值与 PI 的实际值之间存在大约 2 * 10^(-16)
的差异,可能是由于算法 printf
用于获取该数字的十进制版本。
但是您不能期望从 IEEE-754 实现中获得更准确的结果,因此您得到的答案会受到您要求的位数的影响。
顺便问一下,您是否尝试过使用 "%.200f"
格式化字符串?至少,在 gcc 中,你会得到很多非零数字,以完成你所要求的完整精度(在基数 2 中,假设从最后一位开始你的数字都是零)。在 MSVC 中,我知道它会在某个时刻用零填充(使用某种算法),这就是你正在发生的事情。但始终要注意,在 64 位浮点数的 IEEE-754 实现中,结果最多有 16 significative/exact 位数字(好吧,比 16 少一点,因为结果接近它, 但低于。)
我知道这已经被回答了,但是,假设你使用的是 C++,你可以使用
#define _USE_MATH_DEFINES
#include <cmath>
#include <iostream>
using namespace std;
现在在 class 或 int main();
double g = M_PI;
cout << setprecision(50) << g << endl;
输出:
3.141592653589793115997963468544185161590576171875
我正在尝试 printf M_PI 但我认为我没有使用正确的格式说明符。输出应该是:3.14159265358979323846 但我得到 3.14159265358979300000.
int main(void)
{
printf("%.20f\n", M_PI);
return 0;
}
我试过使用 %Lf、%Lg、%e、%g,但是 none 它们都有效,所以我不确定这个错误是来自格式说明符还是它有什么问题处理我正在使用的硬件。
双精度浮点数的精度有限。它少于 20 位数字,因此在某些时候,无论您要求多少位精度,您都会得到无意义的噪音或全为零。
假设您的编译器将 double
浮点类型映射到 IEEE 754 双精度,那么 double
有 53 位二进制精度。浮点数以 2 为基数表示的事实意味着它不是可以表示为 double
并且具有短小数表示的同一组数字。特别是,最接近 π 的 double
的精确值具有紧凑的表示形式,精度仅为 53 位二进制数字,但十进制表示为 3.141592653589793115997963468544185161590576171875。这不是 π 到 50 位十进制数字的近似值!它是 π 的近似值,精度为 53 位二进制数,这意味着大约前 17 位十进制数字是正确的,而其他数字只是因为 M_PI
表示的基数 2 与我们现在正在讨论其价值的基数 10。
这意味着您可以期望 quality printf
实现打印 3.14159265358979311600
。请注意,这并不完全是您在问题中所说的预期字符串,而是 M_PI
实际值的 .
后 20 位的四舍五入十进制表示。无论如何,您可以期望 quality printf
实现打印显示 double
的确切值所需的所有十进制数字,尽管在最坏的情况下there can be 750 or so.
C 标准 does not force 所有 printf
实现都有这个 属性:
For e, E, f, F, g, and G conversions, if the number of significant decimal digits is at most DECIMAL_DIG, then the result should be correctly rounded. If the number of significant decimal digits is more than DECIMAL_DIG but the source value is exactly representable with DECIMAL_DIG digits, then the result should be an exact representation with trailing zeros. Otherwise, the source value is bounded by two adjacent decimal strings L < U, both having DECIMAL_DIG significant digits; the value of the resultant decimal string D should satisfy L <= D <= U, with the extra stipulation that the error should have a correct sign for the current rounding direction.
更容易实现最多打印 double
精确值的前 17 位十进制数字,然后清零,C 标准允许这样的实现。这可能是您的编译器发生的情况。
(采用这种捷径的编译器通常也不会实现“当前舍入方向”约束。)
double
,在大多数遵循 IEEE-754 的架构中实现的只有 64 位,一个用于符号,11 位用于指数,剩下 52 位用于尾数(53,因为第一个有效位是总是 1
,并且由于这个原因不包含在格式中,所以你有 53 位有效数字以 2 为基数),这意味着大致((52+1)/ln(10)*ln(2) ~= 15.95
以 10 为基数的有效数字)[= 的近似值14=] 到那个精度应该类似于.
3.141592653589793
这是你得到的 PI 精确数字的近似值。您得到的值与 PI 的实际值之间存在大约 2 * 10^(-16)
的差异,可能是由于算法 printf
用于获取该数字的十进制版本。
但是您不能期望从 IEEE-754 实现中获得更准确的结果,因此您得到的答案会受到您要求的位数的影响。
顺便问一下,您是否尝试过使用 "%.200f"
格式化字符串?至少,在 gcc 中,你会得到很多非零数字,以完成你所要求的完整精度(在基数 2 中,假设从最后一位开始你的数字都是零)。在 MSVC 中,我知道它会在某个时刻用零填充(使用某种算法),这就是你正在发生的事情。但始终要注意,在 64 位浮点数的 IEEE-754 实现中,结果最多有 16 significative/exact 位数字(好吧,比 16 少一点,因为结果接近它, 但低于。)
我知道这已经被回答了,但是,假设你使用的是 C++,你可以使用
#define _USE_MATH_DEFINES
#include <cmath>
#include <iostream>
using namespace std;
现在在 class 或 int main();
double g = M_PI;
cout << setprecision(50) << g << endl;
输出:
3.141592653589793115997963468544185161590576171875