yohhoyの日記

技術的メモをしていきたい日記

nan("is Not-a-Number")

プログラミング言語C/C++における浮動小数点数 NaN(Not-a-Number)*1 について。

C/C++標準ライブラリはquiet NaN*2を返すnan関数を提供し、同関数では処理系定義(implementation-defined)のタグ文字列を受け取る。一般的には空文字列""を指定するが、ライブラリ仕様上は任意の文字列*3を指定可能。

// C
#include <math.h>
double d1 = nan("42");   // OK
double d2 = nan("wtf");  // OK
// C++
#include <cmath>
double d1 = std::nan("42");   // OK
double d2 = std::nan("wtf");  // OK

IEC 60559浮動小数点型のバイナリ表現は {符号S, 指数部E, 仮数T} の組で表され、指数部Eが全ビット1かつ仮数Tが非ゼロのとき NaN と解釈される。上記で指定するタグは仮数部(significand)ビット列*4に反映される。ただし、ISO C/C++およびIEC 60559いずれの仕様でもその意味を規定しないため、実動作は処理系に依存する。

C11 7.12.11.2/p1-2, 7.22.1.3/p3-4より一部引用(下線部は強調)。C++標準ライブラリに含まれるC標準ライブラリはC言語仕様に従う。*5

#include <math.h>
double nan(const char *tagp);
float nanf(const char *tagp);
long double nanl(const char *tagp);

2 The call nan("n-char-sequence") is equivalent to strtod("NAN(n-char-sequence)", (char**) NULL); the call nan("") is equivalent to strtod("NAN()", (char**) NULL). If tagp does not point to an n-char sequence or an empty string, the call is equivalent to strtod("NAN", (char**) NULL). Calls to nanf and nanl are equivalent to the corresponding calls to strtof and strtold.

3 The expected form of the subject sequence is an optional plus or minus sign, then one of the following:

  • (snip)
  • NAN or NAN(n-char-sequenceopt), ignoring case in the NAN part, where:

  n-char-sequence:
    digit
    nondigit
    n-char-sequence digit
    n-char-sequence nondigit
(snip)

4 (snip) A character sequence NAN or NAN(n-char-sequenceopt) is interpreted as a quiet NaN, if supported in the return type, else like a subject sequence part that does not have the expected form; the meaning of the n-char sequence is implementation-defined.293)(snip)
脚注293) An implementation may use the n-char sequence to determine extra information to be represented in the NaN's significand.

C99 (PDF)Rationale 5.2.4.2.2, 7.20.1.3より一部引用。

5.2.4.2.2 Characteristics of floating types <float.h>
NaNs
The primary utility of quiet NaNs, as stated in IEC 60559, "to handle otherwise intractable situations, such as providing a default value for 0.0/0.0," is supported by C99.

Other applications of NaNs may prove useful. Available parts of NaNs have been used to encode auxiliary information, for example about the NaN’s origin. Signaling NaNs might be candidates for filling uninitialized storage; and their available parts could distinguish uninitialized floating objects. IEC 60559 signaling NaNs and trap handlers potentially provide hooks for maintaining diagnostic information or for implementing special arithmetics.

However, C support for signaling NaNs, or for auxiliary information that could be encoded in NaNs, is problematic. Trap handling varies widely among implementations. Implementation mechanisms may trigger signaling NaNs, or fail to, in mysterious ways. The IEC 60559 floating-point standard recommends that NaNs propagate; but it does not require this and not all implementations do. And the floating-point standard fails to specify the contents of NaNs through format conversion. Making signaling NaNs predictable imposes optimization restrictions that anticipated benefits don’t justify. For these reasons this standard does not define the behavior of signaling NaNs nor specify the interpretation of NaN significands.

7.20.1.3 The strtod, strtof, and strtold functions
So much regarding NaN significands is unspecified because so little is portable. Attaching meaning to NaN significands is problematic, even for one implementation, even an IEC 60559 one. For example, the IEC 60559 floating-point standard does not specify the effect of format conversions on NaN significands. Conversions, perhaps generated by the compiler, may alter NaN significands in obscure ways.

IEEE 754 2.1, 6.2, 6.2.1より一部引用。

2.1 Definitions
payload: The diagnostic information contained in a NaN, encoded in part of its trailing significand field.

6.2 Operations with NaNs
Two different kinds of NaN, signaling and quiet, shall be supported in all floating-point operations. Signaling NaNs afford representations for uninitialized variables and arithmetic-like enhancements (such as complex-affine infinities or extremely wide range) that are not in the scope of this standard. Quiet NaNs should, by means left to the implementer's discretion, afford retrospective diagnostic information inherited from invalid or unavailable data and results. To facilitate propagation of diagnostic information contained in NaNs, as much of that information as possible should be preserved in NaN results of operations.

6.2.1 NaN encodings in binary formats
All binary NaN bit strings have all the bits of the biased exponent field E set to 1 (see 3.4). A quiet NaN bit string should be encoded with the first bit (d1) of the trailing significand field T being 1. A signaling NaN bit string should be encoded with the first bit of the trailing significand field being 0. If the first bit of the trailing significand field is 0, some other bit of the trailing significand field must be non-zero to distinguish the NaN from infinity. In the preferred encoding just described, a signaling NaN shall be quieted by setting d1 to 1, leaving the remaining bits of T unchanged.

For binary formats, the payload is encoded in the p-2 least significant bits of the trailing significand field.

関連URL

*1:https://ja.wikipedia.org/wiki/NaN

*2:C/C++言語仕様およびIEC 60559仕様(旧IEC 559)では、2種類のNaN "quiet NaN" と "signaling NaN" を規定している。

*3:厳密には アンダースコア(_)、アルファベット(a-z A-Z)、数値(0-9)の組み合わせが許容される。(C11 6.4.2.1/p1)

*4:仮数部(significand) MSB 2ビットはquiet NaN/signaling Nanの区別に利用するため、以降のビット列がペイロード(payload)となる。

*5:C++17 20.2/p2: "The descriptions of many library functions rely on the C standard library for the semantics of those functions. In some cases, the signatures specified in this International Standard may be different from the signatures in the C standard library, and additional overloads may be declared in this International Standard, but the behavior and the preconditions (including any preconditions implied by the use of an ISO C restrict qualifier) are the same unless otherwise stated."