【问题标题】:Do data type sizes differ from computer to computer?数据类型大小是否因计算机而异?
【发布时间】:2012-07-10 23:01:15
【问题描述】:

我正在使用带有 MinGW/GCC 4.7.1 的 Windows 7。我试图在 C 中执行double ans = pow(2,1000)。我发现ans 无法正确打印,无论我在改变数据类型方面做了什么尝试。

但是,我读到(实际上,在this 页面的最底部),如果在 Linux 计算机上运行相同的东西,它会正确打印。

我知道我的 MinGW 文件夹中的 limits.h 文件中对 char、int 和 long long 施加的限制,但是 double 和 float 的限制在哪里?这些是否/可以从一个操作系统或架构到下一个有所不同?

编辑:

这是代码,它会打印出截断的零填充答案:

#include <stdio.h>
#include <math.h>

int main(void)
{
   double ans = pow(2,1000);

   printf("%.0f", ans);

   return 0;
}

【问题讨论】:

  • 您的号码可能在double 中准确表示,只是打印程序很糟糕。
  • 这可能值得另一个问题,但也许可以在这里轻松回答:我将如何解决失败的打印例程? @tomasz
  • 请显示一些实际代码。您的问题可能与字体大小有关,也可能无关。例如,如果您在 printf() 调用中使用了错误的格式说明符,那么您将得到错误的结果。
  • 你的源文件顶部有#include &lt;math.h&gt;吗?如果不是,编译器可能会假设 pow 返回一个 int 结果并接受两个 int 参数(您还应该得到一个编译器警告)。
  • 15-16 个正确显示的数字几乎是您所期望的;这通常是 double 给你的精度类型。您没有问题,您只是在不同的printf 实现如何处理 insignificant 数字方面遇到了细微的变化。 (如果你一开始就告诉我们,通过向我们展示你的程序产生的确切输出,你可以为我们所有人节省一些时间和精力。)

标签: c windows gcc mingw


【解决方案1】:

您提出的问题与您看到的问题无关。

很可能您使用的所有系统都使用相同的 double 表示形式,即 64 位 IEEE 双精度。

pow(2, 1000) 的值(或者,更等价和更清楚地,pow(2.0, 1000.0),是 2.01000。由于它是 2 的幂,因此可以精确表示 - 但相对大数字的精度非常粗糙。

double 值通常精确到大约 15 个十进制数字。

显然,在 Linux 系统上使用的 printf 的 glibc 实现尝试打印值的完整十进制表示,而其他 printf 实现替换了 15 位左右之后的部分或全部数字 位带零。后者可能更容易实现,但两种方法都有效。

在几个不同的系统上运行你的程序,我得到以下结果(为了便于阅读,折叠了行):

10715086071862673000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000

10715086071862673209484250490600018105614050000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000

10715086071862673209484250490600018105614048117055336074437503883703510511249361
22493198378815695858127594672917553146825187145285692314043598457757469857480393
45677748242309854210746050623711418779541821530464749835819412673987675591655439
46077062914571196477686542167660429831652624386837205668069376

最后一个恰好正好等于21000

您要打印的数字很不寻常,因为它非常大并且 可以精确地表示——glibc 付出了一些额外的努力来精确地打印它。但更一般地说,浮点值往往不精确,很少需要担心前几位之外的任何数字。

例如,pow(2.0, 1000.0) + 1.0不能精确表示,如果你尝试计算它,你可能会得到与pow(2.0, 1000.0)完全相同的结果。

【讨论】:

  • “你可能会得到完全相同的结果”——我当然希望如此,因为 IEEE 算法要求 :-)
  • +1 这个答案比接受的答案要丰富得多。
  • 而就其价值而言,我发现 printf(甚至是 shell 命令)是计算 2 的巨大幂的精确值的好工具,例如printf %f\\n 0x1p1000.
  • @R..:取决于系统。在使用 newlib 而不是 glibc 的 Cygwin 上,我在小数点前得到 259 个尾随零。
  • 我想我不清楚。我的意思是举一个实际的例子,说明为什么有一个打印正确的确切值的实现很好,而不是说我希望这适用于所有实现。
【解决方案2】:

floatdouble 的大小可以因实现而异。

保证double 永远不会小于float,并且long double 永远不会小于double - 类似于long longlongint、@987654330 的保证@。

【讨论】:

    【解决方案3】:

    是的,float 和 double 等类型的实现可以因平台而异。

    不过,最常见的现代平台使用 IEEE 754,这是一种浮点类型标准。因此,除非您在不寻常的平台上,否则其中一种类型的二进制表示不太可能有所不同。

    您提到的另一个线程似乎强调了打印程序准确性的潜在差异。这并不意味着表示不同(或大小不同)。

    【讨论】:

    • 那么最后一行,您是说ans 在我执行时确实包含2^1000 的正确值吗?只是打印不正确?据我所知,double 应该足够大以包含数字,但它不会正确打印出来。
    • 确实,微软的printf 实现是出了名的糟糕。 C 标准不需要打印超过DECIMAL_DIG 有效数字,即使要打印一个确切的值,但高质量的实现会在可能的情况下打印出确切的值,因为它(可能)更有用并且只是正确的事情去做。
    猜你喜欢
    • 1970-01-01
    • 2010-11-09
    • 2018-09-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-19
    • 2016-04-17
    • 1970-01-01
    • 2011-03-30
    相关资源
    最近更新 更多