It is worth noting that issues such as this are not specific to AutoLISP or indeed any programming language, but rather apply to computing in general.
This issue arises because a computer has finite memory in which data may be stored, and consequently not all numbers can be represented exactly, but instead must be approximated and stored in an agreed format (specifically, in this case, the
double-precision floating-point format, or simply 'double') which has inherent compromises at the extent of its precision in order to be useful under a wide range of applications (i.e. affording an ability to represent both very large numbers (to an order of magnitude of 1e308) with low precision, and very small numbers with high precision).
Just as one third cannot be represented exactly in base 10 [decimal] (instead yielding the infinitely recurring decimal 0.333...
10) but can be represented exactly in base 3 (as 0.1
3), there are many numbers which equally cannot be represented exactly in base 2 [binary], and indeed, the same would arise for any chosen base.
As a result of this hard limit on the level of precision to which any number may be stored,
arithmetic errors begin to creep into calculations where rounding occurs at the very limit of precision for almost every calculation, and such infinitesimal errors propagate with repeated & compound calculations.
In your particular example, we see that performing the subtraction of the integer from the double, followed by a multiplication by the double 10000.0 introduces an infinitesimal rounding error at the limit of precision of the double, which may be observed by converting the double to a string using the
rtos function:
_$
(rtos sub
-deg
-10000 2 20)"3455.999999999992"
Now, since the
fix function merely removes the fractional component of the data to yield an integer value, the introduction of this rounding error will cause the function to return 3455 instead of 3456.
As such, when working with doubles, we must always account for the possibility of rounding and always include a 'fuzz factor' or tolerance when performing any operation which will either attempt to yield an exact value (such as the use of the
fix function), or compare a double with an exact value (such as you might with the
= operator when comparing two integers).
In this case, I would suggest the following (you may decide to opt for a smaller tolerance, such as 1e-12):
_$
(fix (+ sub
-deg
-10000 1e
-8
))3456
Or, where a comparison is concerned, the use of the
equal function with an appropriate tolerance:
_$
(equal 3456 sub
-deg
-10000 1e
-8
)T