Epsilon == and Tolerance Regarding Double Value Comparison in Revit API
Like else where, in Revit API, we need to compare double values many times, however it still seems an issue for some people to do the comparison programmatically. In this article, let us address it.Before the constant Double.Epsilon comes out in the .NET Framework, most people know it is not safe to do double value comparison using the equal logical operator directly, as == in C# for example, and we have to compare the absolute differece between the two double values with a tolerance to see whether they can be thought as equal or not.But since the Double.Epsilon thing comes out it seems to have caused great confusion to some people even having some programming experiences. They might think the Double.Epsilon is just there to make programmers’ life easy and should be used anywhere to replace a hard coded tolerance constant that we have to define explicitly by ourselves.Is it not a good practice?To answer the question, let us do a experiment first. For a single wall, not intersecting with any other walls and not holding any windows, doors or anything else, its area obviously can be calculated through multiplying its height and length.Let us see what the Double.Epsilon, the == operator, and a tolerance constant such as 1e-10 value, will give us:Selection selection = CachedUiApp.ActiveUIDocument.Selection;
Wall wall1 = selection.PickObject(ObjectType.Element, "Pick a wall").Element as Wall;
double height =0, length=0, area=0;
foreach (Parameter p in wall1.Parameters)
{
InternalDefinition def = p.Definition as InternalDefinition;
if (def.BuiltInParameter == BuiltInParameter.WALL_USER_HEIGHT_PARAM)
height = p.AsDouble();
if (def.BuiltInParameter == BuiltInParameter.CURVE_ELEM_LENGTH)
length = p.AsDouble();
if (def.BuiltInParameter == BuiltInParameter.HOST_AREA_COMPUTED)
area = p.AsDouble();
}string message = string.Format("Height: {0}\tLength: {1}\tArea: {2}\n\n", height, length, area);
message += string.Format("Height x Length == Area ?\nCase 1 (Epsilon): {0}\nCase 2 (==): {1}\nCase 3 (1e-10): {2}",
Math.Abs(height*length-area) < Double.Epsilon,
height*length == area,
Math.Abs(height*length-area) < 1e-10);
MessageBox.Show(message, "Epsilon, ==, and Tolerance");If the above code is copied and pasted into an external command definition, the assembly is loaded into Revit, the command is run, and a single wall is picked, the following message may be the output:
http://spiderinnet.typepad.com/.a/6a013489b64e31970c01538ff36146970b-800wi
As can be seen, the Epsilon approach reports the same as the == approach but they are all wrong. As expected, the 1e-10 tolerance approach gives us the good report.Let’s try another single wall:
http://spiderinnet.typepad.com/.a/6a013489b64e31970c014e89e6fbb3970d-800wi
The same result: both the Epsilon and the == approaches report false but everybody can do the simple calculation that 20*6 really equals to 120.
Let’s try a short wall this time:
http://spiderinnet.typepad.com/.a/6a013489b64e31970c014e89e6fbf6970d-800wi
As can be seen, once again, the Epsilon case reports wrongly the same result as the == does, and the tolerance approach reports rightly true.
What about a long wall then? Here it is:
http://spiderinnet.typepad.com/.a/6a013489b64e31970c014e89e6fc41970d-800wi
Still the Epsilon way behaves badly the same as the == means, and the 1e-10 is the right way to go!So anything wrong with the Double.Epsilon?
Not at all.It is clearly stated in the MSDN documentation that the Double.Epsilon is designed for some other purpose and should not be used to compare double values as a general measure of precision.“The value of this constant is 4.94065645841247e-324.”“Represents the smallest positive Double value that is greater than zero. This field is constant.”Obviously too small is it!“However, the Epsilon property is not a general measure of precision of the Double type; it applies only to Double instances that have a value of zero. “As far as zero is concerned, the == operator may also just work.“The value of the Epsilon property is not equivalent to machine epsilon, which represents the upper bound of the relative error due to rounding in floating-point arithmetic.”So this epsilon is not that epsilon!Now it is clear that the Double.Epsilon should not be used for the double value comparison purpose regardless of in our own methods or in Revit API ones like:public FilterDoubleRule(
FilterableValueProvider valueProvider,
FilterNumericRuleEvaluator evaluator,
double ruleValue,
double epsilon
)Otherwise, it is not necessary to expose the tolerance setting to the outside world, is it? So that epsilon is not this epsilon either!
顶......
楼下跟上.....
谢谢老师…
顶起来…………
看看啥…………
页:
[1]