【问题标题】:Largest integer that can be stored in long double可以存储在 long double 中的最大整数
【发布时间】:2021-01-15 16:41:43
【问题描述】:

编辑:在 cmets 中进行了一些讨论后,结果表明,由于对如何在 C 中实现浮点数有一定的了解,我问了一些与我想问的不同的问题。
我想使用(使用)大于unsigned long long 的整数(对我来说是 8 个字节),可能不会重复到数组或 bigint 库。由于我的long double 是 16 个字节,我认为只需切换类型就可以了。结果表明,即使可以表示更大的整数,您也无法在不损失精度的情况下使用这些更大的long double 整数进行操作。所以不可能实现我想做的事情。实际上,正如 cmets 中所述,这对我来说是不可能的。但总的来说,是否可能取决于您的long double 的浮点特性。

// end of EDIT

我试图了解我可以存储在 long double 中的最大整数是多少。
我知道这取决于程序内置的环境,但我不知道具体如何。我有一个 sizeof(long double) == 16 值得一看。

现在在this answer 他们说 64 位双精度的最大值应该是 2^53,大约是 9 x 10^15,正好是 9007199254740992
当我运行以下程序时,它就可以工作了:

#include <stdio.h>

int main() {

    long double d = 9007199254740992.0L, i;
    
    printf("%Lf\n", d);
    
    for(i = -3.0; i < 4.0; i++) {
        
        printf("%.Lf) %.1Lf\n", i, d+i);
    }
    
    return 0;
}

即使11119007199254740992.0L 与开头添加四个1s 的数字相同。但是,当我再添加一个 1 时,第一个 printf 会按预期工作,而其他所有显示的第一个打印件数量相同。
所以我试图用这个程序来获得我long double的最大价值

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

int main() {

    long double d = 11119007199254740992.0L, i;
    
    for(i = 0.0L; d+i == d+i-1.0; i++) {
        
        if( !fmodl(i, 10000.0L) ) printf("%Lf\n", i);
    }
    
    printf("%.Lf\n", i);
    
    return 0;
}

但它会打印0
编辑:我刚刚意识到我需要for 中的条件!=

总是在相同的答案中,他们说双精度的最大可能值是DBL_MAX 或大约 1.8 x 10^308。
我不知道这是什么意思,但是如果我运行

printf("%e\n", LDBL_MAX);

我每次都会得到一个不同的值,始终在 6.9 x 10^(-310) 左右。
编辑:我应该使用 %Le,得到一个大约 1.19 x 10^4932 的值)
我从here 取了LDBL_MAX

我也试过这个

printf("%d\n", LDBL_MAX_10_EXP);

这给出了4932 的值(我也在this C++ 问题中找到了)。

由于long double 有 16 个字节,即使它们都是类型的整数部分,我们也可以将数字存储到 2^128,即大约 3.4 x 10^ 38。所以我不明白 308、-310 和 4932 应该是什么意思。

有人能告诉我如何找出可以存储为long double 的最大整数吗?

【问题讨论】:

  • 这取决于整数是否有任何2因子,这些因子将被指数占用。简单的答案是指定有效位(加 1)的数量,用于无损存储整数值。指数表示可以近似表示的所有值的范围。
  • printf("%e\n", LDBL_MAX); 中你的意思是使用%Le
  • 有几种方法可以解释这个问题,所有这些方法都会产生不同的结果。例如,long double 可以存储的 所有 个最大值都是整数,特别是,LDBL_MAX 是一个整数。但是在大多数实现中没有内置的整数整数数据类型可以表示该值。
  • 4932 不是直接与浮点类型的 16 字节相关,而是 10^4932 来自指数部分的位数。
  • “所以不可能实现我想做的事情。” --> 不正确。这取决于long double 的浮点特性。使用LDBL_MANT_DIG == 64,代码可以影响int65_t之类的操作。

标签: c integer max long-double


【解决方案1】:

由于您在 cmets 中表示您想使用 long double 代替 long long 以获得更大的范围,我假设您还需要单位精度。因此,您要求浮点表示 (FLT_RADIX) 的基数中可用尾数位数 (LDBL_MANT_DIG) 表示的最大数。在FLT_RADIX == 2非常可能事件中,您可以像这样计算该值:

#include <float.h>
#include <math.h>

long double get_max_integer_equivalent() {
    long double max_bit = ldexpl(1, LDBL_MANT_DIG - 1);
    return max_bit + (max_bit - 1);
}

ldexp 系列函数以 2 的幂对浮点值进行缩放,类似于移位运算符(&lt;&lt;&gt;&gt;)对整数所做的操作,因此上述类似于

// not reliable for the purpose!
unsigned long long max_bit = 1ULL << (DBL_MANT_DIG - 1);
return max_bit + (max_bit - 1);

由于您假设您的 long double 提供的尾数位比您的 long long 的值位多,但是,您必须假设位移位会溢出。

当然,您的long double 可以表示更大的值,它们都是整数。但是它们没有单位精度,因此当整数值较大时,long double 的行为将偏离整数的预期行为。例如,如果long double 变量d 包含一个更大的值,那么d + 1 == dd - 1 == d 中的至少一个可能会评估为真。

【讨论】:

  • 我运行你的函数,它返回一个长数字,即 2^64 - 1。我会花时间了解函数的工作原理,但无论如何我得到了我不能使用 @987654339 @ 操作大于我可以使用unsigned long long 操作的整数。谢谢你给我一段代码来证明这个事实。
  • "但它们没有单位精度" --> 然而get_max_integer_equivalent() +1.0 是可表示的。
  • 是的,@chux-ReinstateMonica。它是最小的long double,没有单位精度。也就是说,最低有效位的位值大于 1。这个答案的最后一句话适用于它。如果结果是这个数字加 1 会产生一个不同的数字,那么结果将不是下一个更大的整数。
  • 在我看来,有问题的long double 可以编码所有整数INT65_MIN...INT65_MAX+1 或最多UINT64_MAX+1
  • @chux-ReinstateMonica,这是一个问题,通常情况下,您想如何使用数据。如果您只希望可以依赖的值在算术上与整数相同,正如我明确认为是 OP 的情况,那么 get_max_integer_equivalent() +1.0 不是这样的数字。这实际上正是我表达功能的原因,而不是使用更简单但不可靠的return ldexpl(1, LDBL_MANT_DIG) - 1;
【解决方案2】:

您可以使用limits.h在您的机器上打印最大值,该值为ULLONG_MAX

https://www.geeksforgeeks.org/climits-limits-h-cc/ 中是一个 C++ 示例。

使用 printf() 打印 unsigned long long 的格式说明符是 %llu 用于打印 long double 它是 %Lf

printf("unsigned long long int: %llu ",(unsigned long long) ULLONG_MAX);

printf("long double: %Lf ",(long double) LDBL_MAX);

https://www.tutorialspoint.com/format-specifiers-in-c

也在Printing unsigned long long int Value Type Returns Strange Results

【讨论】:

  • 如果 unsigned long long 是 128 位,ULLONG_MAX 根本无法适应 128 位浮点值而不丢失数据。
  • 打印ULLONG_MAX 总是给我一个大约 6.9 x 10^(-310) 的不同值。比如打印LDBL_MAX。但是,这两个值彼此不同。
  • ULLONG_MAX 不能是 6.9•10^-310 或接近它,因为ULLONG_MAX 是一个整数,而 6.9•10^-310 和它附近的值不是(零除外)。如果您在打印ULLONG_MAX 时得到的值似乎接近 6.9•10^−310,那么您的打印结果不正确。
【解决方案3】:

假设您的意思是“在不丢失信息的情况下存储”,LDBL_MANT_DIG gives the number of bits used for the floating-point mantissa,那么这就是在不丢失信息的情况下可以存储多少位整数值。*

您需要 128 位整数来轻松确定可以保存在 128 位浮点数中的最大整数值,但这至少会发出十六进制值(假设 unsigned long long 是 64 位 - 您可以使用CHAR_BITsizeof( unsigned long long ) 获得可移植的答案):

#include <stdio.h>
#include <float.h>
#include <limits.h>


int main( int argc, char **argv )
{
    int tooBig = 0;
    unsigned long long shift = LDBL_MANT_DIG;
    if ( shift >= 64 )
    {
        tooBig = 1;
        shift -= 64;
    }

    unsigned long long max = ( 1ULL << shift ) - 1ULL;

    printf( "Max integer value: 0x" );

    // don't emit an extraneous zero if LDBL_MANT_DIG is
    // exactly 64
    if ( max )
    {
        printf( "%llx", max );
    }

    if ( tooBig )
    {
        printf( "%llx", ULLONG_MAX );
    }

    printf( "\n" );

    return( 0 );
}

* - 迂腐地说,它是 FLT_RADIX 基数中的位数,但该基数几乎可以肯定是 2。

【讨论】:

    猜你喜欢
    • 2010-12-23
    • 1970-01-01
    • 1970-01-01
    • 2015-02-23
    • 1970-01-01
    • 2020-07-26
    • 2016-01-06
    • 2010-12-10
    • 2021-08-22
    相关资源
    最近更新 更多