How to disable roundoff error tracking in arbitrary precision arithmetic?

In my calculations I need some larger precision. But due to the fact that I iteratively refine the results to compensate for rounding errors accumulated in previous iteration, Mathematica's arbitraty precision arithmetic's roundoff error tracker kills all the results by converting them to effective zero — I can't even divide by such result without getting divide-by-zero error.

In my application a completely wrong intermediate result is much better (and is actually expected) than no result as I get with error tracking. I've tried using SetPrecision[] at some places in calculation, but in some cases I have to do it in many places, which makes the code unreadable.

So, is there any way to just get additional precision, but without tracking roundoff errors?

• I can't picture a case in which your desired behavior would be desirable. Could you provide a minimal example of your specific application? – MarcoB Nov 2 '16 at 16:24
• So you just want to use a fixed and pre-determined number of digits in all calculations, and you want to avoid truncating the number of digits after each operation? And you need more than 15 digits? – Szabolcs Nov 2 '16 at 18:51
• @Szabolcs yes. Basically what e.g. x87's tbyte or IEEE 754's binary128 formats would provide, but potentially with even more precision and range. – Ruslan Nov 2 '16 at 18:55
• How important is performance? I am looking at the ComputerArithmetic package for the first time and it's quite interesting. It lets you define a number format and "arithmetic" with specific rules, then do calculations with it. I would expect it to be slow but I haven't tested how slow exactly. – Szabolcs Nov 2 '16 at 18:58
• @Szabolcs there is now a good answer. – Ruslan Nov 3 '16 at 20:16

There are a few reasonable ways. I'll illustrate with an example of Newton iterations for square roots, take from this MathGroup post

r[x_, n_] := x - (x^2 - n)/(2*x)
x = 1.020;
two = 2.020;

First we run it with the usual arithmetic.

Table[x = r[x, two], {30}]

(* Out[680]= {1.4142135623730950488, 1.4142135623730950488, \
1.414213562373095049, 1.414213562373095049, 1.414213562373095049, \
1.41421356237309505, 1.41421356237309505, 1.41421356237309505, \
1.4142135623730950, 1.4142135623730950, 1.4142135623730950, \
1.4142135623730950, 1.414213562373095, 1.414213562373095, \
1.414213562373095, 1.41421356237310, 1.41421356237310, \
1.41421356237310, 1.4142135623731, 1.4142135623731, 1.4142135623731, \
1.4142135623731, 1.414213562373, 1.414213562373, 1.414213562373, \
1.41421356237, 1.41421356237, 1.41421356237, 1.4142135624, \
1.4142135624} *)

We can force fixed precision as below. I'll just show a few iterations.

x = 1.020; NumericalMathFixedPrecisionEvaluate[
Table[x = r[x, two], {10}], 20]

(* Out[681]= {1.5000000000000000000, 1.4166666666666666667, \
1.4142156862745098039, 1.4142135623746899106, 1.4142135623730950488, \
1.4142135623730950488, 1.4142135623730950488, 1.4142135623730950488, \
1.4142135623730950488, 1.4142135623730950488} *)

Alternatively, use SetPrecision explicitly to reset upward.

x = 1.020;
Table[x = SetPrecision[r[x, two], 20], {10}]

(* Out[683]= {1.5000000000000000000, 1.4166666666666666667, \
1.4142156862745098039, 1.4142135623746899106, 1.4142135623730950488, \
1.4142135623730950488, 1.4142135623730950488, 1.4142135623730950488, \
1.4142135623730950488, 1.4142135623730950488} *)

Last is to temporarily set min and max precisions to be equal. Block is good for this type of localized assignment.

x = 1.020;
Block[{$MinPrecision = 20,$MaxPrecision = 20},
Table[x = r[x, two], {10}]]

(* Out[685]= {1.5000000000000000000, 1.4166666666666666667, \
1.4142156862745098039, 1.4142135623746899106, 1.4142135623730950488, \
1.4142135623730950488, 1.4142135623730950488, 1.4142135623730950488, \
1.4142135623730950488, 1.4142135623730950488} *)
• This is great! A caveat with SetPrecision is that if the result has zero digits of precision, it'll give very precise zero instead of what you'd get with FixedPrecisionEvaluate: see e.g. SetPrecision[((22^21)^21)^21, 10]. – Ruslan Nov 3 '16 at 20:13
• Right. SetPrecision as used above is intentionally subverting the precision tracking system, so it should be done only in situations where one knows it is appropriate. – Daniel Lichtblau Nov 3 '16 at 20:22