简体   繁体   中英

Simpson's Composite Rule giving too large values for when n is very large

Using Simpson's Composite Rule to calculate the integral from 2 to 1,000 of 1/ln(x) , however when using a large n (usually around 500,000 ), I start to get results that vary from the value my calculator and other sources give me ( 176.5644 ). For example, when n = 10,000,000 , it gives me a value of 184.1495 . Wondering why this is, since as n gets larger, the accuracy is supposed to increase and not decrease.

#include <iostream>
#include <cmath>

// the function f(x)
float f(float x)
{
    return (float) 1 / std::log(x);
}




float my_simpson(float a, float b, long int n)
{
  if (n % 2 == 1) n += 1; // since n has to be even
  float area, h = (b-a)/n;


  float x, y, z;
  for (int i = 1; i <= n/2; i++)
  {
    x = a + (2*i - 2)*h;
    y = a + (2*i - 1)*h;
    z = a + 2*i*h;
    area += f(x) + 4*f(y) + f(z);
  }

  return area*h/3;
}



int main()
{
    std::cout.precision(20);
    int upperBound = 1'000;
    int subsplits = 1'000'000;

    float approx = my_simpson(2, upperBound, subsplits);

    std::cout << "Output: " << approx << std::endl;

    return 0;
}

Update: Switched from floats to doubles and works much better now! Thank you!

Unlike a real (in mathematical sense) number, a float has a limited precision.

A typical IEEE 754 32-bit (single precision) floating-point number binary representation dedicates only 24 bits (one of which is implicit) to the mantissa and that translates in roughly less than 8 decimal significant digits (please take this as a gross semplification).

A double on the other end, has 53 significand bits, making it more accurate and (usually) the first choice for numerical computations, these days.

since as n gets larger, the accuracy is supposed to increase and not decrease.

Unfortunately, that's not how it works. There's a sweat spot, but after that the accumulation of rounding errors prevales and the results diverge from their expected values.

In OP's case, this calculation

area += f(x) + 4*f(y) + f(z);

introduces (and accumulates) rounding errors, due to the fact that area becomes much greater than f(x) + 4*f(y) + f(z) (eg 224678.937 vs. 0.3606823). The bigger n is, the sooner this gets relevant, making the result diverging from the real one.

As mentioned in the comments, another issue (undefined behavior) is that area isn't initialized (to zero).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM