File indexing completed on 2024-05-12 15:27:08
0001 /*************************************************************************** 0002 File : nsl_math.c 0003 Project : LabPlot 0004 Description : NSL math functions 0005 -------------------------------------------------------------------- 0006 Copyright : (C) 2018-2020 by Stefan Gerlach (stefan.gerlach@uni.kn) 0007 0008 ***************************************************************************/ 0009 0010 /*************************************************************************** 0011 * * 0012 * This program is free software; you can redistribute it and/or modify * 0013 * it under the terms of the GNU General Public License as published by * 0014 * the Free Software Foundation; either version 2 of the License, or * 0015 * (at your option) any later version. * 0016 * * 0017 * This program is distributed in the hope that it will be useful, * 0018 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0020 * GNU General Public License for more details. * 0021 * * 0022 * You should have received a copy of the GNU General Public License * 0023 * along with this program; if not, write to the Free Software * 0024 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0025 * Boston, MA 02110-1301 USA * 0026 * * 0027 ***************************************************************************/ 0028 0029 #include "nsl_math.h" 0030 #include <gsl/gsl_math.h> 0031 0032 bool nsl_math_approximately_equal(double a, double b) { 0033 return nsl_math_approximately_equal_eps(a, b, 1.e-7); 0034 } 0035 0036 bool nsl_math_approximately_equal_eps(double a, double b, double epsilon) { 0037 return fabs(a - b) <= ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon); 0038 } 0039 0040 bool nsl_math_essentially_equal(double a, double b) { 0041 return nsl_math_essentially_equal_eps(a, b, 1.e-7); 0042 } 0043 0044 bool nsl_math_essentially_equal_eps(double a, double b, double epsilon) { 0045 return fabs(a - b) <= ( (fabs(a) > fabs(b) ? fabs(b) : fabs(a)) * epsilon); 0046 } 0047 0048 bool nsl_math_definitely_greater_than(double a, double b) { 0049 return nsl_math_definitely_greater_than_eps(a, b, 1.e-7); 0050 } 0051 0052 bool nsl_math_definitely_greater_than_eps(double a, double b, double epsilon) { 0053 return (a - b) > ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon); 0054 } 0055 0056 bool nsl_math_definitely_less_than(double a, double b) { 0057 return nsl_math_definitely_less_than_eps(a, b, 1.e-7); 0058 } 0059 0060 bool nsl_math_definitely_less_than_eps(double a, double b, double epsilon) { 0061 return (b - a) > ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon); 0062 } 0063 0064 0065 0066 int nsl_math_decimal_places(double value) { 0067 return -(int)floor(log10(fabs(value))); 0068 } 0069 0070 int nsl_math_rounded_decimals(double value) { 0071 int places = nsl_math_decimal_places(value); 0072 0073 // printf("places = %d, rv = %g\n", places, round(fabs(value) * pow(10, places))); 0074 if (round(fabs(value) * gsl_pow_int(10., places)) >= 5.) 0075 places--; 0076 0077 return places; 0078 } 0079 0080 int nsl_math_rounded_decimals_max(double value, int max) { 0081 return GSL_MIN_INT(max, nsl_math_rounded_decimals(value)); 0082 } 0083 0084 double nsl_math_round_places(double value, unsigned int n) { 0085 // no need to round 0086 if (value == 0. || fabs(value) > 1.e16 || fabs(value) < 1.e-16 || isnan(value) || isinf(value)) 0087 return value; 0088 0089 double scale = gsl_pow_uint(10., n); 0090 double scaled_value = value*scale; 0091 if (fabs(scaled_value) > 1.e16) 0092 return value; 0093 if (fabs(scaled_value) < .5) 0094 return 0.; 0095 0096 return round(scaled_value)/scale; 0097 } 0098 0099 double nsl_math_round_precision(double value, unsigned int p) { 0100 // no need to round 0101 if (value == 0. || p > 16 || isnan(value) || isinf(value)) 0102 return value; 0103 0104 int e = 0; 0105 while (fabs(value) > 10.) { 0106 value /= 10.; 0107 e++; 0108 } 0109 while (fabs(value) < 1.) { 0110 value *= 10.; 0111 e--; 0112 } 0113 0114 double scale = gsl_pow_uint(10., p); 0115 double scaled_value = value*scale; 0116 0117 return round(scaled_value)/scale * gsl_pow_int(10., e); 0118 }