Integral types in .NET use two's complement system for representation. While they could reserve some bit patterns for special values, they chose not to. double
and float
use a completely different representation system (IEEE 754) which reserves some special bit patterns for NaN, +Infinity, -Infinity, ...
One reason that NaN and Infinity values make more sense for floating point arithmetic is that operations could result division by zero, not only because the divisor is actually zero, but because it's too small to be represented by the type. As a result, if that wasn't the case, you could have some valid calculation mysteriously throw a divide by zero exception. This won't happen for int
types as they are exact and don't have a precision error.
decimal
is designed to be used for "real-world" decimal floating point numbers. It's rarely subject to calculations that double
and float
are designed to do. What would NaN
express for a real world number?
Leaving reasons behind it alone, it is what it is and there's nothing we could do about it, so the best route to go is to use nullable types (they are designed to help with exactly this kind of situation). It's the right way to solve this problem. If you don't want to do that (and exceptions don't make sense), you should resort to the magic number solution. If you chose to do so, just make sure it's outside of the domain of valid results.
EDIT (very common misconception about decimal):
As also noted by MSDN, decimal
is not fixed point. It is a floating point number:
A decimal number is a floating-point value that consists of a sign, a numeric value where each digit in the value ranges from 0 to 9, and a scaling factor that indicates the position of a floating decimal point that separates the integral and fractional parts of the numeric value.