# C# math gotchas

C# has three mathematical constants that look like constants in the C header file `float.h`. Two of these are not what you might expect.

The constant `double.MaxValue` in C# looks like the constant `DBL_MAX` in C, and indeed it is. Both give the maximum finite value of a `double`, which is on the order of 10^308. This might lead you to believe that `double.MinValue` in C# is the same as `DBL_MIN` in C or that `double.Epsilon` in C# is the same as `DBL_EPSILON`. If so, you’re in for a surprise.

The constants `DBL_MAX` and `double.MaxValue` are the same because there is no ambiguity over what “max” means: the largest finite value of a `double`. But `DBL_MIN` and `double.MinValue` are different because they minimize over different ranges. The constant `DBL_MIN` is the smallest positive value of a normalized `double`. The constant `double.MinValue` in C# is the smallest (i.e. most negative) value of a `double` and is the negative of `double.MaxValue`. The difference between `DBL_MIN` and `double.MinValue` is approximately the difference between 10^-308 and -10^308, between a very small positive number and a very large negative number.

C has a constant `DBL_EPSILON` for the smallest positive double precision number `x` such that `1 + x` does not equal 1 in machine precision. Typically a `double` has about 15 figures of precision, and so `DBL_EPSILON` is on the order of 10^-16. (For a more precise description, see Anatomy of a floating point number.)

You might expect `double.Epsilon` in C# corresponds to `DBL_EPSILON` in C. I did, until a unit test failed on some numerical code I was porting from C++ to C#. But in C# `double.Epsilon` is the smallest positive value a (denormalized) `double` can take. It is similar to `DBL_MIN`, except that `double.Epsilon` is the possible smallest value of a `double`, not requiring normalization. The constant `DBL_MIN` is on the order of 10^-308 while `double.Epsilon` is on the order of 10^-324 because it allows denormalized values. (See Anatomy of a floating point number for details of denormalized numbers.)

Incidentally, the C constants `DBL_MAX`, `DBL_MIN`, and `DBL_EPSILON` equal the return values of `max`, `min`, and `epsilon` for the C++ class `numeric_limits<double>`.

To summarize,

• `double.MaxValue` in C# equals `DBL_MAX` in C.
• `double.MinValue` in C# equals `-DBL_MAX` in C.
• `double.Epsilon` is similar to `DBL_MIN` in C, but orders of magnitude smaller.
• C# has no analog of `DBL_EPSILON` from C.

One could argue that the C# names are better than the C names. It makes sense for `double.MinValue` to be the negative of `double.MaxValue`. But the use of `Epsilon` was a mistake. The term “epsilon” in numeric computing has long been established and is not limited to C. It would have been better if Microsoft had used the name `MinPositiveValue` to be more explicit and not conflict with established terminology.

## Related posts ## 13 thoughts on “C# math gotchas”

1. Great post. Thanks for detailing this out! Glad you used unit tests to catch this instead of finding out in the wild :).

2. Hi, read your informative posts on floating point arithmetic. Do you know why in C# double and float arithmetic 1.0/0.0 evaluates to Infinity, where it would seem more rigorous for division by zero to yield a NaN as occurs in several other circumstances under IEEE 754?

3. Chris

Delete previous comment, the style sheet came back.

4. Anonymous

nit: from the sentence: “The difference between DBL_MIN and double.MinValue is approximately the difference between 10^-308 and -10^308, between a very small positive number and a very large negative number.”

-10^308 = -1^308 * 10^308 = 10^308 … -(10^308) intended perhaps?

5. Sean T. McBeth

Technical point of clarification, these values are constants in the System.Double struct from the mscorlib.dll version of the base .NET Class Library, i.e. they will be this way regardless of what language you are running on the CLR, be it F#, VB.NET, IronPython, etc., not just C#.

6. @Eutactic: You could argue that 1/0 should return the limit as x->0+ of 1/x. That would justify returning infinity. I believe that’s in keeping with the spirit of the IEEE standard. NaNs are reserved for situations where it is impossible to argue for other values such as infinity or negative infinity. For example, sqrt(-1).

@Chris: I’ve been getting a lot of traffic over the last couple days and sometimes the stylesheet doesn’t serve correctly.

@Anonymous: I believe my notation is standard. Exponentiation has higher precedence than multiplication, so -a^b means -(a^b). If you want (-a)^b you need parentheses. Negation is typically interpreted the same as multiplication by -1 and so has the same precedence as multiplication.

@Sean: Good point. Thanks for adding that.

7. Anonymous2

@John: You are correct, Anonymous is wrong. (-a^b) always means “the negation of a^b”. Which is how it should be, of course, since (-a)^b is always equal to either -(a^b) or (a^b) when b is a whole number, and so it would be silly to devote to it the short-notation real estate of parenthesisless (-a^b).

8. Anonymous22.1

1/|x| -> infinity, as x -> 0 ;
but, 1/x has different limits as x goes to 0+ or 0-
Therefore, 1/x should be NaN.

9. @Anonymous22.1: Yes, you make a good argument for why 1/0 should produce a NaN. I imagine people on the IEEE committee made that argument, but here is why I believe the committee decided on infinity rather than NaN.

There are actually two representations of zero: +0 and -0. That may sound absurd, but it is useful. If a positive quantity underflows to zero, it becomes +0. And if a negative quantity underflows to zero, it becomes -0. You could think of +0 (respectively, -0) as the bit pattern for a positive (negative) number too small to represent. The standard says 1/+0 should be +infinity and 1/-0 should be -infinity. This makes sense if you interpret +/- 0 as the ghost of a number that underflowed leaving behind only its sign.

10. Rui Alves

Thanks for informative article, but the most important issue here is:
How to replace the C++ numeric_limits::epsilon() in C# ??

Is there any known workaround for this unfortunate implementation by Microsoft?

11. Exp HP

Yikes. I’ve always been bugged by DBL_MIN (and it’s even worse in C++ as std::numeric_limits<double&rt;::min(), where it messes up generic constructs), but between that and “Epsilon,” I’m not sure which is more misleading!

On the bright side, for IEEE-754 floating point types, the “other epsilon” is easily computed, as it is necessarily a power of 2.

12. Exp HP

Also, just found this gem in the MSDN docs:

On ARM systems, the value of the Epsilon constant is too small to be detected, so it equates to zero. You can define an alternative epsilon value that equals 2.2250738585072014E-308 instead.

I take that to mean it’s defined as the smallest denormalized number even on platforms that don’t have denormalized floats? What could possibly be the use of such a constant? O_o