【问题标题】:double & long double : are they same on my computer?double 和 long double :它们在我的计算机上是否相同?
【发布时间】:2017-03-23 05:26:59
【问题描述】:

这是 ANSI C 代码:

   float        x = 3.14159264351134890172;
   double       y = 3.14159264351134890172;
   long double  z = 3.14159264351134890172;

   printf("%f\n",x);
   printf("%f\n",y);
   printf("%f\n",z);
   printf("%.20f\n",x);
   printf("%.20f\n",y);
   printf("%.20f\n",z);

这段代码的输出是:

3.141593
3.141593
3.141593
3.14159274101257324219
3.14159264351134881466
3.14159264351134881466

查看最后一个输出行。我读过long double 的精度为小数点后 19 位。但在这里我得到小数点后 15 位的精度。所以在我的电脑中doublelong double 没有区别。我在 CentOS 上使用 linux 内核 2.6.32-358.el6.x86_64。 我的 C 编译器是gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC)

为什么会这样?如果它取决于计算机硬件/架构,我如何购买我的 linux 机器,其中 long double 比 double 更精确? 它是否也取决于我的 C 编译器?如果是,我该如何选择我的 C 编译器?

对于float,取值范围是1.2E-38 to 3.4E+38。我不明白这个。从上面的例子我们看到我们不能在float 变量中正确地存储一个小数,例如 3.1415926。我的机器将仅在 float 变量中正确存储 3.141592。所以我丢失了最后的第 7 位数字,这里是 6。那为什么我们说float range is 1.2*10^-38 呢?

是不是我们不能存储多达 10^-38 但我们可以为 C 中的 float 变量存储多达 10^-6 ?

【问题讨论】:

  • 这在 x64 上是预期的。为什么你觉得双倍不够。尽管您根本不了解浮点的工作原理,但从您的 cmets 来看。在继续之前,您必须正确处理。您需要了解值存储为尾数和指数。
  • 请注意,您应该将z 格式化为%Lf(尽管如果使用sizeof(double) == sizeof(long double),您将侥幸成功)。
  • 要检查 double 和 long double 是否具有相同的精度,请检查 sizeof(double) 和 sizeof(long double)。如果大小相等,则两者都表示相同的精度。这类似于 int 和 long int 都占用 4 个字节的情况,而 long long int 是 8 个字节并且范围更大。
  • @prashanthns:大小相等并不意味着精度或范围相等。实现可以选择使用更广泛的双精度格式,例如更好地对齐它们,但对它们执行比long double 更快的操作。只有一种方法:比较提供的宏。
  • @KamiKaze:通常情况下 - 计算不同的架构。大多数 C 平台仍然使用 16 位 int 或 32 位 CPU。 intlong 的 Wrt 大小,有一个众所周知的反例:POSIX64(例如 Linux),即 I32LP64。

标签: c gcc floating-point numerical-methods


【解决方案1】:

首先,您应该使用%Lf 打印long double 值。

其次,如果您希望您的long double 变量包含一个不能表示为double 的值,则不应使用double 常量对其进行初始化。 3.14159264351134890172 具有 double 类型,并且如果您的编译器将 FLT_EVAL_METHOD 定义为 0 或 1,则使用 long double z = 3.14159264351134890172;z 设置为 double 值,即使 long double 类型可以更接近地表示该常量平台。相反,该行应为:

long double  z = 3.14159264351134890172L;

在“对于浮点值范围是 1.2E-38 到 3.4E+38 ...”之后对您的问题的简短回答是,您机器上的浮点格式以 2 为基数,并且可表示的值不一样在这些格式中,就好像它们以 10 为基数表示一样。您平台上的类型 float 正好提供 24 个二进制位的精度。 double 类型提供 53,您应该能够期望 long double 提供 64。对于 StackOverflow 格式来说,答案太长了,但您可以从阅读 http://floating-point-gui.de 开始。

【讨论】:

    【解决方案2】:

    存在有助于回答 OP 调查的值,并且可以直接打印以辨别 doublelong double 的相似之处。它们可能完全相同。

    要查找各种浮点类型的精度,请打印***_MANT_DIG

    浮点有效数FLT_RADIX中的基数-p
    C11§5.2.4.2.2 11

    #include <float.h>
    printf("FLT_RADIX         %d\n", FLT_RADIX);  // Almost always 2
    printf("DBL_MANT_DIG      %d\n", DBL_MANT_DIG);
    printf("LDBL_MANT_DIG     %d\n", LDBL_MANT_DIG);
    

    要查找与 FP 精确值匹配的小数位数,请使用***_DIG(如预期的那样往返“text-FP-text”)

    printf("DBL_DIG           %d\n", DBL_DIG);
    printf("LDBL_DIG          %d\n", LDBL_DIG);
    

    要查找可能影响 FP 精确值的小数位数,请使用 ***_DECIMAL_DIG(如预期的那样往返“FP-text-FP”)

    printf("DBL_DECIMAL_DIG   %d\n", DBL_DECIMAL_DIG);
    printf("LDBL_DECIMAL_DIG  %d\n", LDBL_DECIMAL_DIG);
    
    double d = 3;
    long double ld = 3;
    printf("(double) 1/3      %.*e %.*e\n", DBL_DIG - 1, 1 / d,
        DBL_DECIMAL_DIG - 1, 1 / d);
    printf("(long double) 1/3 %.*Le %.*Le\n", LDBL_DIG - 1, 1 / ld,
        LDBL_DECIMAL_DIG - 1, 1 / ld);
    

    示例输出

    FLT_RADIX         2
    DBL_MANT_DIG      53
    LDBL_MANT_DIG     64
    DBL_DIG           15
    LDBL_DIG          18
    DBL_DECIMAL_DIG   17
    LDBL_DECIMAL_DIG  21
    (double) 1/3      3.33333333333333e-01 3.3333333333333331e-01
    (long double) 1/3 3.33333333333333333e-01 3.33333333333333333342e-01
    

    注意事项:
    对于范围问题,请打印***_MAX, ***_MIN
    请务必在long double 的打印说明符中使用L

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-30
      • 2011-05-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多