Let's say I have a function that consists solely of floating-point operations where the last operation rounds the computed value to a predefined number of digits. And I feed this function with a range of floats.
How do I conclude - just by looking at the decimals of the operand(s), and the structure of the code / sequence of floating-point calculations - that the round-up errors may or may not yield an unexpected result?
Do you know of any rule of thumb or mathematical methodology? Anything I can put to general use? I don't want to actually test the code.
Just one example for reference; range of input, required precision, and implementation of calc() are arbitrary:
Input: 0, 0.01, 0.02 ... 999.98, 999.99, 1000 (delta = 0.01)
Required precision: Rounded accurately to 2nd decimal
Pseudo code:
function main(a) {
res = calc(a);
return round(res); // Rounds res to desired decimals
}
function calc(a) {
float b = 1.1;
return a * b;
}
Update #1:
I found an interesting blogpost on the topic: Introduction to Scientific Computing: Error Propagation
It seems to contain the mathematical tools one needs to evaluate how "error prone" a computation is.
Update #2:
I worked out the following method to estimate the error propagation and will describe how I applied it on my use case.
It would be great if you comment on my thoughts. I'm not sure if I did it right. And thanks for your help so far! :)
Pseudo code:
// Floats conform to IEEE 547
function main() {
float a,b; // Real value between 199 and 684
a = some_value;
b = another_value;
res_a = calc(a);
res_b = calc(b);
res = res_a + res_b;
return round(res); // Rounds to 2nd decimal
}
function calc(x) {
float c = yet_another_value; // Real value between 1 and 1.4
return c * x;
}
Estimation:
- As I'm using IEEE 547 floats, the machine epsilon ε is 1.1e-16.
- The relative error δ is 2ε - according to the article linked under update #1.
- So the absolute error of my maximal input emax won't exceed 3.8304e-13. *
- That means the result will be precise up to the 12th decimal.
- Since I just desire a precision of 2, the calculation does work precisely enough.
*) emax = 2ε * resmax = 2 * 1.1e-16 * 2 * 684 * 1.4 = 3.8304e-13.
Bonus consideration:
Q: Would one add up the results of calc() infinitely, how many results would be "needed" approximately to contaminate the rounded total?
A: One would have to call calc() at least 4 trillion times. \o/
- e has to be at least 0.001 to force a round-up error
- The maximum result of calc() is xmax = 684 * 1.4 = 957.6
- e = δ * x => x = e / δ = e / 2ε = 1e-3 / (2 * 1.1e-16) = 1e+13 / 2.2
- n = x / xmax = 1e+13 / (2.2 * 957.6) ≈ 4e+9