2
\$\begingroup\$

The code beyond approximates the error-function erf(x) with following formular \$erf(x)=1-(a_1t+a_2t^2+a_3t^3)e^{-x^2})\$ for \$x\geq0\$ inclusive the identity \$erf(-x)=-erf(x)\$.

  1. Is it okay to end the program in the middle of a code with exit(EXIT_FAILURE)? I just tried to avoid it and came to following solution, where the program always ends with return 0 at the end of the main-programm: https://codepaste.net/ek8ed5 So the question is whats's the more correct way?

(I hope a moderator can paste this code section in here please, because somehow I didn't make it work to show it as nicely formatted code, sorry!)

  1. What else can I improve?

.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define p 0.47047
#define a_1 0.3480242
#define a_2 -0.0958798
#define a_3 0.7478556


double ErrorFunction(double x);

int main(void)
{
  double x = 0;

  do
  {
    printf("Enter any value x to show erf(x): ");

    if (scanf_s("%lf", &x) != 1)
    {
      printf("error: invalid input\n");
      exit(EXIT_FAILURE);
    }
    else
    {
      printf("\n erf(x)=%f\n\n", ErrorFunction(x));
    }

  } while (x != 0);

  return 0;
}

double ErrorFunction(double x)
{
  double t = 0;

  if (x < 0)
  {
    x = -x;
    t = 1 / (1 + p*x);
    return -(1 - (a_1*t + a_2*t*t + a_3*t*t*t)*exp(-(x*x)));
  }
  else
  {
    t = 1 / (1 + p*x);
    return 1 - (a_1*t + a_2*t*t + a_3*t*t*t)*exp(-(x*x));
  }
}
\$\endgroup\$
3
\$\begingroup\$
  • DRY. Actual computations are repeated twice, which is always a signal for improvement:

    if (x < 0) {
        t = 1 / (1 - p*x);
    } else {
        t = 1 / (1 + p*x);
    }
    
    result = compute_the_formula(t, x);
    
    if (x < 0) {
        result = -result;
    }
    return result;
    
  • Try to cut down multiplications. Instead of

    a_1*t + a_2*t*t + a_3*t*t*t
    

    consider

    t*(a_1 + t*(a2 + t*a_3)))
    

    Three multiplications instead of original six is not only faster, but generally more accurate.

\$\endgroup\$
  • \$\begingroup\$ Thanks. 1. Actually I should really implement erf(-x)=-erf(x) according to this exercise. And it is also called identity. \$\endgroup\$ – physics Apr 18 '17 at 7:37
  • \$\begingroup\$ 2. I.e. the less multiplications you have the more accurate it is, because you have less rounding errors? \$\endgroup\$ – physics Apr 18 '17 at 7:44
  • \$\begingroup\$ 3. What do you say to my v1- and v2-main() in my starting post (codepaste.net)? \$\endgroup\$ – physics Apr 18 '17 at 7:44
2
\$\begingroup\$
double ErrorFunction(double x);

Would erf be a better name?


    if (scanf_s("%lf", &x) != 1)
      printf("\n erf(x)=%f\n\n", ErrorFunction(x));

Why the inconsistency between %lf and %f?


Following up on a comment you made to another answer:

Actually I should really implement erf(-x)=-erf(x) according to this exercise

The best way to do that from the point of view of 1) self-documenting code; 2) not accidentally breaking it in maintenance is

double ErrorFunction(double x)
{
  if (x < 0) return -ErrorFunction(-x);
  ...
\$\endgroup\$
  • \$\begingroup\$ Oh yeah that is good idea! So I only have one code line that computes my approximation instead ot two! 1. I didn't use erf as name, because I got this compiler warning: docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/… or is it ok to ignore this one? I thought that you always should avoid any compiler Warnings. (I use VS 2017) \$\endgroup\$ – physics Apr 18 '17 at 10:11
  • \$\begingroup\$ 2. I used %fin my printf, because it makes no difference to %lfby using it in a printf and I got the advice from here too: codereview.stackexchange.com/questions/160846/… (point 5) \$\endgroup\$ – physics Apr 18 '17 at 10:16
  • \$\begingroup\$ And when are you trying to use it on 'scanf' it won't work, because pointers aren't promoted to anything, but variables are. (stackoverflow.com/questions/210590/…) But I guess i should always stick to the same %? I. e. %lffor doubles, %ffor floats etc. \$\endgroup\$ – physics Apr 18 '17 at 10:17
  • \$\begingroup\$ @physics, 1. Makes sense that the logical name is already used. Still, I'd favour namespacing the name. In extremis, my_erf. 2. Fair enough. Gareth knows C better than I do. \$\endgroup\$ – Peter Taylor Apr 18 '17 at 10:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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