부동소수점 리터럴

부동소수점 리터럴 (Floating-point literals)

소스 파일에 값을 직접 적어서 컴파일 타임 상수를 만드는 부동소수점 리터럴을 알아볼게요. 3.141e10처럼 소수점이 들어간 숫자 상수를 적는 규칙입니다.

출처: cppreference

본문

문법

    digit-sequence decimal-exponent suffix (optional) (1)
    digit-sequence . decimal-exponent (optional) suffix (optional) (2)
    digit-sequence (optional) . digit-sequence decimal-exponent (optional) suffix (optional) (3)
    0x | 0X hex-digit-sequence hex-exponent suffix (optional) (4) (since C++17)
    0x | 0X hex-digit-sequence . hex-exponent suffix (optional) (5) (since C++17)
    0x | 0X hex-digit-sequence (optional) . hex-digit-sequence hex-exponent suffix (optional) (6) (since C++17)
  • (1) 소수점 없이 정수를 나타내는 digit-sequence. 이 경우 지수는 필수예요: 1e10, 1e-5L
  • (2) 소수점을 가진 정수를 나타내는 digit-sequence. 이 경우 지수는 선택이에요: 1., 1.e-2
  • (3) 분수를 나타내는 digit-sequence. 지수는 선택이에요: 3.14, .1f, 0.1e-1L
  • (4) 기수 구분자(radix separator) 없이 정수를 나타내는 16진수 digit-sequence. 16진수 부동소수점 리터럴에서는 지수가 항상 필수예요: 0x1ffp10, 0X0p-1
  • (5) 기수 구분자를 가진 정수를 나타내는 16진수 digit-sequence. 16진수 부동소수점 리터럴에서는 지수가 항상 필수예요: 0x1.p0, 0xf.p-1
  • (6) 기수 구분자를 가진 분수를 나타내는 16진수 digit-sequence. 16진수 부동소수점 리터럴에서는 지수가 항상 필수예요: 0x0.123p-1, 0xa.bp10l

decimal-exponent는 다음과 같은 형태를 가져요:

    e | E exponent-sign (optional) digit-sequence

hex-exponent는 다음과 같은 형태를 가져요:

    p | P exponent-sign (optional) digit-sequence (since C++17)

exponent-sign은 있으면 +- 중 하나예요.

suffix는 있으면 f, l, F, L, f16, f32, f64, f128, bf16, F16, F32, F64, F128, BF16(C++23부터) 중 하나이며, 부동소수점 리터럴의 타입을 결정해요:

  • (접미사 없음) → double
  • f Ffloat
  • l Llong double
  • f16 F16std::float16_t, f32 F32std::float32_t, f64 F64std::float64_t, f128 F128std::float128_t, bf16 BF16std::bfloat16_t (C++23부터)

선택적인 작은따옴표(')를 숫자 사이에 구분자로 넣을 수 있으며, 리터럴의 값을 결정할 때는 무시돼요. (C++14부터)

설명

십진 과학 표기법이 사용돼요. 부동소수점 리터럴의 값은 significand(가수)에 10의 decimal-exponent승을 곱한 값이 됩니다. 예를 들어 123e4의 수학적 의미는 123×10⁴예요.

부동소수점 리터럴이 0x0X로 시작하면 16진수 부동소수점 리터럴이고, 그렇지 않으면 십진 부동소수점 리터럴이에요. (C++17부터) 16진수 부동소수점 리터럴에서는 significand가 16진수 유리수로 해석되고, 지수의 digit-sequence는 significand를 스케일링할 (십진) 정수 2의 거듭제곱으로 해석돼요. (C++17부터)

double d = 0x1.4p3; // hex fraction 1.4 (decimal 1.25) scaled by 2^3, that is 10.0

참고 사항

16진수 부동소수점 리터럴은 C++17 이전에는 C++의 일부가 아니었어요. 다만 C++11부터는 I/O 함수에서 파싱하고 출력할 수 있었죠. std::hexfloat를 켠 C++ I/O 스트림과 std::printf, std::scanf 등의 C I/O 스트림 모두 해당됩니다. 형식 설명은 std::strtof를 참고하세요.

| 기능 테스트 매크로 | 값 | 표준 | 기능 | | __cpp_hex_float | 201603L | (C++17) | 16진수 부동소수점 리터럴 |

예제

접미사가 타입을 어떻게 바꾸는지, 그리고 출력이 어떻게 달라지는지 확인해 볼게요.

#include <iomanip>
#include <iostream>
#include <limits>
#include <typeinfo>

#define OUT(x) '\n' << std::setw(16) << #x << x

int main()
{
    std::cout
        << "Literal" "\t" "Printed value" << std::left
        << OUT( 58.            ) // double
        << OUT( 4e2            ) // double
        << OUT( 123.456e-67    ) // double
        << OUT( 123.456e-67f   ) // float, truncated to zero
        << OUT( .1E4f          ) // float
        << OUT( 0x10.1p0       ) // double
        << OUT( 0x1p5          ) // double
        << OUT( 0x1e5          ) // integer literal, not floating-point
        << OUT( 3.14'15'92     ) // double, single quotes ignored (C++14)
        << OUT( 1.18e-4932l    ) // long double
        << std::setprecision(39)
        << OUT( 3.4028234e38f  ) // float
        << OUT( 3.4028234e38   ) // double
        << OUT( 3.4028234e38l  ) // long double
        << '\n';

    static_assert(3.4028234e38f == std::numeric_limits<float>::max());

    static_assert(3.4028234e38f ==  // ends with 4
                  3.4028235e38f);   // ends with 5

    static_assert(3.4028234e38 !=   // ends with 4
                  3.4028235e38);    // ends with 5

    // Both floating-point constants below are 3.4028234e38
    static_assert(3.4028234e38f !=  // a float (then promoted to double)
                  3.4028234e38);    // a double
}

가능한 출력:

Literal         Printed value
58.             58
4e2             400
123.456e-67     1.23456e-65
123.456e-67f    0
.1E4f           1000
0x10.1p0        16.0625
0x1p5           32
0x1e5           485
3.14'15'92      3.14159
1.18e-4932l     1.18e-4932
3.4028234e38f   340282346638528859811704183484516925440
3.4028234e38    340282339999999992395853996843190976512
3.4028234e38l   340282339999999999995912555211526242304

더 알아보기 (Learn more)