Is scientific notation safe for integer constants

2020-05-21 08:12发布

For a while, I've been representing large powers of 10 in constants using scientific notation, just so I don't have to count the zeros. e.g.

#define DELAY_USEC 1e6

A colleague pointed out that this isn't safe, because it's not an integer and is not guaranteed to always equal 1000000 exactly. Documentation seems to confirm this, but I'm wondering if its true in practicality. Is there any way to safely declare a power-of-ten integer using a shorthand? Is it safe just to cast it to an int in the define?

标签: c++ c gcc
6条回答
在下西门庆
2楼-- · 2020-05-21 08:14

It's really not safe because the compiler will consider it as a floating point number, so the precision is limited to 53 bits instead of 64 bits of integers (long int) for more you can read about the presentation of floating point numbrers

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

查看更多
The star\"
3楼-- · 2020-05-21 08:16

You ask specifically about powers of ten. 1e6 will be exactly one million. You can go up to 1e22 without anything bad happening. However, note that in both C++ and C, 1e6 is a double constant, rather than an integer constant.

Negative powers of ten are a different story. 1e-1 is inexact, as are all lower powers.

查看更多
太酷不给撩
4楼-- · 2020-05-21 08:27

You'll never get rounding errors on something less than INT_MAX, since the specification for double sets aside 52 bits for you to use. Your "fractional component" is just your integer, and your "exponent" will be 1, and floating point doesn't struggle with that.

查看更多
劳资没心,怎么记你
5楼-- · 2020-05-21 08:35

In theory, no. Neither language specifies how floating point values are represented, or which values can be represented exactly. (UPDATE: apparently, C11 does recommend a representation. C++, and older C dialects, don't).

In practice, yes, for quite a large range of values. Any implementation you're remotely likely to encounter will use a 64-bit IEEE representation for double. This can represent any integer value up to 253 (approximately 9x1015) exactly. It can certainly represent anything representable by a 32-bit integer type.

查看更多
倾城 Initia
6楼-- · 2020-05-21 08:37

It seems that gcc assumes a constant defined using scientific notation as a floating point number unless it is cast.

A simple C code shows this:

#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;
}

On a x86-64 machine, gcc generates this assembly code ($ 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

As stated here, 10e15 and 10e22 are the maximum power of ten numbers that have an exact representation in simple and double-precision floating-point format, respectively.

Larger power of ten numbers can not be represented using 32-bit or 64-bit integer types.

查看更多
来,给爷笑一个
7楼-- · 2020-05-21 08:40

You want to use user defined literals:

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

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

then you can simple do:

long long delay = 1_m;
long long wait = 45_k;
查看更多
登录 后发表回答