%% options copyright owner = Dirk Krause copyright year = 2013-2014 license = bsd %% header #include #include #ifdef __cplusplus extern "C" { #endif /** Addition of double or long double. @param a Left operand. @param b Right operand. @param ec Pointer to error code variable. @return Operation result. */ dk3_double_t dk3md_add_ok(dk3_double_t a, dk3_double_t b, int *ec); /** Substraction of double or long double. @param a Left operand. @param b Right operand. @param ec Pointer to error code variable. @return Operation result. */ dk3_double_t dk3md_sub_ok(dk3_double_t a, dk3_double_t b, int *ec); /** Multiplication of double or long double. @param a Left operand. @param b Right operand. @param ec Pointer to error code variable. @return Operation result. */ dk3_double_t dk3md_mul_ok(dk3_double_t a, dk3_double_t b, int *ec); /** Division of double or long double. @param a Left operand. @param b Right operand. @param ec Pointer to error code variable. @return Operation result. */ dk3_double_t dk3md_div_ok(dk3_double_t a, dk3_double_t b, int *ec); /** Obtain format string for conversions. @param c Key character 'e', 'f', or 'g'. @return Conversion format string. */ dkChar const * dk3md_format(char c); /** Obtain format string for conversions. @param c Key character 'e', 'f', or 'g'. @return Conversion format string. */ char const * dk3md_c8_format(char c); /** Check availability of long double. @return 1 for long double available, 0 for fallback to double. */ int dk3md_have_long_double(void); /** Sinus. @param x Argument. @return Result. */ dk3_double_t dk3md_sin(dk3_double_t x); /** Cosinus. @param x Argument. @return Result. */ dk3_double_t dk3md_cos(dk3_double_t x); /** Tangens. @param x Argument. @return Result. */ dk3_double_t dk3md_tan(dk3_double_t x); /** Arcus sinus. @param x Argument. @return Result. */ dk3_double_t dk3md_asin(dk3_double_t x); /** Arcus cosinus. @param x Argument. @return Result. */ dk3_double_t dk3md_acos(dk3_double_t x); /** Arcus tangens. @param x Argument. @return Result. */ dk3_double_t dk3md_atan(dk3_double_t x); /** Arcus tangens for two arguments. @param y Y position. @param x X position. @return Result. */ dk3_double_t dk3md_atan2(dk3_double_t y, dk3_double_t x); /** Absolute value. @param x Argument. @return Result. */ dk3_double_t dk3md_fabs(dk3_double_t x); /** Round downwards. @param x Argument. @return Result. */ dk3_double_t dk3md_floor(dk3_double_t x); /** Round upwards. @param x Argument. @return Result. */ dk3_double_t dk3md_ceil(dk3_double_t x); /** Round to next integer. @param x Argument. @return Result. */ dk3_double_t dk3md_rint(dk3_double_t x); /** Exponential function. @param x Argument. @return Result. */ dk3_double_t dk3md_exp(dk3_double_t x); /** Logarithm. @param x Argument. @return Result. */ dk3_double_t dk3md_log(dk3_double_t x); /** Square root. @param x Argument. @return Result. */ dk3_double_t dk3md_sqrt(dk3_double_t x); /** Sinus hyperbolicus. @param x Argument. @return Result. */ dk3_double_t dk3md_sinh(dk3_double_t x); /** Cosinus hyperbolicus. @param x Argument. @return Result. */ dk3_double_t dk3md_cosh(dk3_double_t x); /** Tangens hyperbolicus. @param x Argument. @return Result. */ dk3_double_t dk3md_tanh(dk3_double_t x); #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if (DK3_HAVE_ASINHL) && (DK3_HAVE_ACOSHL) && (DK3_HAVE_ATANHL) /** Arcus sinus hyperbolicus. @param x Argument. @return Result. */ dk3_double_t dk3md_asinh(dk3_double_t x); /** Arcus cosinus hyperbolicus. @param x Argument. @return Result. */ dk3_double_t dk3md_acosh(dk3_double_t x); /** Arcus tangens hyperbolicus. @param x Argument. @return Result. */ dk3_double_t dk3md_atanh(dk3_double_t x); #else #if (DK3_HAVE_ASINH) && (DK3_HAVE_ACOSH) && (DK3_HAVE_ATANH) /** Arcus sinus hyperbolicus. @param x Argument. @return Result. */ dk3_double_t dk3md_asinh(dk3_double_t x); /** Arcus cosinus hyperbolicus. @param x Argument. @return Result. */ dk3_double_t dk3md_acosh(dk3_double_t x); /** Arcus tangens hyperbolicus. @param x Argument. @return Result. */ dk3_double_t dk3md_atanh(dk3_double_t x); #else #if (DK3_NEED_ASINH) || (DK3_NEED_ACOSH) || (DK3_NEED_ATANH) #error "No asinh/acosh/atanh function in math library!" #endif #endif #endif #else #if (DK3_HAVE_ASINH) && (DK3_HAVE_ACOSH) && (DK3_HAVE_ATANH) /** Arcus sinus hyperbolicus. @param x Argument. @return Result. */ dk3_double_t dk3md_asinh(dk3_double_t x); /** Arcus cosinus hyperbolicus. @param x Argument. @return Result. */ dk3_double_t dk3md_acosh(dk3_double_t x); /** Arcus tangens hyperbolicus. @param x Argument. @return Result. */ dk3_double_t dk3md_atanh(dk3_double_t x); #else #if (DK3_NEED_ASINH) || (DK3_NEED_ACOSH) || (DK3_NEED_ATANH) #error "No asinh/acosh/atanh function in math library!" #endif #endif #endif #ifdef __cplusplus } #endif %% module #include "dk3all.h" #include "dk3md.h" #include /** Maximum value for long double. */ #define DK3_MAX_LONG_DOUBLE DK3_MAX_DOUBLE #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) /* Real long double (start) */ /** Conversion format strings in dkChar size. */ static dkChar const * const dk3md_conversion_formats[] = { dkT("%Le"), dkT("%Lf"), dkT("%Lg"), NULL }; /** Conversion format strings in char size. */ static char const * const dk3md_c8_conversion_formats[] = { "%Le", "%Lf", "%Lg", NULL }; /* Real long double (end) */ #else /* Fallback to normal double (start) */ /** Conversion format strings in dkChar size. */ static dkChar const * const dk3md_conversion_formats[] = { dkT("%le"), dkT("%lf"), dkT("%lg"), NULL }; /** Conversion format strings in char size. */ static char const * const dk3md_c8_conversion_formats[] = { "%le", "%lf", "%lg", NULL }; /* Fallback to normal double (end) */ #endif dkChar const * dk3md_format(char c) { dkChar const *back; back = dk3md_conversion_formats[0]; switch(c) { case 'f': case 'F': { back = dk3md_conversion_formats[1]; } break; case 'g': case 'G': { back = dk3md_conversion_formats[2]; } break; } return back; } char const * dk3md_c8_format(char c) { char const *back; back = dk3md_c8_conversion_formats[0]; switch(c) { case 'f': case 'F': { back = dk3md_c8_conversion_formats[1]; } break; case 'g': case 'G': { back = dk3md_c8_conversion_formats[2]; } break; } return back; } int dk3md_have_long_double(void) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) return 1; #else return 0; #endif } dk3_double_t dk3md_add_ok(dk3_double_t a, dk3_double_t b, int *ec) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) double back; if(a >= 0.0L) { if(b >= 0.0L) { back = a + b; if((DK3_MAX_LONG_DOUBLE - a) < b) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { back = a + b; } } else { if(b >= 0.0L) { back = a + b; } else { back = -1.0L * dk3md_add_ok(fabsl(a), fabsl(b), ec); } } return back; #else return(dk3ma_d_add_ok(a, b, ec)); #endif } dk3_double_t dk3md_sub_ok(dk3_double_t a, dk3_double_t b, int *ec) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) double back; if(a >= 0.0L) { if(b >= 0.0L) { back = a - b; } else { back = dk3md_add_ok(a, fabsl(b), ec); } } else { if(b >= 0.0L) { back = -1.0L * dk3md_add_ok(fabsl(a), b, ec); } else { back = a - b; } } return back; #else return(dk3ma_d_sub_ok(a, b, ec)); #endif } dk3_double_t dk3md_mul_ok(dk3_double_t a, dk3_double_t b, int *ec) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) double back; if(a >= 0.0L) { if(b >= 0.0L) { back = a * b; if(a > 1.0L) { if((DK3_MAX_LONG_DOUBLE / a) < b) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } } else { back = -1.0L * dk3md_mul_ok(a, fabsl(b), ec); } } else { if(b >= 0.0L) { back = -1.0L * dk3md_mul_ok(fabsl(a), b, ec); } else { back = dk3md_mul_ok(fabsl(a), fabsl(b), ec); } } return back; #else return(dk3ma_d_mul_ok(a, b, ec)); #endif } dk3_double_t dk3md_div_ok(dk3_double_t a, dk3_double_t b, int *ec) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) double back; if(a >= 0.0L) { if(b >= 0.0L) { if(b < 1.0L) { if((DK3_MAX_LONG_DOUBLE * b) > a) { back = a / b; } else { back = 0.0L; if(ec) { *ec = DK3_ERROR_MATH_DIVZERO; } } } else { back = a / b; } } else { back = -1.0L * dk3md_div_ok(a, fabsl(b), ec); } } else { if(b >= 0.0L) { back = -1.0L * dk3md_div_ok(fabsl(a), b, ec); } else { back = dk3md_div_ok(fabsl(a), fabsl(b), ec); } } return back; #else return(dk3ma_d_div_ok(a, b, ec)); #endif } dk3_double_t dk3md_sin(dk3_double_t x) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if DK3_HAVE_SINL return(sinl(x)); #else return((long double)sin((double)(x))); #endif #else return(sin(x)); #endif } dk3_double_t dk3md_cos(dk3_double_t x) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if DK3_HAVE_COSL return(cosl(x)); #else return((long double)cos((double)(x))); #endif #else return(cos(x)); #endif } dk3_double_t dk3md_tan(dk3_double_t x) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if DK3_HAVE_TANL return(tanl(x)); #else return((long double)tan((double)(x))); #endif #else return(tan(x)); #endif } dk3_double_t dk3md_asin(dk3_double_t x) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if DK3_HAVE_ASINL return(asinl(x)); #else return((long double)asin((double)(x))); #endif #else return(asin(x)); #endif } dk3_double_t dk3md_acos(dk3_double_t x) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if DK3_HAVE_ACOSL return(acosl(x)); #else return((long double)acos((double)(x))); #endif #else return(acos(x)); #endif } dk3_double_t dk3md_atan(dk3_double_t x) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if DK3_HAVE_ATANL return(atanl(x)); #else return((long double)atan((double)(x))); #endif #else return(atan(x)); #endif } dk3_double_t dk3md_atan2(dk3_double_t y, dk3_double_t x) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if DK3_HAVE_ATAN2L return(atan2l(y, x)); #else #if DK3_HAVE_ATAN2 return((long double)atan2((double)(y), (double)(x))); #else return((long double)dk3ma_d_atan2((double)y, (double)x)); #endif #endif #else #if DK3_HAVE_ATAN2 return(atan2(y, x)); #else return(dk3ma_d_atan2(y,x)); #endif #endif } dk3_double_t dk3md_fabs(dk3_double_t x) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if DK3_HAVE_FABSL return(fabsl(x)); #else return((long double)fabs((double)(x))); #endif #else return(fabs(x)); #endif } dk3_double_t dk3md_floor(dk3_double_t x) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if DK3_HAVE_FLOORL return(floorl(x)); #else return((long double)floor((double)(x))); #endif #else return(floor(x)); #endif } dk3_double_t dk3md_ceil(dk3_double_t x) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if DK3_HAVE_CEILL return(ceill(x)); #else return((long double)ceil((double)(x))); #endif #else return(ceil(x)); #endif } dk3_double_t dk3md_rint(dk3_double_t x) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if DK3_HAVE_RINTL return(rintl(x)); #else #if DK3_HAVE_RINT return((long double)rint((double)(x))); #else return((long double)dk3ma_d_rint((double)(x))); #endif #endif #else #if DK3_HAVE_RINT return(rint(x)); #else return(dk3ma_d_rint(x)); #endif #endif } dk3_double_t dk3md_exp(dk3_double_t x) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if DK3_HAVE_EXPL return(expl(x)); #else return((long double)exp((double)(x))); #endif #else return(exp(x)); #endif } dk3_double_t dk3md_log(dk3_double_t x) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if DK3_HAVE_LOGL return(logl(x)); #else return((long double)log((double)(x))); #endif #else return(log(x)); #endif } dk3_double_t dk3md_sqrt(dk3_double_t x) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if DK3_HAVE_SQRTL return(sqrtl(x)); #else return((long double)sqrt((double)(x))); #endif #else return(sqrt(x)); #endif } dk3_double_t dk3md_sinh(dk3_double_t x) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if DK3_HAVE_SINHL return(sinhl(x)); #else return((long double)sinh((double)(x))); #endif #else return(sinh(x)); #endif } dk3_double_t dk3md_cosh(dk3_double_t x) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if DK3_HAVE_COSHL return(coshl(x)); #else return((long double)cosh((double)(x))); #endif #else return(cosh(x)); #endif } dk3_double_t dk3md_tanh(dk3_double_t x) { #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if DK3_HAVE_TANHL return(tanhl(x)); #else return((long double)tanh((double)(x))); #endif #else return(tanh(x)); #endif } #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) #if (DK3_HAVE_ASINHL) && (DK3_HAVE_ACOSHL) && (DK3_HAVE_ATANHL) dk3_double_t dk3md_asinh(dk3_double_t x) { return(asinhl(x)); } dk3_double_t dk3md_acosh(dk3_double_t x) { return(acoshl(x)); } dk3_double_t dk3md_atanh(dk3_double_t x) { return(atanhl(x)); } #else #if (DK3_HAVE_ASINH) && (DK3_HAVE_ACOSH) && (DK3_HAVE_ATANH) dk3_double_t dk3md_asinh(dk3_double_t x) { return((long double)asinh((double)x)); } dk3_double_t dk3md_acosh(dk3_double_t x) { return((long double)acosh((double)x)); } dk3_double_t dk3md_atanh(dk3_double_t x) { return((long double)atanh((double)x)); } #else #if (DK3_NEED_ASINH) || (DK3_NEED_ACOSH) || (DK3_NEED_ATANH) #error "No asinh/acosh/atanh function in math library!" #endif #endif #endif #else #if (DK3_HAVE_ASINH) && (DK3_HAVE_ACOSH) && (DK3_HAVE_ATANH) dk3_double_t dk3md_asinh(dk3_double_t x) { return(asinh(x)); } dk3_double_t dk3md_acosh(dk3_double_t x) { return(acosh(x)); } dk3_double_t dk3md_atanh(dk3_double_t x) { return(atanh(x)); } #else #if (DK3_NEED_ASINH) || (DK3_NEED_ACOSH) || (DK3_NEED_ATANH) #error "No asinh/acosh/atanh function in math library!" #endif #endif #endif