[H]ow do I fix it once and for all for the entire Notebook?
I suppose it depends on how you want to treat results that contain round-off error. You cannot really get rid of the problem, only shift where the problem arises. For instance, in IntegerPart[x]
, IntegerPart
(nor usually the program/programmer) knows at that point whether the roundoff error that led to x
is positive, negative, or zero. If you fix IntegerPart[x]
when x
comes from a/a
and is one bit less than 1.
, then it will be broken when another x
has a roundoff error that increases it to one bit less than 1.
. One may be willing to live with it being broken in this way. Here's a way based on Equal
comparing with tolerance:
intPart // ClearAll;
intPart[x_?NumericQ] /; x == Round[x] := Round[x];
intPart[x_?NumericQ] := IntegerPart[x];
intPart[a/a]
(* 1 *)
Make it Listable
if your code relies on IntegerPart
being listable. You can change the tolerance used by Equal
with Internal`$EqualTolerance
.
Another approach is to "correct" real numbers that are close to integers:
snapToInteger // ClearAll;
snapToInteger[expr_] :=
expr /. {x_Real /; x == Round[x] :>
SetPrecision[Round[x], Precision[x]]};
IntegerPart[snapToInteger[a/a]]
(* 1 *)
Either approach is likely to incur a performance hit, which may or may not be important.
For what it's worth, this works on x = a/a
, because of the nature of the rounding error and how MatchQ
works on machine reals and bignums, and it's a bit faster:
intPart // ClearAll;
intPart[x_Real] /; MatchQ[x, N[Round[x], Precision[x]] :=
Round[x];
intPart[x_?NumericQ] := IntegerPart[x];
IntegerPart[Divide[a, a]]
. It has been noted before on this site that "a / a" is parsed asTimes[a, Power[a, -1]]
. The roundoff error in1 / a = 99999.99999999999
meansa * (1/a)
does not cancel (and sometimes doesn't for other values ofa
). $\endgroup$Table[a = 10.`16^-k; IntegerPart[a/a], {k, 100}]
. The use of arbitrary-precision means more bits than in machine precision are used to represent the floating-point numbers (plus precision tracking, which is unimportant here). All the extra precision does is change where the problem occurs. $\endgroup$