This one doesn't work
double majorTickStart = majorStep * Math.Floor(min / majorStep); double majorTickEnd = majorStep * Math.Floor(max / majorStep); for (double x = majorTickStart; x <= majorTickEnd; x += majorStep) { Point p1 = new Point((x - min) * scale, 0); Point p2 = new Point((x - min) * scale, 16); drawingContext.DrawLine(majorTickPen, p1, p2); }
This one does work
double majorTickStart = majorStep * Math.Floor(min / majorStep); double majorTickEnd = majorStep * Math.Floor(max / majorStep); double majorSteps = (majorTickEnd - majorTickStart); for (double x = 0; x <= majorSteps; x += majorStep) { double _x = (x + (majorTickStart - min)) * scale; Point p1 = new Point(_x, 0); Point p2 = new Point(_x, 16); drawingContext.DrawLine(majorTickPen, p1, p2); }If you look closely that math turns out to be the same on both of them. What this is meant to do is draw the tick marks you would see on a graph along the axis. The first two lines compute the offsets of where to start and stop drawing tick marks, since the beginning value, "min", doesn't necessarily start on a boundary. Next the for loop will iterate between those two values with a step size of, "majorStep". This would normally be a power of 10.
The problem the happens is the first set of code turns into an infinite loop under certain conditions. If "majorsStep" is small compared to the start and end values, x will never increase. "small" means that there is more than 52bits of precision between the two of them. In other words a factor of more that 4503599627370496. This has to do with how a computer stores an IEEE754 (64 bit double) number. It stores it using 1 bit sign, 11bit exponent , and 52bit fractional. To get the number it represents 2 raise to the power of the exponent times the fractional bits. Stated another way the exponent is the number of bits that are ignored. If it takes more than 52 bits to represent the number, you will lose the lower E bits of accuracy. Adding 1 to your 53 bit number will result in the lowest bit being ignore, and this the 1 turns into a 0.
How do you fix this? Make sure you do all your math with numbers that are close to each other. The second one works because we start "x" at 0 and add the small value of "majorStep" to it. We also subtract "min" from "majorTickStart" to get a small value before we add it to x, which will also be small. If we tried to add "x" to "majorTickStart" and then subtract "min" we would end up with just "majorTickStart - min", because the value in x would be ignored.