Search code examples
mathfloating-pointaveragelinear-algebranumerical

Compute average precision


I am computing the number of significant digits, two numbers have the same. However, the function I have written, will return a big value when the numbers are equal. As a result, the average result is not representative enough, as I will show below.

Here is the code:

#include <iostream>
#include <cmath>

double calc_error(double a,double x) {
  return std::abs(x-a)/std::abs(a);
}

int significant(double err) {
    int s = -1;
    do {
        ++s;
    } while(err < pow(5, -s));
    return s;
}

int main(void) {
  double sans[]={-250207683.634793,-1353198687.861288,2816966067.598196,-144344843844.616425, 323890119928.788757};
  double pans[]={-250207683.634692, -1353198687.861386, 2816966067.598891, -144344843844.617096, 323890119928.788757};
  double err[5];
  double avg_err = 0;
  int avg_significant = 0;
  std::cout<<"Serial Answer,Distributed Answer, Error, Significant digits"<<std::endl;
  for (int it=0; it<5; it++) {
    err[it]=calc_error(sans[it], pans[it]);
    avg_err += err[it];
    avg_significant += significant(err[it]);
    std::cout<<sans[it]<<","<<pans[it]<<","<<err[it]<<","<<significant(err[it])<<"\n";
  }
  std::cout << "avg_error: " << avg_err/5 << ", avg_sign:" << avg_significant/5 << "\n";
}

and check the output:

Serial Answer,Distributed Answer, Error, Significant digits
-2.50208e+08,-2.50208e+08,4.03665e-13,18
-1.3532e+09,-1.3532e+09,7.24136e-14,19
2.81697e+09,2.81697e+09,2.46631e-13,19
-1.44345e+11,-1.44345e+11,4.65127e-15,21
3.2389e+11,3.2389e+11,0,463
avg_error: 1.45472e-13, avg_sign:108

In my real application, I have many numbers, thus I should provide something representative. How would you do it? An idea that came up while writing this post, is to count how many cases (i.e. pair of numbers) had 18 (for example) significant digits equal, how many 17 and so on, but I fear that the spread might be much.


Solution

  • Two choices, depending on how you want to handle identical values, either pretty much involves treating significant(0) as a special case, and returning 0.

    Then it's up to you whether or not you include these 0's in the average or not; if you don't, simply divide by the number where the significant function is not 0 instead of 5.