IT박스

비정규 부동 소수점 숫자는 무엇입니까?

itboxs 2020. 11. 24. 07:46
반응형

비정규 부동 소수점 숫자는 무엇입니까?


isnormal () 참조 페이지 는 다음을 알려줍니다.

주어진 부동 소수점 수 arg가 정상인지, 즉 0, 비정규, 무한 또는 NaN이 아닌지 판별합니다.

0, 무한 또는 NaN 인 숫자는 그 의미가 분명합니다. 그러나 그것은 또한 비정상이라고 말합니다. 숫자는 언제 비정규입니까?


IEEE754 표준에서 부동 소수점 숫자는 이진 과학 표기법 x  =  M  × 2 e로 표시 됩니다. 여기서 M가수 이고 e지수 입니다. 수학적으로 항상 1 ≤ M  <2가 되도록 지수를 선택할 수 있습니다  . * 그러나 컴퓨터 표현에서 지수는 유한 범위 만 가질 수 있기 때문에 0보다 크지 만 1.0 × 2 e 보다 작은 숫자가 있습니다. min . 그 숫자는 비정규 또는 비정규 입니다.

실제로 가수는 비정규 숫자 (및 0)를 제외하고 항상 선행 1이 있기 때문에 선행 1없이 저장됩니다 . 따라서 해석은 지수가 최소가 아니면 암시 적 선행 1이 있고 지수가 최소이면 존재하지 않으며 숫자가 비정규라는 것입니다.

*)보다 일반적으로,   모든 base- B 과학적 표기법에 대해 1 ≤  M  <  B 입니다 .


IEEE 754 기본 사항

먼저 IEEE 754 번호의 기본 구성을 살펴 보겠습니다.

단 정밀도 (32 비트)에 초점을 맞출 것이지만 모든 것이 즉시 다른 정밀도로 일반화 될 수 있습니다.

형식은 다음과 같습니다.

  • 1 비트 : 부호
  • 8 비트 : 지수
  • 23 비트 : 분수

또는 사진이 마음에 들면 :

여기에 이미지 설명 입력

소스 .

기호는 간단합니다. 0은 양수이고 1은 음수이며 이야기의 끝입니다.

지수는 8 비트 길이이므로 범위는 0에서 255까지입니다.

지수는 오프셋이이므로 편향이라고합니다 -127. 예 :

  0 == special case: zero or subnormal, explained below
  1 == 2 ^ -126
    ...
125 == 2 ^ -2
126 == 2 ^ -1
127 == 2 ^  0
128 == 2 ^  1
129 == 2 ^  2
    ...
254 == 2 ^ 127
255 == special case: infinity and NaN

최고의 비트 규칙

IEEE 754를 설계하는 동안 엔지니어는를 제외한 모든 숫자 가 첫 번째 숫자로 2 진수 0.01 1가지고 있음을 발견했습니다.

예 :

25.0   == (binary) 11001 == 1.1001 * 2^4
 0.625 == (binary) 0.101 == 1.01   * 2^-1

둘 다 그 성가신 1.부분으로 시작 합니다.

따라서 그 숫자가 거의 모든 단일 숫자를 하나의 정밀도 비트를 차지하도록하는 것은 낭비입니다.

이러한 이유로 그들은 "선도적 인 비트 규칙"을 만들었습니다.

항상 숫자가 1로 시작한다고 가정합니다.

하지만 어떻게 처리 0.0할까요? 글쎄, 그들은 예외를 만들기로 결정했습니다.

  • 지수가 0이면
  • 분수는 0
  • 숫자는 플러스 또는 마이너스를 나타냅니다. 0.0

그래서 바이트 00 00 00 00도를 나타내 므로 0.0좋아 보입니다.

이러한 규칙 만 고려하면 나타낼 수있는 가장 작은 0이 아닌 숫자는 다음과 같습니다.

  • 지수 : 0
  • 분수 : 1

선행 비트 규칙으로 인해 16 진수 분수에서 다음과 같이 보입니다.

1.000002 * 2 ^ (-127)

여기서,은 .000002A의 22 인 제로 1끝에.

우리는 받아 들일 수 없습니다 fraction = 0. 그렇지 않으면 그 숫자가 될 것입니다 0.0.

그러나 예리한 예술적 감각을 가진 엔지니어들은 이렇게 생각했습니다. 우리가 직선 0.0에서 2의 적절한 거듭 제곱도 아닌 다른 것으로 점프 한다고? 어떻게 든 더 작은 숫자를 나타낼 수는 없습니까?

비정규 숫자

엔지니어들은 한동안 머리를 긁적이며 평소처럼 또 다른 좋은 아이디어를 가지고 돌아 왔습니다. 새 규칙을 만들면 어떻게 되나요?

지수가 0이면 :

  • 선행 비트는 0이됩니다.
  • 지수는 -126으로 고정됩니다 (이 예외가없는 것처럼 -127이 아님).

이러한 숫자를 비정규 숫자 (또는 동의어 인 비정규 숫자)라고합니다.

이 규칙은 즉시 다음과 같은 숫자를 의미합니다.

  • 지수 : 0
  • 분수 : 0

is 0.0, 이는 추적해야 할 규칙이 하나 적다는 것을 의미하므로 우아합니다.

그래서 0.0실제로 우리의 정의에 따르면 비정규 숫자입니다!

이 새로운 규칙에서 가장 작은 비정규 숫자는 다음과 같습니다.

  • 지수 : 1 (0은 비정규 임)
  • 분수 : 0

이는 다음을 나타냅니다.

1.0 * 2 ^ (-126)

그런 다음 가장 큰 비정규 수는 다음과 같습니다.

  • 지수 : 0
  • 분수 : 0x7FFFFF (23 비트 1)

다음과 같습니다.

0.FFFFFE * 2 ^ (-126)

여기서 .FFFFFE다시 점의 우측에 23 비트이다.

이것은 정상이 아닌 가장 작은 숫자에 매우 가깝습니다.

그리고 0이 아닌 가장 작은 비정규 숫자는 다음과 같습니다.

  • 지수 : 0
  • 분수 : 1

다음과 같습니다.

0.000002 * 2 ^ (-126)

이것도 꽤 가깝게 보입니다 0.0!

그보다 작은 숫자를 표현하는 현명한 방법을 찾을 수 없었던 엔지니어들은 기뻐했고 다시 온라인으로 고양이 사진을 보거나 70 년대에했던 것이 무엇이든 봤습니다.

보시다시피 비정규 숫자는 정밀도와 표현 길이 사이의 균형을 이룹니다.

가장 극단적 인 예로서, 가장 작은 0이 아닌 비정규 :

0.000002 * 2 ^ (-126)

기본적으로 32 비트 대신 단일 비트의 정밀도를가집니다. 예를 들어 2로 나누면 :

0.000002 * 2 ^ (-126) / 2

우리는 실제로 0.0정확히 도달 합니다!

심상

우리가 배운 것에 대해 기하학적 직관을 갖는 것은 항상 좋은 생각입니다.

주어진 각 지수에 대해 IEEE 754 부동 소수점 숫자를 한 줄에 플로팅하면 다음과 같습니다.

          +---+-------+---------------+-------------------------------+
exponent  |126|  127  |      128      |              129              |
          +---+-------+---------------+-------------------------------+
          |   |       |               |                               |
          v   v       v               v                               v
          -------------------------------------------------------------
floats    ***** * * * *   *   *   *   *       *       *       *       *
          -------------------------------------------------------------
          ^   ^       ^               ^                               ^
          |   |       |               |                               |
          0.5 1.0     2.0             4.0                             8.0

그것으로부터 우리는 각 지수에 대해 그것을 볼 수 있습니다.

  • 각 지수에 대해 표시된 숫자간에 겹침이 없습니다.
  • 각 지수에 대해 동일한 숫자 2 ^ 32의 숫자 (여기서는 4로 *표시됨)가 있습니다.
  • 포인트는 주어진 지수에 대해 동일한 간격으로 배치됩니다.
  • 더 큰 지수는 더 큰 범위를 포함하지만 점이 더 분산되어 있습니다.

이제이를 지수 0까지 낮추겠습니다.

비정규가 없으면 가상적으로 다음과 같이 보일 것입니다.

          +---+---+-------+---------------+-------------------------------+
exponent  | ? | 0 |   1   |       2       |               3               |
          +---+---+-------+---------------+-------------------------------+
          |   |   |       |               |                               |
          v   v   v       v               v                               v
          -----------------------------------------------------------------
floats    *   ***** * * * *   *   *   *   *       *       *       *       *
          -----------------------------------------------------------------
          ^   ^   ^       ^               ^                               ^
          |   |   |       |               |                               |
          0   |   2^-126  2^-125          2^-124                          2^-123
              |
              2^-127

비법 선의 경우 다음과 같습니다.

          +-------+-------+---------------+-------------------------------+
exponent  |   0   |   1   |       2       |               3               |
          +-------+-------+---------------+-------------------------------+
          |       |       |               |                               |
          v       v       v               v                               v
          -----------------------------------------------------------------
floats    * * * * * * * * *   *   *   *   *       *       *       *       *
          -----------------------------------------------------------------
          ^   ^   ^       ^               ^                               ^
          |   |   |       |               |                               |
          0   |   2^-126  2^-125          2^-124                          2^-123
              |
              2^-127

두 그래프를 비교하면 다음을 확인할 수 있습니다.

  • subnormals는 지수의 범위의 길이를 두 배로 0부터 [2^-127, 2^-126)[0, 2^-126)

    비정상 범위에서 부동 소수점 사이의 공간은 for와 동일합니다 [0, 2^-126).

  • 범위 [2^-127, 2^-126)에는 비정규가 없을 경우 점 수의 절반이 있습니다.

    이 포인트의 절반은 범위의 나머지 절반을 채우는 데 사용됩니다.

  • 범위 [0, 2^-127)에는 비정규가있는 점이 있지만없는 점은 없습니다.

    이 점의 부족은 [0, 2^-127)그다지 우아하지 않으며 비정규가 존재하는 주된 이유입니다!

  • 포인트 간격이 동일하기 때문에 :

    • 범위 [2^-128, 2^-127)는 포인트의 절반이 [2^-127, 2^-126)- [2^-129, 2^-128)포인트의 절반이[2^-128, 2^-127)
    • 등등

    이것은 비정규가 크기와 정밀도 사이의 균형이라고 말할 때 의미하는 것입니다.

실행 가능한 C 예제

이제 우리의 이론을 검증하기 위해 실제 코드를 가지고 놀자.

거의 모든 현재 및 데스크톱 컴퓨터에서 C float는 단 정밀도 IEEE 754 부동 소수점 숫자를 나타냅니다.

이것은 특히 내 Ubuntu 18.04 amd64 Lenovo P51 노트북의 경우입니다.

이러한 가정하에 모든 어설 션은 다음 프로그램을 전달합니다.

subnormal.c

#if __STDC_VERSION__ < 201112L
#error C11 required
#endif

#ifndef __STDC_IEC_559__
#error IEEE 754 not implemented
#endif

#include <assert.h>
#include <float.h> /* FLT_HAS_SUBNORM */
#include <inttypes.h>
#include <math.h> /* isnormal */
#include <stdlib.h>
#include <stdio.h>

#if FLT_HAS_SUBNORM != 1
#error float does not have subnormal numbers
#endif

typedef struct {
    uint32_t sign, exponent, fraction;
} Float32;

Float32 float32_from_float(float f) {
    uint32_t bytes;
    Float32 float32;
    bytes = *(uint32_t*)&f;
    float32.fraction = bytes & 0x007FFFFF;
    bytes >>= 23;
    float32.exponent = bytes & 0x000000FF;
    bytes >>= 8;
    float32.sign = bytes & 0x000000001;
    bytes >>= 1;
    return float32;
}

float float_from_bytes(
    uint32_t sign,
    uint32_t exponent,
    uint32_t fraction
) {
    uint32_t bytes;
    bytes = 0;
    bytes |= sign;
    bytes <<= 8;
    bytes |= exponent;
    bytes <<= 23;
    bytes |= fraction;
    return *(float*)&bytes;
}

int float32_equal(
    float f,
    uint32_t sign,
    uint32_t exponent,
    uint32_t fraction
) {
    Float32 float32;
    float32 = float32_from_float(f);
    return
        (float32.sign     == sign) &&
        (float32.exponent == exponent) &&
        (float32.fraction == fraction)
    ;
}

void float32_print(float f) {
    Float32 float32 = float32_from_float(f);
    printf(
        "%" PRIu32 " %" PRIu32 " %" PRIu32 "\n",
        float32.sign, float32.exponent, float32.fraction
    );
}

int main(void) {
    /* Basic examples. */
    assert(float32_equal(0.5f, 0, 126, 0));
    assert(float32_equal(1.0f, 0, 127, 0));
    assert(float32_equal(2.0f, 0, 128, 0));
    assert(isnormal(0.5f));
    assert(isnormal(1.0f));
    assert(isnormal(2.0f));

    /* Quick review of C hex floating point literals. */
    assert(0.5f == 0x1.0p-1f);
    assert(1.0f == 0x1.0p0f);
    assert(2.0f == 0x1.0p1f);

    /* Sign bit. */
    assert(float32_equal(-0.5f, 1, 126, 0));
    assert(float32_equal(-1.0f, 1, 127, 0));
    assert(float32_equal(-2.0f, 1, 128, 0));
    assert(isnormal(-0.5f));
    assert(isnormal(-1.0f));
    assert(isnormal(-2.0f));

    /* The special case of 0.0 and -0.0. */
    assert(float32_equal( 0.0f, 0, 0, 0));
    assert(float32_equal(-0.0f, 1, 0, 0));
    assert(!isnormal( 0.0f));
    assert(!isnormal(-0.0f));
    assert(0.0f == -0.0f);

    /* ANSI C defines FLT_MIN as the smallest non-subnormal number. */
    assert(FLT_MIN == 0x1.0p-126f);
    assert(float32_equal(FLT_MIN, 0, 1, 0));
    assert(isnormal(FLT_MIN));

    /* The largest subnormal number. */
    float largest_subnormal = float_from_bytes(0, 0, 0x7FFFFF);
    assert(largest_subnormal == 0x0.FFFFFEp-126f);
    assert(largest_subnormal < FLT_MIN);
    assert(!isnormal(largest_subnormal));

    /* The smallest non-zero subnormal number. */
    float smallest_subnormal = float_from_bytes(0, 0, 1);
    assert(smallest_subnormal == 0x0.000002p-126f);
    assert(0.0f < smallest_subnormal);
    assert(!isnormal(smallest_subnormal));

    return EXIT_SUCCESS;
}

GitHub 업스트림 .

Compile and run with:

gcc -ggdb3 -O0 -std=c11 -Wall -Wextra -Wpedantic -Werror -o subnormal.out subnormal.c
./subnormal.out

C++

In addition to exposing all of C's APIs, C++ also exposes some extra subnormal related functionality that is not as readily available in C in <limits>, e.g.:

  • denorm_min: Returns the minimum positive subnormal value of the type T

In C++ the hole API is templated for each floating point type, and is much nicer.

Implementations

x86_64 and ARMv8 implemens IEEE 754 directly on hardware, which the C code translates to.

Subnormals seem to be less fast than normals in certain implementations: Why does changing 0.1f to 0 slow down performance by 10x? This is mentioned in the ARM manual, see the "ARMv8 details" section of this answer.

ARMv8 details

ARM Architecture Reference Manual ARMv8 DDI 0487C.a manual A1.5.4 "Flush-to-zero" describes a configurable mode where subnormals are rounded to zero to improve performance:

The performance of floating-point processing can be reduced when doing calculations involving denormalized numbers and Underflow exceptions. In many algorithms, this performance can be recovered, without significantly affecting the accuracy of the final result, by replacing the denormalized operands and intermediate results with zeros. To permit this optimization, ARM floating-point implementations allow a Flush-to-zero mode to be used for different floating-point formats as follows:

  • For AArch64:

    • If FPCR.FZ==1, then Flush-to-Zero mode is used for all Single-Precision and Double-Precision inputs and outputs of all instructions.

    • If FPCR.FZ16==1, then Flush-to-Zero mode is used for all Half-Precision inputs and outputs of floating-point instructions, other than:—Conversions between Half-Precision and Single-Precision numbers.—Conversions between Half-Precision and Double-Precision numbers.

A1.5.2 "Floating-point standards, and terminology" Table A1-3 "Floating-point terminology" confirms that subnormals and denormals are synonyms:

This manual                 IEEE 754-2008
-------------------------   -------------
[...]
Denormal, or denormalized   Subnormal

C5.2.7 "FPCR, Floating-point Control Register" describes how ARMv8 can optionally raise exceptions or set a flag bits whenever the input of a floating point operation is subnormal:

FPCR.IDE, bit [15] Input Denormal floating-point exception trap enable. Possible values are:

  • 0b0 Untrapped exception handling selected. If the floating-point exception occurs then the FPSR.IDC bit is set to 1.

  • 0b1 Trapped exception handling selected. If the floating-point exception occurs, the PE does not update the FPSR.IDC bit. The trap handling software can decide whether to set the FPSR.IDC bit to 1.

D12.2.88 "MVFR1_EL1, AArch32 Media and VFP Feature Register 1" shows that denormal support is completely optional in fact, and offers a bit to detect if there is support:

FPFtZ, bits [3:0]

Flush to Zero mode. Indicates whether the floating-point implementation provides support only for the Flush-to-Zero mode of operation. Defined values are:

  • 0b0000 Not implemented, or hardware supports only the Flush-to-Zero mode of operation.

  • 0b0001 Hardware supports full denormalized number arithmetic.

All other values are reserved.

In ARMv8-A, the permitted values are 0b0000 and 0b0001.

This suggests that when subnormals are not implemented, implementations just revert to flush-to-zero.

Infinity and NaN

Curious? I've written some things at:


From http://blogs.oracle.com/d/entry/subnormal_numbers:

There are potentially multiple ways of representing the same number, using decimal as an example, the number 0.1 could be represented as 1*10-1 or 0.1*100 or even 0.01 * 10. The standard dictates that the numbers are always stored with the first bit as a one. In decimal that corresponds to the 1*10-1 example.

Now suppose that the lowest exponent that can be represented is -100. So the smallest number that can be represented in normal form is 1*10-100. However, if we relax the constraint that the leading bit be a one, then we can actually represent smaller numbers in the same space. Taking a decimal example we could represent 0.1*10-100. This is called a subnormal number. The purpose of having subnormal numbers is to smooth the gap between the smallest normal number and zero.

비정규 숫자는 정규 숫자보다 정밀도가 낮다는 것을 인식하는 것이 매우 중요합니다. 실제로 그들은 더 작은 크기에 대해 감소 된 정밀도를 거래하고 있습니다. 따라서 비정규 숫자를 사용하는 계산은 일반 숫자에 대한 계산과 동일한 정밀도를 갖지 않습니다. 따라서 비정규 숫자에 대해 상당한 계산을 수행하는 응용 프로그램은 배율을 다시 조정 (즉, 숫자에 일부 배율 인수를 곱하는 것)이 비정규 수가 적고 더 정확한 결과를 얻을 수 있는지 조사 할 가치가있을 것입니다.

참고 URL : https://stackoverflow.com/questions/8341395/what-is-a-subnormal-floating-point-number

반응형