It is the same as trying to store 1/3 = 0.333... as a finite decimal. Basically, a floating point number only has a finite space to put the component after the decimal point, so it gets truncated and made inaccurate, just like truncating 1/3 to 0.3333 will mean that calculations become wrong: 3*0.3333 = 0.9999 ≠ 1.
By the by, for typical MD processing, as long as you're using sensible units you shouldn't need to worry about floating point precision. Just don't use SI units, because then you might end up with some very very small numbers and that's when it'll start to bite you!
This is how easy that is:
(Note: it appears the horizontal scroll bar for this code is hidden by default for OS X browsers.)
eigenvalues = require 'eigenvalues.js'
regressCoordinatesToNormal = (coords) ->
min = (array) ->
array.reduce ((x, y, i) -> if x.val < y then x else {index: i, val: y}), {index: null, val: Infinity}
centerOfMass = (coords) ->
coords.reduce ((x, y) -> (x[i] + (y[i] / coords.length) for v, i in y)), [0, 0, 0]
normalUnitVector = (coords) ->
c = centerOfMass coords
matrix = for row in [0..2]
for col in [0..2]
((coord[row] - c[row]) * (coord[col] - c[col]) for coord in coords).reduce (x, y) -> x + y
results = eigenvalues.calculateEigenvalues matrix
results.eigenvectors[min(results.real).index]
normalUnitVector coords
This code just takes in a list of coordinates and performs a linear plane regression on them to return the normal vector of the plane. Then if I want the vertical distance between two planes of atoms (these are circular planes that kind of wobble around), then it's just: normals = (regressCoordinatesToNormal coords for coords in planes)
planeToPlaneVector = distanceVector planeCenterOfMass[0], planeCenterOfMass[1]
projectionDistance = dotProduct planeToPlaneVector, normals[0]
I left out some details, but you can get the gist of it.In your browser console, run: 0.3 + 0.544 You'll get back 0.8440000000000001
In practice (especially if in the browser), the difference is either irrelevant (in CSS 1px == 1.1px) or not significant. But in accumulation, it could be problematic.
$ erl
1> 0.2 + 0.1.
0.30000000000000004
2> 0.94 - 0.01.
0.9299999999999999
3> 0.3 + 0.544.
0.8440000000000001
$ irb
1.9.2-p290 :001 > 0.2 + 0.1
=> 0.30000000000000004
1.9.2-p290 :002 > 0.94 - 0.01
=> 0.9299999999999999
1.9.2-p290 :003 > 0.3 + 0.544
=> 0.8440000000000001
1.9.2-p290 :004 >You use something like:
fabs( a-b ) < epsilon
where epsilon is usually defined by the language as a very small quantity (example values in C are 1E-8 for a float, 1E-15 for double), or you can just use a hard coded value appropriate to the values you are comparing.x == y
and
|x - y| < epsilon
As I said, things get worse if your comparison is between larger numbers. For example, the smallest double larger than 1024 is 1024+1024 epsilon (IIRC; I am too lazy to double-check that now)
The epsilon used in numerical algorithms is an entirely different beast than the machine epsilon.
That epsilon you should pick as follows: make a numerical analysis of your problem, choose a good algorithm, and determine the desired accuracy of your answer. From those, derive a (relative, absolute, whatever) error you can live with.
Alternatively, pick a reasonable value from thin air and hope for the best/test your code to get confidence that it will return good values (do not do this when programming flight control software, pacemakers, etc). Oftentimes, it is not really hard to produce a reasonable value. For example, an iterative procedure that produces pixel coordinate likely can stop once the absolute error is less than .01 pixel, and possibly a lot earlier.
Finally, in the ideal world, you will use a good way to test for your accuracy, for example one from boost test: http://www.boost.org/doc/libs/1_52_0/libs/test/doc/html/utf/... (contains useful links to more in-depth discussions)
And, by the way, 1E-8 is lower than the machine epsilon for floats, and 1E-15 larger than that for doubles. http://en.wikipedia.org/wiki/Machine_epsilon gives them as 1.2E-7, respectively 2.2E-16.
Although, could someone clarify for me the floating point issues mentioned by Steve? I wasn't aware there were issues...