File indexing completed on 2024-05-12 03:47:52
0001 /* 0002 File : nsl_math.c 0003 Project : LabPlot 0004 Description : NSL math functions 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2018-2024 Stefan Gerlach <stefan.gerlach@uni.kn> 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "nsl_math.h" 0011 #include <gsl/gsl_math.h> 0012 #include <stdio.h> 0013 0014 bool nsl_math_approximately_equal(double a, double b) { 0015 return nsl_math_approximately_equal_eps(a, b, 1.e-7); 0016 } 0017 0018 bool nsl_math_approximately_equal_eps(double a, double b, double epsilon) { 0019 return fabs(a - b) <= ((fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon); 0020 } 0021 0022 bool nsl_math_essentially_equal(double a, double b) { 0023 return nsl_math_essentially_equal_eps(a, b, 1.e-7); 0024 } 0025 0026 bool nsl_math_essentially_equal_eps(double a, double b, double epsilon) { 0027 return fabs(a - b) <= ((fabs(a) > fabs(b) ? fabs(b) : fabs(a)) * epsilon); 0028 } 0029 0030 bool nsl_math_definitely_greater_than(double a, double b) { 0031 return nsl_math_definitely_greater_than_eps(a, b, 1.e-7); 0032 } 0033 0034 bool nsl_math_definitely_greater_than_eps(double a, double b, double epsilon) { 0035 return (a - b) > ((fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon); 0036 } 0037 0038 bool nsl_math_definitely_less_than(double a, double b) { 0039 return nsl_math_definitely_less_than_eps(a, b, 1.e-7); 0040 } 0041 0042 bool nsl_math_definitely_less_than_eps(double a, double b, double epsilon) { 0043 return (b - a) > ((fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon); 0044 } 0045 0046 double nsl_math_frexp10(double x, int* e) { 0047 int expo = 0; 0048 if (x != 0) 0049 expo = floor(log10(fabs(x))); 0050 0051 if (e != NULL) 0052 *e = expo; 0053 0054 return x / gsl_pow_int(10., expo); 0055 } 0056 0057 /* rounding methods */ 0058 0059 int nsl_math_decimal_places(double value) { 0060 return -(int)floor(log10(fabs(value))); 0061 } 0062 0063 int nsl_math_rounded_decimals(double value) { 0064 int places = nsl_math_decimal_places(value); 0065 0066 // printf("places = %d, rv = %g\n", places, round(fabs(value) * pow(10, places))); 0067 if (round(fabs(value) * gsl_pow_int(10., places)) >= 5.) 0068 places--; 0069 0070 return places; 0071 } 0072 0073 int nsl_math_rounded_decimals_max(double value, int max) { 0074 return GSL_MIN_INT(max, nsl_math_rounded_decimals(value)); 0075 } 0076 0077 double nsl_math_round_places(double value, int n) { 0078 return nsl_math_places(value, n, 0); 0079 } 0080 double nsl_math_floor_places(double value, int n) { 0081 return nsl_math_places(value, n, 1); 0082 } 0083 double nsl_math_ceil_places(double value, int n) { 0084 return nsl_math_places(value, n, 2); 0085 } 0086 double nsl_math_trunc_places(double value, int n) { 0087 return nsl_math_places(value, n, 3); 0088 } 0089 0090 double nsl_math_places(double value, int n, int method) { 0091 // no need to round 0092 if (value == 0. || fabs(value) > 1.e16 || fabs(value) < 1.e-16 || isnan(value) || isinf(value)) { 0093 /* printf("nsl_math_places(): not changed : %.19g\n", value); */ 0094 return value; 0095 } 0096 0097 double scale = gsl_pow_int(10., n); 0098 double scaled_value = value * scale; 0099 if (fabs(scaled_value) > 1.e16) 0100 return value; 0101 if (fabs(scaled_value) < .5) 0102 return 0.; 0103 0104 double eps = 1.e-15; 0105 /* 0106 printf("nsl_math_places(): value = %g, n = %d, DBL_EPSILON = %.19g, scale = %.19g, scaled_value = %.19g, round(scaled_value) = %.19g 0107 round(scaled_value)/scale = %.19g\n", value, n, DBL_EPSILON, scale, scaled_value, round(scaled_value), round(scaled_value)/scale); 0108 */ 0109 switch (method) { 0110 case 0: 0111 return round(scaled_value) / scale; 0112 break; 0113 case 1: 0114 return floor(scaled_value + eps) / scale; 0115 break; 0116 case 2: 0117 return ceil(scaled_value - eps) / scale; 0118 break; 0119 case 3: 0120 return trunc(scaled_value) / scale; 0121 break; 0122 default: 0123 printf("ERROR: unknown rounding method %d\n", method); 0124 return value; 0125 } 0126 } 0127 0128 double nsl_math_round_precision(double value, int p) { 0129 return nsl_math_round_basex(value, p, 10.); 0130 } 0131 0132 double nsl_math_round_basex(double value, int p, double base) { 0133 /* printf("nsl_math_round_basex(%g, %d, %g)\n", value, p, base); */ 0134 0135 // no need to round 0136 if (value == 0. || p > 16 || isnan(value) || isinf(value)) 0137 return value; 0138 0139 int e = 0; 0140 while (fabs(value) > base) { 0141 value /= base; 0142 e++; 0143 } 0144 while (fabs(value) < 1.) { 0145 value *= base; 0146 e--; 0147 } 0148 double power_of_x = gsl_pow_int(base, e); 0149 0150 if (p < 0) 0151 return power_of_x; 0152 0153 double scale = gsl_pow_uint(base, p); 0154 double scaled_value = value * scale; 0155 /* 0156 printf("nsl_math_round_basex(): scale = %g, scaled_value = %g, e = %d, return: %g\n", scale, scaled_value, e, round(scaled_value)/scale * 0157 gsl_pow_int(10., e)); 0158 */ 0159 0160 return round(scaled_value) / scale * power_of_x; 0161 } 0162 0163 double nsl_math_round_multiple(double value, double m) { 0164 return nsl_math_multiple(value, m, Round); 0165 } 0166 double nsl_math_floor_multiple(double value, double m) { 0167 return nsl_math_multiple(value, m, Floor); 0168 } 0169 double nsl_math_ceil_multiple(double value, double m) { 0170 return nsl_math_multiple(value, m, Ceil); 0171 } 0172 double nsl_math_trunc_multiple(double value, double m) { 0173 return nsl_math_multiple(value, m, Trunc); 0174 } 0175 0176 double nsl_math_multiple(double value, double multiple, round_method method) { 0177 // no need to round 0178 if (value == 0. || multiple == 0. || isnan(value) || isnan(multiple) || isinf(value) || isinf(multiple)) { 0179 /* printf("nsl_math_multiple(): not changed : %.19g\n", value); */ 0180 return value; 0181 } 0182 0183 switch (method) { 0184 case Round: 0185 return multiple * round(value / multiple); 0186 case Floor: 0187 return multiple * floor(value / multiple); 0188 case Ceil: 0189 return multiple * ceil(value / multiple); 0190 case Trunc: 0191 return multiple * trunc(value / multiple); 0192 } 0193 0194 return value; 0195 }