3

I was looking for satisfactory and safe workaround to my double precision issue specified to this problem:

enter image description here

This program tries to find how many small circle can fit into a large circle. It fills the large circle and then culls those that intersect the large circumference. using this formula:

distance_small_pos_from_center + small_radius < big_radius

All calculations were in double, except for screen output on WinForms which takes int for coords.

enter image description here

The above image shows the result of the culling. You can see that it is not symmetric when it should really be because the constraint is that there must be one small circle exactly in the center. I step through the code and find that this is because some calculations yield, for example,

99.9999999 < 100

This answer C++ double precision and rounding off says we should use all the precision available, but in this case, I had to do a Math.Round(distance_small_pos_from_center + small_radius, 3) using 3 arbitarily.

The result of the culling differs very much without Math.Round. In retrospect, this is one kind of bug that is hard to detect if I had not drawn it out. Maybe I did something wrong, or didn't understand doubles as much as I thought I had.

So, anyone has solutions or tips to avoid this kind of problem?

Community
  • 1
  • 1
Jake
  • 11,273
  • 21
  • 90
  • 147
  • 1
    My guess is that double can't represent 100 exactly. I suggest choosing a figure very close to 100 that double can represent and comparing against that. – George Duckett Nov 03 '11 at 08:23
  • 99.99999 < 100 was just one case I found out. If i set the large diameter to 600 and small diameter to 40 (increase by factor 2) the same problem happens. Since the input can be any decimal number, i think it is pretty hard to know when the issue will happen. – Jake Nov 03 '11 at 08:26
  • Actually, thinking about it i'm not sure what i said makes sense (since the 100 would be converted to a double to do the comparison anyway). Would be interested to hear other people's take on this. – George Duckett Nov 03 '11 at 08:27

2 Answers2

2

Sorry for not beeing able to provide a complete answer to your question, but i have no time for that right now. But when you compare floats, compare them with a "tolerance" since a float is not exact.

EDIT: modified with abs() in case you don't know which is big and small, as pointed out by Hans Kesting

Ie, do something like if(abs(big_radius - distance_small_pos_from_center) < epsilon) where epsilon is your tolerance, selected with consideration to how "inexact" the floats will be in the range where you are working..

For more precise information see:

http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm

http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html

http://www.cplusplus.com/forum/articles/3638/

Niclas
  • 1,220
  • 6
  • 12
  • I will post this link in the comment since spam protection only allowed two links in answer. It might be interesting to look at aswell.. http://www.cplusplus.com/forum/articles/3638/ – Niclas Nov 03 '11 at 08:36
  • Wouldn't this give the same issue? Effectively you're now doing `big_radius - distance_small_pos_from_center < 100 - SmallAmount`. He's said that 100 is an example number, all you're doing is replacing it with a different number. (I understand the principle you've applied, not sure it'd work though). – George Duckett Nov 03 '11 at 08:43
  • Okey, this was a simplified example and maybe i wasn't clear enough about that. What my code snippet above does is testing "big_radius" and "distance_small_pos_from_center" for equality, in a floating point sense. For this it will work, to solve the complete problem it will have to be slightly adapted.. But that should be easy once you understand the problem :) Edit - To clarify, test for equality, if not equal it's bigger or smaller, test that and you have answer. – Niclas Nov 03 '11 at 09:23
  • You'll need to add an "absolute" to that difference, so that "100" and "99.999" are considered "equal enough" no matter which of them is the "big radius". – Hans Kesting Nov 03 '11 at 10:19
0

Use System.Decimal:

http://msdn.microsoft.com/en-us/library/system.decimal.aspx

sq33G
  • 3,320
  • 1
  • 23
  • 38