Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use scientific notation in const fields?

Tags:

c#

I'm working in a math library, and due to the inherent troubles of working with double I am coding all equality comparisons type a == b as Math.Abs(a - b) <= epsilon.

Also, by default, I want my formatted strings to be generated with the maximum considered precision. That is, if epsilon is 0.001 I want my default format to be N3.

Happily I did the following:

public static class Math3D
{
     internal const int ROUND = 3;
     public const double Epsilon = 1e-ROUND;
}

...and I got a compilation error. Apparently this is not allowed.

With this limitation I see no way I can define both interdependant constants as consts. Obviously I can define Epsilon as a readonly field but I feel doing so is somehow conceptually wrong. Am I missing an obvious way of how to do this?

like image 711
InBetween Avatar asked Jun 17 '13 15:06

InBetween


2 Answers

If you're going to possibly be changing it, you should use readonly here. const should really be used for things that will never change, like π. The reason for this is because of a subtle difference between const and readonly.

The main issue is that if you change the value of the const, you must recompile all dependent clients that use the const, otherwise you can shoot yourself in the foot, badly. So for values that might change, don't use const, use readonly.

So, if the value is never going to change, just use const and then don't worry about defining Epsilon in terms of ROUND, just say:

internal const int ROUND = 3;
public const double Epsilon = 1e-3;

If you really want to make sure you don't accidentally change one without changing the other, you could add a small check in the constructor:

if (Epsilon != Math.Pow(10, -ROUND)) {
    throw new YouForgotToChangeBothConstVariablesException();
}

You could even add conditional compilation so that only gets compiled in debug releases.

If it is going to change, use static readonly:

internal readonly int ROUND = 3;
public static readonly double Epsilon = Math.Pow(10, -ROUND);

With this limitation I see no way I can define both interdependant constants as consts. [...] Am I missing an obvious way of how to do this?

No, you need to do some kind of math using Math.Pow or Math.Log to go between ROUND and Epsilon and those are not acceptable for compile-time usage with const. You could write a miniature code generator to spit out these two lines of code based on a single input value, but I really question the value of investing time into that.

like image 172
jason Avatar answered Sep 29 '22 08:09

jason


1e-ROUND, specifically 1e is not a valid literal integer. You would have to do something like,

public static readonly double Epsilon = 
    decimal.Parse(
        string.Format("1E-{0}", ROUND), 
        System.Globalization.NumberStyles.Float);

Also, note the static readonly since you cannot use a const when the expression won't be known until runtime. The static readonly will work similarly to a const in this scenario.

If you prefer not dealing with strings, you can always do,

public static readonly double Epsilon = Math.Pow(10, -ROUND);
like image 26
rae1 Avatar answered Sep 29 '22 08:09

rae1