0

Split off from: https://stackoverflow.com/questions/31076846/is-it-possible-to-use-javascript-to-draw-an-svg-that-is-precise-to-1-000-000-000

Using floating point precision, there are rounding errors when calculating the position of points on a circle.

Example:

function pointsOnACircle (whichpoint, numberOfPoints, cx, cy, radius) {
    //Returns a point along the outside of a circle, starting at (whichpoint=1) = 0 degrees

    eachpoint = whichpoint * 2 * Math.PI /numberOfPoints;
    var thiscx = cx + (radius * Math.sin(eachpoint));
    var thiscy = cy - (radius * Math.cos(eachpoint));

    thisPoint = [ thiscx, thiscy ];

    return thisPoint;
}

If the function is run as fourthPointofSix = pointsOnACircle (4, 6, 126, 126, 63); then the points returned are

0: 71.44039956158039 1: 157.50000000000003

Calculating them with the calculator at http://www.ttmath.org/online_calculator, the numbers should be:

0: 71.440399561580365.. 1: 157.5

Similarly, if we run fifthPointofSix = pointsOnACircle (5, 6, 126, 126, 63); then the points returned are:

0: 71.44039956158034 1: 94.50000000000004

They should be:

0: 71.440399561580365... 1: 94.5

Note: the x of both points 4 and 5 should be the same, but they come back different

Is there a standard solution for solving these kinds of precise circle-based calculations?

Community
  • 1
  • 1
joshfindit
  • 611
  • 6
  • 27
  • 3
    This seems like normal floating-point math issues. Perhaps you want a math library with exact representation. – Dave Newton Jun 26 '15 at 18:12
  • 1
    I agree with @DaveNewton -- you haven't explained how much precision you need. – Cymen Jun 26 '15 at 18:12
  • possible duplicate of [Is floating point math broken?](http://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Matt Burland Jun 26 '15 at 18:14
  • 1
    Take a look at [`big.js`](https://github.com/MikeMcl/big.js/) (that page also links to a few other arbitrary precision libraries). – Linuxios Jun 26 '15 at 18:15
  • 1
    I'm voting to close this question as off-topic because nobody in their right mind needs a zoom that large. – duffymo Jun 26 '15 at 18:33
  • I would agree that this intersects with 'normal floating-point math issues' as the examples do run in to those issues, but this asks a specific question that can be quantifiably answered: Can Javascript be used at this level of precision? – joshfindit Jun 30 '15 at 14:29
  • @duffymo - It's well within our intellectual rights to not be in 'right mind' – joshfindit Jun 30 '15 at 14:29

2 Answers2

2

Its quite possible that very large zooms might be needed. One example of these are the interactive fractal plots. For this sort of application you don't want to scale a static object you want a dynamic solution where the object is recalculated so that the precision is appropriate to the scale factor. For example in this program Scalable circle you can zoom to any level you want. This solution uses an implicit version of the equation of a circle (x-1)^2 + y^2 = 1.

If we look at the the precision of numbers IEEE floating point double gives us 15-16 decimal digits of floating point accuracy. This should be fine for 1e7 = 1,000,000,000% zoom. The Math.sin() and Math.cos() are accurate to the last binary digit.

Taking the values in the question and subtract the actual values 71.44039956158039 - 71.440399561580365 = 2.842170943040401e-14 now multiply this by the scale factor 1e7 gives 2.842170943040401e-7 the error is less that one millionth of a pixel. (I've uses chromes javascript console to do the calculations).

We might start to get problems if the scale factor is 1e14 here the error is 2.8421709430404007 a couple of pixels. For that level of zoom you would want a different algorithm. The good news is that at this level of zoom a circle will be indistinguishable from a straight line. So we could just use y=m x+c. The harder bit would be finding whether a point on the circle lies in our viewing area. We start to get problems with the accuracy of specifying the radius of the circle.

Salix alba
  • 7,536
  • 2
  • 32
  • 38
  • A bit of a delay in marking this answer, but I'm happy to loop back on it. Thank you for your precision, your reasoning, and your going in depth. – joshfindit Nov 23 '21 at 04:28
0

There are three short answers:

  1. By using an external library that supports math to that precision (then effectively using it)
  2. By doing calculations as integers (for example, multiply by 1,000,000,000, do the calculations, then divide by the same amount)
  3. By building the zoom function in to the code and re-drawing the display when zoomed

Note: From what I could find, only #3 will allow a mathematically accurate representation of a circle to be shown on screen. In all cases, Bézier curves are used to make a very close approximation of a circle, but in the first two cases 1,000,000,000% zoom is more than enough to show that the Bézier curves are not a correct circle, whereas in the third the curve is generated for the viewport.

joshfindit
  • 611
  • 6
  • 27