8
$\begingroup$

What is the most stable way to compute $$\frac{x - y}{x - z}$$ when $x$, $y$, and $z$ are all close to each other? I would like to compute expressions of this form in low precision on a GPU, but when I do so, I find that rounding errors really mess up the computation.

A straightforward implementation subtracts two numbers that are close to each other, and divides two numbers that are near zero. Neither of these operations is advisable.

I played around with the expression for a bit, trying to find a mathematical transformation that gives the same result without doing questionable numerical operations. However, couldn't figure out any good transformations.

$\endgroup$
1

2 Answers 2

13
$\begingroup$

If your inputs are $x,y,z$, this computation is not unstable, but ill-conditioned. That's worse, because it means that a small change in your input (such as a previous approximation as a floating-point number) causes a large change in your output.

In practical terms, this means that this is the wrong subproblem to focus on. If all you have is $x,y,z$ stored as floating point numbers, then you have already lost the battle.

Either you have some more properties on $x,y,z$ (such as them coming from a finite difference, see my question linked in a comment by NNN, or there is no hope of obtaining an accurate result.

$\endgroup$
2
  • $\begingroup$ If @Nick Alger has only $x,y,z$ stored as floating point numbers, perhaps the only thing that could help is an arbitrary precision library. $\endgroup$
    – NNN
    Commented Sep 11 at 9:04
  • 6
    $\begingroup$ @NNN Not really, you have already lost. If your true data are x=1 and y=1.0000000000000123456789, but you only have access to their floating point approximations xfp=1 and yfp=1.00000000000001, no arbitrary precision library can ever recover those 23456789 digits because it does not have access to them in the first place. OP needs to consider this problem together with the previous steps, not just as a separate problem. Maybe those x,y come from a finite difference? Then there are tricks that could help. $\endgroup$ Commented Sep 11 at 10:37
1
$\begingroup$

Main source of instability here is that when all numbers are very close to each other,- expression approaches indeterminate form $\frac 00$. Add GPU rounding errors and it becomes obvious why you get unstable results. We can't get rid much of floating point rounding errors, because it's built-in into GPU floating point format, but we can try to get rid of indeterminate form mathematical uncertainty. For that try to compute expression $$ \frac {1}{1-z/x} - \frac {y}{x-z} ,$$

which is mathematically equivalent to your given one, but is more stable, because now you will not have indeterminate forms $0/0$, assuming $y \neq 0$ and $z \neq 0$.

As a test shot, I have tried such variables,

x=1.00010000521010  
y=1.00010000521020  
z=1.00010000521030

Then I have changed $x$ accordingly ,

|       x        |
|----------------|
|1.00010000521015|
|1.00010000521018|
|1.00010000521019|

Then I have noticed that relative error between steps of old and new expressions differs radically :

|   Err_Old (%)   |   Err_New (%)   |
|-----------------|-----------------|
|33.4072431633408 | 33.4814814817031|
|49.9999999999999 | 24.9999999997805|
|45.4545454545456 | 9.09090909099427|

Which shows that second expression converges gracefully, while original one- jumps in error and later re-considers back.

Note: do not expect black magic here, because these may be false result, due to not enough points taken (I have played with LibreCalc, so...). Besides results may depend on exact $x,y,z$ values taken and how they converges. In addition , GPU floating point inaccuracy may even spoil this small advantage. However, worth a try.

HTH!

$\endgroup$
8
  • $\begingroup$ Thanks! I tried this now in my example. It helped a little bit, but not enough. $\endgroup$
    – Nick Alger
    Commented Sep 12 at 20:20
  • $\begingroup$ Good to hear. Well, progress goes on with little-by-little, radical optimizations are rare. It would be interesting if you could run your calculations on CPU and compare results with GPU, to check the root cause of problems,- maybe you have reached GPU rounding limits ? $\endgroup$ Commented Sep 13 at 6:17
  • 1
    $\begingroup$ Yes it is definitely the GPU rounding. I've been running the same thing on CPU for a while, and only encountered these problem now that I am moving it to the GPU. $\endgroup$
    – Nick Alger
    Commented Sep 13 at 17:22
  • $\begingroup$ Try to run GPU computations in double-precision mode or you are out-of-luck. Also since this is a particular hardware issue, I would recommend posting your problem to some GPU manufacturer site like, nvidia forum and the likes. $\endgroup$ Commented Sep 13 at 21:49
  • $\begingroup$ Per the answer of Federico Poloni, I think I this is a theoretical issue with what I am doing, not really a problem with the hardware. I have tried in double precision on the GPU and it works just fine (the same as CPU). The downside is that doing double precision on the GPU makes it much slower. $\endgroup$
    – Nick Alger
    Commented Sep 13 at 22:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.