Of the 2**64 possible bit patterns a double can take on only 99.90234375% of them are used to store normal (normalised) floating point values (including +0 & -0).
Of the rest, some 18,014,398,509,481,984 bit patterns:
Numbers too big or too small to be represented respectively.
In decimal, 3.14159e0 is normalised. Whereas 0.314159e1 & 31.4159e-1 represent the same number, but are denormalised.
When produced by a mathematical operation, signalling NaNs cause an immediate trap. They represent invalid operations.
When produced, quiet NaNs don't immediately trap, but rather propogate through subsequent operations they are involved in. They represent indeterminate results.
There doesn't appear to be a positive 1.#IND (on MSC).
Numerically, this sits in the negative qNaN range -- which are all "indeterminate".
Quite why this one value -- from the 18 quintillion -- is singled out for special treatment I have yet to discover.
#! perl -slw use strict; no warnings 'portable'; use constant { POS_ZERO => 0b0_00000000000_0000_00000000_00000000_00000000_000 +00000_00000000_00000000, POS_DENORM_1ST => 0b0_00000000000_0000_00000000_00000000_00000000_000 +00000_00000000_00000001, POS_DENORM_LST => 0b0_00000000000_1111_11111111_11111111_11111111_111 +11111_11111111_11111111, POS_NORM_1ST => 0b0_00000000001_0000_00000000_00000000_00000000_000 +00000_00000000_00000000, POS_NORM_LST => 0b0_11111111110_1111_11111111_11111111_11111111_111 +11111_11111111_11111111, POS_INF => 0b0_11111111111_0000_00000000_00000000_00000000_000 +00000_00000000_00000000, POS_SNAN_1ST => 0b0_11111111111_0000_00000000_00000000_00000000_000 +00000_00000000_00000001, POS_SNAN_LST => 0b0_11111111111_0111_11111111_11111111_11111111_111 +11111_11111111_11111111, POS_QNAN_1ST => 0b0_11111111111_1000_00000000_00000000_00000000_000 +00000_00000000_00000000, POS_QNAN_LST => 0b0_11111111111_1111_11111111_11111111_11111111_111 +11111_11111111_11111111, NEG_ZERO => 0b1_00000000000_0000_00000000_00000000_00000000_000 +00000_00000000_00000000, NEG_DENORM_1ST => 0b1_00000000000_0000_00000000_00000000_00000000_000 +00000_00000000_00000001, NEG_DENORM_LST => 0b1_00000000000_1111_11111111_11111111_11111111_111 +11111_11111111_11111111, NEG_NORM_1ST => 0b1_00000000001_0000_00000000_00000000_00000000_000 +00000_00000000_00000000, NEG_NORM_LST => 0b1_11111111110_1111_11111111_11111111_11111111_111 +11111_11111111_11111111, NEG_INF => 0b1_11111111111_0000_00000000_00000000_00000000_000 +00000_00000000_00000000, NEG_SNAN_1ST => 0b1_11111111111_0000_00000000_00000000_00000000_000 +00000_00000000_00000001, NEG_SNAN_LST => 0b1_11111111111_0111_11111111_11111111_11111111_111 +11111_11111111_11111111, NEG_IND => 0b1_11111111111_1000_00000000_00000000_00000000_000 +00000_00000000_00000000, NEG_QNAN_1ST => 0b1_11111111111_1000_00000000_00000000_00000000_000 +00000_00000000_00000001, NEG_QNAN_LST => 0b1_11111111111_1111_11111111_11111111_11111111_111 +11111_11111111_11111111, }; printf "%23.16g : %016x\n", unpack( 'd', pack 'Q', $_ ), $_ for POS_ZERO, POS_DENORM_1ST, POS_DENORM_LST, POS_NORM_1ST, POS_NORM_L +ST, POS_INF, POS_SNAN_1ST, POS_SNAN_LST, POS_QNAN_1ST, POS_QNAN_LST, NEG_ZERO, NEG_DENORM_1ST, NEG_DENORM_LST, NEG_NORM_1ST, NEG_NORM_L +ST, NEG_INF, NEG_SNAN_1ST, NEG_SNAN_LST, NEG_IND, NEG_QNAN_1ST, NEG_QNAN_LST;
Produces:
C:\test>ieee.pl 0 : 0000000000000000 4.940656458412465e-324 : 0000000000000001 2.225073858507201e-308 : 000fffffffffffff 2.225073858507201e-308 : 0010000000000000 1.797693134862316e+308 : 7fefffffffffffff 1.#INF : 7ff0000000000000 1.#SNAN : 7ff0000000000001 1.#SNAN : 7ff7ffffffffffff 1.#QNAN : 7ff8000000000000 1.#QNAN : 7fffffffffffffff -0 : 8000000000000000 -4.940656458412465e-324 : 8000000000000001 -2.225073858507201e-308 : 800fffffffffffff -2.225073858507201e-308 : 8010000000000000 -1.797693134862316e+308 : ffefffffffffffff -1.#INF : fff0000000000000 -1.#SNAN : fff0000000000001 -1.#SNAN : fff7ffffffffffff -1.#IND : fff8000000000000 -1.#QNAN : fff8000000000001 -1.#QNAN : ffffffffffffffff
For completeness, here is the equivelent code in C:
#include <stdio.h> #include <float.h> typedef unsigned __int64 U64; U64 dblPatns[] = { 0x0000000000000000, // +zero 0x0000000000000001, // +denorm lo 0x000fffffffffffff, // +denorm hi 0x0010000000000000, // +norm lo 0x7fefffffffffffff, // +norm hi 0x7ff0000000000000, // +infinity 0x7ff0000000000001, // +sNAN lo 0x7ff7ffffffffffff, // +sNAN hi 0x7ff8000000000000, // +qNAN lo 0x7fffffffffffffff, // +qNAN hi 0x8000000000000000, // -zero 0x8000000000000001, // -denorm lo 0x800fffffffffffff, // -denorm hi 0x8010000000000000, // -norm lo 0xffefffffffffffff, // -norm hi 0xfff0000000000000, // -infinity 0xfff0000000000001, // -sNAN lo 0xfff7ffffffffffff, // -sNAN hi 0xfff8000000000000, // -IND ?? 0xfff8000000000001, // -qNAN lo 0xffffffffffffffff // -qNAN hi }; double asDouble( U64 u ) { return *(double*)&u; } char *FPClassAsText( int class ) { switch( class ) { case _FPCLASS_SNAN: return "Signaling NaN"; break; case _FPCLASS_QNAN: return "Quiet NaN"; break; case _FPCLASS_NINF: return "Negative infinity (–INF)"; break; case _FPCLASS_NN : return "Negative normalized non-zero"; bre +ak; case _FPCLASS_ND : return "Negative denormalized"; break; case _FPCLASS_NZ : return "Negative zero (-0)"; break; case _FPCLASS_PZ : return "Positive zero (+0)"; break; case _FPCLASS_PD : return "Positive denormalized"; break; case _FPCLASS_PN : return "Positive normalized non-zero"; bre +ak; case _FPCLASS_PINF: return "Positive infinity (+INF)"; break; default: return "Never happen; but silence the warn +ing"; } } int main( int argc, char **argv ) { int i; for( i = 0; i < sizeof( dblPatns ) / sizeof( U64 ); ++i ) printf( "%016I64x : % 23.16g %s\n", dblPatns[ i ], asDouble( dblPatns[ i ] ), FPClassAsText( _fpclass( asDouble( dblPatns[ i ] ) ) ) ); }
Which produces:
C:\test>qnan 0000000000000000 : 0 Positive zero (+0) 0000000000000001 : 4.940656458412465e-324 Positive denormalized 000fffffffffffff : 2.225073858507201e-308 Positive denormalized 0010000000000000 : 2.225073858507201e-308 Positive normalized non-zer +o 7fefffffffffffff : 1.797693134862316e+308 Positive normalized non-zer +o 7ff0000000000000 : 1.#INF Positive infinity (+INF) 7ff0000000000001 : 1.#SNAN Signaling NaN 7ff7ffffffffffff : 1.#SNAN Signaling NaN 7ff8000000000000 : 1.#QNAN Quiet NaN 7fffffffffffffff : 1.#QNAN Quiet NaN 8000000000000000 : -0 Negative zero (-0) 8000000000000001 : -4.940656458412465e-324 Negative denormalized 800fffffffffffff : -2.225073858507201e-308 Negative denormalized 8010000000000000 : -2.225073858507201e-308 Negative normalized non-zer +o ffefffffffffffff : -1.797693134862316e+308 Negative normalized non-zer +o fff0000000000000 : -1.#INF Negative infinity (-INF) fff0000000000001 : -1.#SNAN Signaling NaN fff7ffffffffffff : -1.#SNAN Signaling NaN fff8000000000000 : -1.#IND Quiet NaN fff8000000000001 : -1.#QNAN Quiet NaN ffffffffffffffff : -1.#QNAN Quiet NaN
Note how the oddball -1.#IND is labeled as "Quiet NaN" by the runtime library _fpclass() routine.
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Exploring IEEE754 floating point bit patterns.
by syphilis (Archbishop) on Jul 29, 2012 at 04:35 UTC | |
by BrowserUk (Patriarch) on Jul 29, 2012 at 06:46 UTC | |
by syphilis (Archbishop) on Jul 30, 2012 at 00:20 UTC | |
Re: Exploring IEEE754 floating point bit patterns.
by roboticus (Chancellor) on Jul 28, 2012 at 12:05 UTC | |
by BrowserUk (Patriarch) on Jul 29, 2012 at 03:11 UTC | |
by roboticus (Chancellor) on Jul 29, 2012 at 04:15 UTC | |
Re: Exploring IEEE754 floating point bit patterns.
by pryrt (Abbot) on Jun 23, 2016 at 15:10 UTC |