对于C中的整数常量,科学记数法是否安全?

时间:2014-06-24 14:47:36

标签: c++ c gcc

有一段时间,我使用科学记数法代表常数中的10大常数,因此我不必计算零。 e.g。

#define DELAY_USEC 1e6

一位同事指出,这不安全,因为它不是一个整数,并且不能保证总是等于1000000 正好。文档似乎证实了这一点,但我想知道它在实用性方面是否真实。有没有办法用速记安全地声明十次幂的整数?将它强制转换为定义中的int是否安全?

6 个答案:

答案 0 :(得分:21)

理论上,没有。两种语言都没有指定如何表示浮点值,或者哪些值可以精确表示。 (更新:显然,C11确实推荐了一种表示法.C ++和旧的C语言,不要)。

在实践中,是的,适用于很大范围的值。您可能遇到的任何实施都会使用double {{1}}。这可以精确地表示高达2 53 (大约9x10 15 )的任何整数值。它当然可以代表32位整数类型所代表的任何东西。

答案 1 :(得分:8)

您想要使用用户定义的文字:

constexpr long long operator "" _k(long long l) {
    return l * 1000;
}

constexpr long long operator "" _m(long long l) {
    return l * 1000 * 1000;
}

然后你可以简单地做:

long long delay = 1_m;
long long wait = 45_k;

答案 2 :(得分:8)

你具体询问十的权力。 1e6将是一百万。您可以前往1e22而不会发生任何不良事件。但请注意,在C ++和C中,1e6double常量,而不是整数常量。

十的负面力量是另一回事。 1e-1与所有较低权力一样不精确。

答案 3 :(得分:2)

似乎gcc假定使用科学记数法将常量定义为浮点数,除非它是强制转换的。

一个简单的C代码显示了这一点:

#include <stdio.h>

#define DELAY_USEC_FP  1e6
#define DELAY_USEC_INT (unsigned int) 1e6

int main()
{
    printf("DELAY_USEC_FP: %f\n", DELAY_USEC_FP);
    printf("DELAY_USEC_INT: %u\n",  DELAY_USEC_INT);
    return 0;
}

在x86-64计算机上,gcc生成此汇编代码($ gcc -S define.c):

[...]
; 0x4696837146684686336 = 1e6 in double-precision FP IEEE-754 format
movabsq $4696837146684686336, %rax
[...]
call    printf
movl    $1000000, %esi
[...]
call    printf
movl    $0, %eax

如上所述here,10e15和10e22分别是10个数字的最大幂,它们分别以简单和双精度浮点格式具有精确表示。

使用32位或64位整数类型无法表示10个数字的更大功率。

答案 4 :(得分:0)

由于INT_MAX的规范预留了52 bits for you to use,因此您永远不会在double以下的内容上出现舍入错误。你的“小数分量”只是你的整数,你的“指数”将是1,浮点数不会与之相悖。

答案 5 :(得分:0)

这真的不安全,因为编译器会将其视为浮点数,因此精度限制为53位而不是64位整数(long int),您可以阅读更多关于浮点数numbrers的表示< / p>

http://en.wikipedia.org/wiki/Floating_point