%% options copyright owner = Dirk Krause copyright year = 2013 license = bsd %% header #include #include #if DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) /* Long double (start) */ /** Calculate sin(x). */ #if DK3_HAVE_SINL #define dk3md_sin(x) sinl(x) #else #define dk3md_sin(x) (long double)sin((double)(x)) #endif /** Calculate cos(x). */ #if DK3_HAVE_COSL #define dk3md_cos(x) cosl(x) #else #define dk3md_cos(x) (long double)cos((double)(x)) #endif /** Calculate tan(x). */ #if DK3_HAVE_TANL #define dk3md_tan(x) tanl(x) #else #define dk3md_tan(x) (long double)tan((double)(x)) #endif /** Calculate asin(x). */ #if DK3_HAVE_ASINL #define dk3md_asin(x) asinl(x) #else #define dk3md_asin(x) (long double)asin((double)(x)) #endif /** Calculate acos(x). */ #if DK3_HAVE_ACOSL #define dk3md_acos(x) acosl(x) #else #define dk3md_acos(x) (long double)acos((double)(x)) #endif /** Calculate atan(x). */ #if DK3_HAVE_ATANL #define dk3md_atan(x) atanl(x) #else #define dk3md_atan(x) (long double)atan((double)(x)) #endif /** Calculate atan of y and x. */ #if DK3_HAVE_ATAN2L #define dk3md_atan2(y,x) atan2l(y,x) #else #if DK3_HAVE_ATAN2 #define dk3md_atan2(y,x) (long double)atans((double)(y), (double)(x)) #else #define dk3md_atan2(y,x) dk3ma_d_atan2(y,x) #endif #endif /** Calculate absolute value. */ #if DK3_HAVE_FABSL #define dk3md_fabs(x) fabsl(x) #else #define dk3md_fabs(x) (long double)fabs((double)(x)) #endif /** Next smaller integer. */ #if DK3_HAVE_FLOORL #define dk3md_floor(x) floorl(x) #else #define dk3md_floor(x) (long double)floor((double)(x)) #endif /** Next higher integer. */ #if DK3_HAVE_CEILL #define dk3md_ceil(x) ceill(x) #else #define dk3md_ceil(x) (long double)ceil((double)(x)) #endif /** Rounding. */ #if DK3_HAVE_RINTL #define dk3md_rint(x) rintl(x) #else #if DK3_HAVE_FLOORL #define dk3md_rint(x) floorl((x) + 0.5L) #else #if DK3_HAVE_RINT #define dk3md_rint(x) (long double)rint((double)(x)) #else #if DK3_HAVE_FLOOR #define dk3md_rint(x) (long double)floor((double)(x) + 0.5) #else #define dk3md_rint(x) dk3ma_rint(x) #endif #endif #endif #endif /** Calculate exp(x). */ #if DK3_HAVE_EXPL #define dk3md_exp(x) expl(x) #else #define dk3md_exp(x) (long double)exp((double)(x)) #endif /** Calculate logarithm. */ #if DK3_HAVE_LOGL #define dk3md_log(x) logl(x) #else #define dk3md_log(x) (long double)log((double)(x)) #endif /** Calculate square root. */ #if DK3_HAVE_SQRTL #define dk3md_sqrt(x) sqrtl(x) #else #define dk3md_sqrt(x) (long double)sqrt((double)(x)) #endif /** Calculate sinh(x). */ #if DK3_HAVE_SINHL #define dk3md_sinh(x) sinhl(x) #else #define dk3md_sinh(x) (long double)sinh((double)(x)) #endif /** Calculate cosh(x). */ #if DK3_HAVE_COSHL #define dk3md_cosh(x) coshl(x) #else #define dk3md_cosh(x) (long double)cosh((double)(x)) #endif /** Calculate tanh(x). */ #if DK3_HAVE_TANHL #define dk3md_tanh(x) tanhl(x) #else #define dk3md_tanh(x) (long double)tanh((double)(x)) #endif #if (DK3_HAVE_ASINHL) && (DK3_HAVE_ACOSHL) && (DK3_HAVE_ATANHL) /** Caluclate arcus sinh(x). */ #define dk3md_asinh(x) asinhl(x) /** Calculate arcus cosh(x). */ #define dk3md_acosh(x) acoshl(x) /** Calculate arcus tanh(x). */ #define dk3md_atanh(x) atanhl(x) #else /* if (DK3_HAVE_ASINHL) && (DK3_HAVE_ACOSHL) && (DK3_HAVE_ATANHL) */ #if (DK3_HAVE_ASINH) && (DK3_HAVE_ACOSH) && (DK3_HAVE_ATANH) /** Caluclate arcus sinh(x). */ #define dk3md_asinh(x) (long double)asinh((double)(x)) /** Calculate arcus cosh(x). */ #define dk3md_acosh(x) (long double)acosh((double)(x)) /** Calculate arcus tanh(x). */ #define dk3md_atanh(x) (long double)atanh((double)(x)) #else /* if (DK3_HAVE_ASINH) && (DK3_HAVE_ACOSH) && (DK3_HAVE_ATANH) */ #if (DK3_NEED_ASINH) || (DK3_NEED_ACOSH) || (DK3_NEED_ATANH) #error "No asinh/acosh/atanh function in math library!" #endif #endif /* if (DK3_HAVE_ASINH) && (DK3_HAVE_ACOSH) && (DK3_HAVE_ATANH) */ #endif /* if (DK3_HAVE_ASINHL) && (DK3_HAVE_ACOSHL) && (DK3_HAVE_ATANHL) */ /** Calculate summary of a and b. */ #define dk3md_add(a,b) dk3md_add_ok(a,b,NULL) /** Calculate difference of a and b. */ #define dk3md_sub(a,b) dk3md_sub_ok(a,b,NULL) /** Calculate product of a and b. */ #define dk3md_mul(a,b) dk3md_mul_ok(a,b,NULL) /** Calculate division of a and b. */ #define dk3md_div(a,b) dk3md_div_ok(a,b,NULL) #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); #ifdef __cplusplus } #endif /* Long double (end) */ #else /* DK3_HAVE_LONG_DOUBLE && (DK3_SIZEOF_LONG_DOUBLE > DK3_SIZEOF_DOUBLE) */ /* Normal double (start) */ /** Calculate summary of a and b, set error code if necessary. */ #define dk3md_add_ok(a,b,ec) dk3ma_d_add_ok(a,b,ec) /** Calculate difference of a and b, set error code if necessary. */ #define dk3md_sub_ok(a,b,ec) dk3ma_d_sub_ok(a,b,ec) /** Calculate product of a and b, set error code if necessary. */ #define dk3md_mul_ok(a,b,ec) dk3ma_d_mul_ok(a,b,ec) /** Calculate division of a and b, set error code if necessary. */ #define dk3md_div_ok(a,b,ec) dk3ma_d_div_ok(a,b,ec) /** Calculate summary of a and b. */ #define dk3md_add(a,b) dk3ma_d_add(a,b) /** Calculate difference of a and b. */ #define dk3md_sub(a,b) dk3ma_d_sub(a,b) /** Calculate product of a and b. */ #define dk3md_mul(a,b) dk3ma_d_mul(a,b) /** Calculate division of a and b. */ #define dk3md_div(a,b) dk3ma_d_div(a,b) /** Calculate sin(x). */ #define dk3md_sin(x) sin(x) /** Calculate cos(x). */ #define dk3md_cos(x) cos(x) /** Calculate tan(x). */ #define dk3md_tan(x) tan(x) /** Calculate asin(x). */ #define dk3md_asin(x) asin(x) /** Calculate acos(x). */ #define dk3md_acos(x) acos(x) /** Calculate atan(x). */ #define dk3md_atan(x) atan(x) /** Calculate atan of y and x. */ #define dk3md_atan2(y,x) atan2(y,x) /** Calculate absolute value. */ #define dk3md_fabs(x) fabs(x) /** Next smaller integer. */ #define dk3md_floor(x) floor(x) /** Next higher integer. */ #define dk3md_ceil(x) ceil(x) /** Rounding. */ #define dk3md_rint(x) rint(x) /** Calculate exp(x). */ #define dk3md_exp(x) exp(x) /** Calculate logarithm. */ #define dk3md_log(x) log(x) /** Calculate square root. */ #define dk3md_sqrt(x) sqrt(x) /** Calculate sinh(x). */ #define dk3md_sinh(x) sinh(x) /** Calculate cosh(x). */ #define dk3md_cosh(x) cosh(x) /** Calculate tanh(x). */ #define dk3md_tanh(x) tanh(x) #if (DK3_HAVE_ASINH) && (DK3_HAVE_ACOSH) && (DK3_HAVE_ATANH) /** Caluclate arcus sinh(x). */ #define dk3md_asinh(x) asinh(x) /** Calculate arcus cosh(x). */ #define dk3md_acosh(x) acosh(x) /** Calculate arcus tanh(x). */ #define dk3md_atanh(x) atanh(x) #else /* if (DK3_HAVE_ASINH) && (DK3_HAVE_ACOSH) && (DK3_HAVE_ATANH) */ #if (DK3_NEED_ASINH) || (DK3_NEED_ACOSH) || (DK3_NEED_ATANH) #error "No asinh/acosh/atanh function in math library!" #endif #endif /* if (DK3_HAVE_ASINH) && (DK3_HAVE_ACOSH) && (DK3_HAVE_ATANH) */ #ifdef __cplusplus extern "C" { #endif /** 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); #ifdef __cplusplus } #endif /* Normal double (end) */ #endif %% module #include "dk3all.h" #include "dk3md.h" #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 }; int dk3md_have_long_double(void) { return 1; } dk3_double_t dk3md_add_ok(dk3_double_t a, dk3_double_t b, int *ec) { 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; } dk3_double_t dk3md_sub_ok(dk3_double_t a, dk3_double_t b, int *ec) { 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; } dk3_double_t dk3md_mul_ok(dk3_double_t a, dk3_double_t b, int *ec) { 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; } dk3_double_t dk3md_div_ok(dk3_double_t a, dk3_double_t b, int *ec) { 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; } /* 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 }; int dk3md_have_long_double(void) { return 1; } /* 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': { dk3md_conversion_formats[1]; } break; case 'g': case 'G': { 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': { dk3md_c8_conversion_formats[1]; } break; case 'g': case 'G': { dk3md_c8_conversion_formats[2]; } break; } return back; }