File indexing completed on 2024-05-12 03:47:52
0001 /* 0002 File : nsl_int.c 0003 Project : LabPlot 0004 Description : NSL numerical integration functions 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2016 Stefan Gerlach <stefan.gerlach@uni.kn> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 /* TODO: 0012 * absolute area for Simpson/Simpson-3/8 rules (needs more numerics) 0013 */ 0014 0015 #include "nsl_int.h" 0016 #include "nsl_common.h" 0017 #include "nsl_sf_poly.h" 0018 0019 const char* nsl_int_method_name[] = {i18n("Rectangle (1-point)"), i18n("Trapezoid (2-point)"), i18n("Simpson's (3-point)"), i18n("Simpson's 3/8 (4-point)")}; 0020 0021 int nsl_int_rectangle(const double* x, double* y, const size_t n, int abs) { 0022 if (n == 0) 0023 return -1; 0024 0025 size_t i, j; 0026 double sum = 0, xdata[2]; 0027 for (i = 0; i < n - 1; i++) { 0028 for (j = 0; j < 2; j++) 0029 xdata[j] = x[i + j]; 0030 double s = nsl_sf_poly_interp_lagrange_0_int(xdata, y[i]); 0031 if (abs) 0032 s = fabs(s); 0033 y[i] = sum; 0034 sum += s; 0035 } 0036 y[n - 1] = sum; 0037 0038 return 0; 0039 } 0040 0041 int nsl_int_trapezoid(const double* x, double* y, const size_t n, int abs) { 0042 if (n < 2) 0043 return -1; 0044 0045 size_t i, j; 0046 double sum = 0, xdata[2], ydata[2]; 0047 for (i = 0; i < n - 1; i++) { 0048 for (j = 0; j < 2; j++) 0049 xdata[j] = x[i + j], ydata[j] = y[i + j]; 0050 y[i] = sum; 0051 if (abs) 0052 sum += nsl_sf_poly_interp_lagrange_1_absint(xdata, ydata); 0053 else 0054 sum += nsl_sf_poly_interp_lagrange_1_int(xdata, ydata); 0055 } 0056 y[n - 1] = sum; 0057 0058 return 0; 0059 } 0060 0061 size_t nsl_int_simpson(double* x, double* y, const size_t n, int abs) { 0062 if (n < 3) 0063 return 0; 0064 if (abs != 0) { 0065 printf("absolute area Simpson rule not implemented yet.\n"); 0066 return 0; 0067 } 0068 0069 size_t i, j, np = 1; 0070 double sum = 0, xdata[3], ydata[3]; 0071 for (i = 0; i < n - 2; i += 2) { 0072 for (j = 0; j < 3; j++) 0073 xdata[j] = x[i + j], ydata[j] = y[i + j]; 0074 0075 sum += nsl_sf_poly_interp_lagrange_2_int(xdata, ydata); 0076 y[np] = sum; 0077 x[np++] = (x[i] + x[i + 1] + x[i + 2]) / 3.; 0078 /*printf("i/sum: %zu-%zu %g\n", i, i+2, sum);*/ 0079 } 0080 0081 /* handle possible last point: use trapezoid rule */ 0082 if (i == n - 2) { 0083 for (j = 0; j < 2; j++) 0084 xdata[j] = x[i + j], ydata[j] = y[i + j]; 0085 sum += nsl_sf_poly_interp_lagrange_1_int(xdata, ydata); 0086 y[np] = sum; 0087 x[np++] = x[i]; 0088 } 0089 0090 /* first point */ 0091 y[0] = 0; 0092 0093 return np; 0094 } 0095 0096 size_t nsl_int_simpson_3_8(double* x, double* y, const size_t n, int abs) { 0097 if (n < 4) { 0098 printf("minimum number of points is 4 (given %d).\n", (int)n); 0099 return 0; 0100 } 0101 if (abs != 0) { 0102 printf("absolute area Simpson 3/8 rule not implemented yet.\n"); 0103 return 0; 0104 } 0105 0106 size_t i, j, np = 1; 0107 double sum = 0, xdata[4], ydata[4]; 0108 for (i = 0; i < n - 3; i += 3) { 0109 for (j = 0; j < 4; j++) 0110 xdata[j] = x[i + j], ydata[j] = y[i + j]; 0111 0112 sum += nsl_sf_poly_interp_lagrange_3_int(xdata, ydata); 0113 y[np] = sum; 0114 x[np++] = (x[i] + x[i + 1] + x[i + 2] + x[i + 3]) / 4.; 0115 /*printf("i/sum: %zu-%zu %g\n", i, i+3, sum);*/ 0116 } 0117 0118 /* handle possible last point(s): use trapezoid (one point) or simpson rule (two points) */ 0119 if (i == n - 2) { 0120 for (j = 0; j < 2; j++) 0121 xdata[j] = x[i + j], ydata[j] = y[i + j]; 0122 sum += nsl_sf_poly_interp_lagrange_1_int(xdata, ydata); 0123 y[np] = sum; 0124 x[np++] = x[i]; 0125 } else if (i == n - 3) { 0126 for (j = 0; j < 3; j++) 0127 xdata[j] = x[i + j], ydata[j] = y[i + j]; 0128 sum += nsl_sf_poly_interp_lagrange_2_int(xdata, ydata); 0129 y[np] = sum; 0130 x[np++] = (x[i] + x[i + 1] + x[i + 2]) / 3.; 0131 } 0132 0133 /* first point */ 0134 y[0] = 0; 0135 0136 return np; 0137 }