%% options copyright owner = Dirk Krause copyright year = 2011-2013 license = bsd %% header #include "dk3conf.h" #include "dk3types.h" #ifdef __cplusplus extern "C" { #endif /** Maximum length unsigned int addition. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ dk3_um_t dk3ma_mu_add_ok(dk3_um_t a, dk3_um_t b, int *ec); /** Maximum length unsigned int substraction. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ dk3_um_t dk3ma_mu_sub_ok(dk3_um_t a, dk3_um_t b, int *ec); /** Maximum length unsigned int multiplication. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ dk3_um_t dk3ma_mu_mul_ok(dk3_um_t a, dk3_um_t b, int *ec); /** Maximum length unsigned int division. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ dk3_um_t dk3ma_mu_div_ok(dk3_um_t a, dk3_um_t b, int *ec); /** Maximum length unsigned int greatest common divisor. * @param u1 Left operand. * @param u2 Right operand. * @return Operation result. */ dk3_um_t dk3ma_mu_gcd(dk3_um_t u1, dk3_um_t u2); /** Maximum length unsigned int addition. * @param a Left operand. * @param b Right operand. * @return Operation result. */ dk3_um_t dk3ma_mu_add(dk3_um_t a, dk3_um_t b); /** Maximum length unsigned int substraction. * @param a Left operand. * @param b Right operand. * @return Operation result. */ dk3_um_t dk3ma_mu_sub(dk3_um_t a, dk3_um_t b); /** Maximum length unsigned int multiplication. * @param a Left operand. * @param b Right operand. * @return Operation result. */ dk3_um_t dk3ma_mu_mul(dk3_um_t a, dk3_um_t b); /** Maximum length unsigned int division. * @param a Left operand. * @param b Right operand. * @return Operation result. */ dk3_um_t dk3ma_mu_div(dk3_um_t a, dk3_um_t b); #if 0 /** Maximum length unsigned int greatest common divisor. * @param u1 Left operand. * @param u2 Right operand. * @return Result. */ dk3_um_t dk3ma_mu_gcd(dk3_um_t u1, dk3_um_t u2); #endif /** Convert maximum length unsigned int to char string. * @param rb Result buffer. * @param sz Size of \a rb in bytes. * @param va Value to convert. * @return 1 on success, 0 on error. */ int dk3ma_uintmax_to_c8_string(char *rb, size_t sz, dk3_um_t va); /** Convert maximum length unsigned int to dkChar string. * @param rb Result buffer. * @param sz Size of \a rb in bytes. * @param va Value to convert. * @return 1 on success, 0 on error. */ int dk3ma_uintmax_to_string(dkChar *rb, size_t sz, dk3_um_t va); /** Convert maximum length unsigned int to dkChar hex string. * @param rb Result buffer. * @param sz Size of \a rb in bytes. * @param va Value to convert. * @return 1 on success, 0 on error. */ int dk3ma_uintmax_to_hex_string(dkChar *rb, size_t sz, dk3_um_t va); /** Read maximum length unsigned int from char string. * @param va Pointer to result variable. * @param s String to read. * @return 1 on success, 0 on error. */ int dk3ma_uintmax_from_c8_string(dk3_um_t *va, char const *s); /** Read maximum length unsigned int from char string. * @param va Pointer to result variable. * @param s String to read. * @return 1 on success, 0 on error. */ int dk3ma_uintmax_from_string(dk3_um_t *va, dkChar const *s); /** Maximum length int addition. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ dk3_im_t dk3ma_mi_add_ok(dk3_im_t a, dk3_im_t b, int *ec); /** Maximum length int substraction. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ dk3_im_t dk3ma_mi_sub_ok(dk3_im_t a, dk3_im_t b, int *ec); /** Maximum length int multiplication. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ dk3_im_t dk3ma_mi_mul_ok(dk3_im_t a, dk3_im_t b, int *ec); /** Maximum length int division. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ dk3_im_t dk3ma_mi_div_ok(dk3_im_t a, dk3_im_t b, int *ec); /** Maximum length int addition. * @param a Left operand. * @param b Right operand. * @return Operation result. */ dk3_im_t dk3ma_mi_add(dk3_im_t a, dk3_im_t b); /** Maximum length int substraction. * @param a Left operand. * @param b Right operand. * @return Operation result. */ dk3_im_t dk3ma_mi_sub(dk3_im_t a, dk3_im_t b); /** Maximum length int multiplication. * @param a Left operand. * @param b Right operand. * @return Operation result. */ dk3_im_t dk3ma_mi_mul(dk3_im_t a, dk3_im_t b); /** Maximum length int division. * @param a Left operand. * @param b Right operand. * @return Operation result. */ dk3_im_t dk3ma_mi_div(dk3_im_t a, dk3_im_t b); /** Maximum length int greatest common divisor. * @param u1 Left operand. * @param u2 Right operand. * @return Result. */ dk3_im_t dk3ma_mi_gcd(dk3_im_t u1, dk3_im_t u2); /** Get absolute value from maximum length integer value. @param a Argument. @return Absolute value. */ dk3_im_t dk3ma_mi_abs(dk3_im_t a); /** Convert maximum length int to char string. * @param rb Result buffer. * @param sz Size of \a rb in bytes. * @param va Value to convert. * @return 1 on success, 0 on error. */ int dk3ma_intmax_to_c8_string(char *rb, size_t sz, dk3_im_t va); /** Convert maximum length int to dkChar string. * @param rb Result buffer. * @param sz Size of \a rb in bytes. * @param va Value to convert. * @return 1 on success, 0 on error. */ int dk3ma_intmax_to_string(dkChar *rb, size_t sz, dk3_im_t va); /** Read maximum length int from char string. * @param va Pointer to result variable. * @param s String to read. * @return 1 on success, 0 on error. */ int dk3ma_intmax_from_c8_string(dk3_im_t *va, char const *s); /** Read maximum length int from dkChar string. * @param va Pointer to result variable. * @param s String to read. * @return 1 on success, 0 on error. */ int dk3ma_intmax_from_string(dk3_im_t *va, dkChar const *s); /** Unsigned long addition. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ unsigned long dk3ma_ul_add_ok(unsigned long a, unsigned long b, int *ec); /** Unsigned long substraction. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ unsigned long dk3ma_ul_sub_ok(unsigned long a, unsigned long b, int *ec); /** Unsigned long multiplication. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ unsigned long dk3ma_ul_mul_ok(unsigned long a, unsigned long b, int *ec); /** Unsigned long division. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ unsigned long dk3ma_ul_div_ok(unsigned long a, unsigned long b, int *ec); /** Unsigned long addition. * @param a Left operand. * @param b Right operand. * @return Operation result. */ unsigned long dk3ma_ul_add(unsigned long a, unsigned long b); /** Unsigned long substraction. * @param a Left operand. * @param b Right operand. * @return Operation result. */ unsigned long dk3ma_ul_sub(unsigned long a, unsigned long b); /** Unsigned long multiplication. * @param a Left operand. * @param b Right operand. * @return Operation result. */ unsigned long dk3ma_ul_mul(unsigned long a, unsigned long b); /** Unsigned long division. * @param a Left operand. * @param b Right operand. * @return Operation result. */ unsigned long dk3ma_ul_div(unsigned long a, unsigned long b); /** Unsigned long greatest common divisor. * @param u1 Left operand. * @param u2 Right operand. * @return Result. */ unsigned long dk3ma_ul_gcd(unsigned long u1, unsigned long u2); /** Long addition. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ long dk3ma_l_add_ok(long a, long b, int *ec); /** Long substraction. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ long dk3ma_l_sub_ok(long a, long b, int *ec); /** Long multiplication. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ long dk3ma_l_mul_ok(long a, long b, int *ec); /** Long division. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ long dk3ma_l_div_ok(long a, long b, int *ec); /** Long addition. * @param a Left operand. * @param b Right operand. * @return Operation result. */ long dk3ma_l_add(long a, long b); /** Long substraction. * @param a Left operand. * @param b Right operand. * @return Operation result. */ long dk3ma_l_sub(long a, long b); /** Long multiplication. * @param a Left operand. * @param b Right operand. * @return Operation result. */ long dk3ma_l_mul(long a, long b); /** Long division. * @param a Left operand. * @param b Right operand. * @return Operation result. */ long dk3ma_l_div(long a, long b); /** Long greatest common divisor. * @param u1 Left operand. * @param u2 Right operand. * @return Result. */ long dk3ma_l_gcd(long u1, long u2); /** Double addition. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ double dk3ma_d_add_ok(double a, double b, int *ec); /** Double substraction. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ double dk3ma_d_sub_ok(double a, double b, int *ec); /** Double multiplication. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ double dk3ma_d_mul_ok(double a, double b, int *ec); /** Double division. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Operation result. */ double dk3ma_d_div_ok(double a, double b, int *ec); /** Double addition. * @param a Left operand. * @param b Right operand. * @return Operation result. */ double dk3ma_d_add(double a, double b); /** Double substraction. * @param a Left operand. * @param b Right operand. * @return Operation result. */ double dk3ma_d_sub(double a, double b); /** Double multiplication. * @param a Left operand. * @param b Right operand. * @return Operation result. */ double dk3ma_d_mul(double a, double b); /** Double division. * @param a Left operand. * @param b Right operand. * @return Operation result. */ double dk3ma_d_div(double a, double b); /** Round double to next int value. @param x Value to round. @return Rounding result. */ double dk3ma_rint(double x); /** Convert double value to unsigned long. @param x Double value. @param ec Pointer to error code variable. @return Conversion result. */ unsigned long dk3ma_d_to_ul_ok(double x, int *ec); /** Convert double value to long. @param x Double value. @param ec Pointer to error code variable. @return Conversion result. */ long dk3ma_d_to_l_ok(double x, int *ec); /** Convert double value to maximum size unsigned integer. @param x Double value. @param ec Pointer to error code variable. @return Conversion result. */ dk3_um_t dk3ma_d_to_mu_ok(double x, int *ec); /** Convert double value to maximum size integer. @param x Double value. @param ec Pointer to error code variable. @return Conversion result. */ dk3_im_t dk3ma_d_to_mi_ok(double x, int *ec); /** Convert maximum size unsigned integer to double. @param x Maximum size unsigned integer value. @return Conversion result. */ double dk3ma_mu_to_d(dk3_um_t x); /** Convert maximum size integer to double. @param x Maximum size integer value. @return Conversion result. */ double dk3ma_mi_to_d(dk3_im_t x); /** Convert unsigned long to double. @param x Unsigned long value. @return Conversion result. */ double dk3ma_ul_to_d(unsigned long x); /** Convert long value to double. @param x Long value. @return Conversion result. */ double dk3ma_l_to_d(long x); /** Add two sizes, check range overflow. * @param a Left operand. * @param b Right operand. * @param ec Pointer to error code variable. * @return Addition result on success, 0 on error. */ size_t dk3ma_sz_add_ok(size_t a, size_t b, int *ec); /** Multiplicate two sizes, check range overflow. @param a Number of elements. @param b Element size. @param ec Pointer to error code variable. @return Result on success, 0 on error. */ size_t dk3ma_sz_mul_ok(size_t a, size_t b, int *ec); /** Calculate arcus tangens of given y and x. @param y The sinus value. @param x The cosinus value. @return Arcus tangens result 0<=result<=2*pi. */ double dk3ma_atan2(double y, double x); /** Check whether two double values are equal. @param a First value. @param b Second value. @param epsilon Allowed difference to treat values as equal. @return 1 if the values are close enough to each other. */ int dk3ma_d_equal(double a, double b, double epsilon); /** Calculate x*x. @param x Value to create square for. @param ec Pointer to error code variable, may be NULL. @return Operation result. */ double dk3ma_d_square_ok(double x, int *ec); /** Restrict number of digits following the decimal dot. @param x Original value. @param n Number of digits after decimal dot. @return Rounded result. */ double dk3ma_restrict_digits(double x, size_t n); /** Restrict number of digits following the decimal dot, round downwards. @param x Original value. @param n Number of digits after decimal dot. @return Rounded result. */ double dk3ma_restrict_digits_floor(double x, size_t n); /** Restrict number of digits following the decimal dot, round upwards. @param x Original value. @param n Number of digits after decimal dot. @return Rounded result. */ double dk3ma_restrict_digits_ceil(double x, size_t n); /** Convert double number to size. @param v Value to convert. @param ec Pointer to error code variable, may be NULL. @return Conversion result. */ size_t dk3ma_d_to_size_ok(double v, int *ec); /** Print floating point value specified as string to output file, avoid exponential notation. @param of Output file. @param buffer Buffer containing string representation of value, probably in scientific notatation. The buffer content is modified by this function. The string represenation should be built using sprintf(buffer, "%lg", value). */ void dk3ma_print_double_c8_str_no_sci(FILE *of, char *buffer); /** Print floating point value to output file, avoid exponential notation. @param of Output file. @param x Value to print. */ void dk3ma_print_double_c8_no_sci(FILE *of, double x); #ifdef __cplusplus } #endif /* Yes, there are systems without M_PI or M_PI_2 in math.h */ #ifndef M_PI /** Define pi if not already defined in math.h */ #define M_PI 3.14159265358979323846 #endif #ifndef M_PI_2 /** Define 0.5 * pi if not already defined in math.h */ #define M_PI_2 1.57079632679489661923 #endif %% module #include "dk3all.h" $(trace-include) /** Bit mask for most significant bit in a maximum size integer. */ static dk3_im_t const dk3ma_im_msb = DK3_MAX_INT_MSB; /** Check whether a maximum size integer is the most negative value. @param i Number to check. @return 1 for true, 0 for false. */ static int dk3ma_is_im_msb(dk3_im_t i) { int back = 0; if(i == dk3ma_im_msb) { back = 1; } return back; } /** Bit mask for most significant bit in an unsigned long value. */ static long const dk3ma_l_msb = (long)0x80000000L; /** Check whether a long is the most negative value. @param i Number to check. @return 1 for true, 0 for false. */ static int dk3ma_is_l_msb(long i) { int back = 0; if(i == dk3ma_l_msb) { back = 1; } return back; } dk3_um_t dk3ma_mu_add_ok(dk3_um_t a, dk3_um_t b, int *ec) { dk3_um_t back = DK3_MAX_UINT_0; back = a + b; if((DK3_MAX_UINTMAX - a) < b) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } return back; } dk3_um_t dk3ma_mu_sub_ok(dk3_um_t a, dk3_um_t b, int *ec) { dk3_um_t back = DK3_MAX_UINT_0; back = a - b; if(b > a) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } return back; } dk3_um_t dk3ma_mu_mul_ok(dk3_um_t a, dk3_um_t b, int *ec) { dk3_um_t back = DK3_MAX_UINT_0; back = a * b; if(a) { if(b > (DK3_MAX_UINTMAX / a)) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } return back; } dk3_um_t dk3ma_mu_div_ok(dk3_um_t a, dk3_um_t b, int *ec) { dk3_um_t back = DK3_MAX_UINT_0; if(b) { back = a / b; } else { if(ec) { *ec = DK3_ERROR_MATH_DIVZERO; } } return back; } dk3_um_t dk3ma_mu_add(dk3_um_t a, dk3_um_t b) { dk3_um_t back = DK3_MAX_UINT_0; back = dk3ma_mu_add_ok(a, b, NULL); return back; } dk3_um_t dk3ma_mu_sub(dk3_um_t a, dk3_um_t b) { dk3_um_t back = DK3_MAX_UINT_0; back = dk3ma_mu_sub_ok(a, b, NULL); return back; } dk3_um_t dk3ma_mu_mul(dk3_um_t a, dk3_um_t b) { dk3_um_t back = DK3_MAX_UINT_0; back = dk3ma_mu_mul_ok(a, b, NULL); return back; } dk3_um_t dk3ma_mu_div(dk3_um_t a, dk3_um_t b) { dk3_um_t back = DK3_MAX_UINT_0; back = dk3ma_mu_div_ok(a, b, NULL); return back; } /* Unsigned long */ unsigned long dk3ma_ul_add_ok(unsigned long a, unsigned long b, int *ec) { unsigned long back = 0UL; back = a + b; if((0xFFFFFFFFUL - a) < b) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } return back; } unsigned long dk3ma_ul_sub_ok(unsigned long a, unsigned long b, int *ec) { unsigned long back = 0UL; back = a - b; if(b > a) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } return back; } unsigned long dk3ma_ul_mul_ok(unsigned long a, unsigned long b, int *ec) { unsigned long back = 0UL; back = a * b; if(a) { if((0xFFFFFFFFUL / a) < b) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } return back; } unsigned long dk3ma_ul_div_ok(unsigned long a, unsigned long b, int *ec) { unsigned long back = 0UL; if(b) { back = a / b; } else { if(ec) { *ec = DK3_ERROR_MATH_DIVZERO; } } return back; } unsigned long dk3ma_ul_add(unsigned long a, unsigned long b) { unsigned long back = 0UL; back = dk3ma_ul_add_ok(a, b, NULL); return back; } unsigned long dk3ma_ul_sub(unsigned long a, unsigned long b) { unsigned long back = 0UL; back = dk3ma_ul_sub_ok(a, b, NULL); return back; } unsigned long dk3ma_ul_mul(unsigned long a, unsigned long b) { unsigned long back = 0UL; back = dk3ma_ul_mul_ok(a, b, NULL); return back; } unsigned long dk3ma_ul_div(unsigned long a, unsigned long b) { unsigned long back = 0UL; back = dk3ma_ul_div_ok(a, b, NULL); return back; } /* Max signed */ dk3_im_t dk3ma_mi_abs(dk3_im_t a) { dk3_im_t back; if(a >= DK3_MAX_INT_0) { back = a; } else { back = DK3_MAX_INT_0 - a; } return back; } dk3_im_t dk3ma_mi_add_ok(dk3_im_t a, dk3_im_t b, int *ec) { dk3_im_t back = DK3_MAX_INT_0; if(a >= DK3_MAX_INT_0) { if(b >= DK3_MAX_INT_0) { back = a + b; if((DK3_MAX_INTMAX - a) < b) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { back = a + b; } } else { if(b >= DK3_MAX_INT_0) { back = a + b; } else { if(dk3ma_is_im_msb(a)) { back = a + b; if(b) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { if(dk3ma_is_im_msb(b)) { back = a + b; if(a) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { back = DK3_MAX_INT_0 - dk3ma_mi_add_ok(dk3ma_mi_abs(a),dk3ma_mi_abs(b),ec); } } } } return back; } dk3_im_t dk3ma_mi_sub_ok(dk3_im_t a, dk3_im_t b, int *ec) { dk3_im_t back = DK3_MAX_INT_0; if(a >= DK3_MAX_INT_0) { if(b >= DK3_MAX_INT_0) { back = a - b; } else { if(dk3ma_is_im_msb(b)) { back = a - b; if(a) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { back = dk3ma_mi_add_ok(a, dk3ma_mi_abs(b), ec); } } } else { if(b >= DK3_MAX_INT_0) { if(dk3ma_is_im_msb(a)) { back = a - b; if(b) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { back = DK3_MAX_INT_0 - dk3ma_mi_add_ok(b, dk3ma_mi_abs(a), ec); } } else { back = a - b; } } return back; } dk3_im_t dk3ma_mi_mul_ok(dk3_im_t a, dk3_im_t b, int *ec) { dk3_im_t back = DK3_MAX_INT_0; if(a >= DK3_MAX_INT_0) { if(b >= DK3_MAX_INT_0) { back = a * b; if(a) { if((DK3_MAX_INTMAX / a) < b) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } } else { if(dk3ma_is_im_msb(b)) { back = a * b; if((a > DK3_MAX_INT_1) || (a < DK3_MAX_INT_MINUS_1)) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { back = DK3_MAX_INT_0 - dk3ma_mi_mul_ok(a, dk3ma_mi_abs(b), ec); } } } else { if(b >= DK3_MAX_INT_0) { if(dk3ma_is_im_msb(a)) { back = a * b; if((b > DK3_MAX_INT_1) || (b < DK3_MAX_INT_MINUS_1)) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { back = DK3_MAX_INT_0 - dk3ma_mi_mul_ok(dk3ma_mi_abs(a), b, ec); } } else { if(dk3ma_is_im_msb(a)) { if(dk3ma_is_im_msb(b)) { back = a * b; if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } else { back = a * b; if((b > DK3_MAX_INT_1) || (b < DK3_MAX_INT_MINUS_1)) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } } else { if(dk3ma_is_im_msb(b)) { back = a * b; if((a > DK3_MAX_INT_1) || (a < DK3_MAX_INT_MINUS_1)) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { back = dk3ma_mi_mul_ok(dk3ma_mi_abs(a), dk3ma_mi_abs(b), ec); } } } } return back; } dk3_im_t dk3ma_mi_div_ok(dk3_im_t a, dk3_im_t b, int *ec) { dk3_im_t back = DK3_MAX_INT_0; if(b) { back = a / b; } else { if(ec) { *ec = DK3_ERROR_MATH_DIVZERO; } } return back; } dk3_im_t dk3ma_mi_add(dk3_im_t a, dk3_im_t b) { dk3_im_t back = DK3_MAX_INT_0; back = dk3ma_mi_add_ok(a, b, NULL); return back; } dk3_im_t dk3ma_mi_sub(dk3_im_t a, dk3_im_t b) { dk3_im_t back = DK3_MAX_INT_0; back = dk3ma_mi_sub_ok(a, b, NULL); return back; } dk3_im_t dk3ma_mi_mul(dk3_im_t a, dk3_im_t b) { dk3_im_t back = DK3_MAX_INT_0; back = dk3ma_mi_mul_ok(a, b, NULL); return back; } dk3_im_t dk3ma_mi_div(dk3_im_t a, dk3_im_t b) { dk3_im_t back = DK3_MAX_INT_0; back = dk3ma_mi_div_ok(a, b, NULL); return back; } /* Long */ #if DK3_HAVE_LABS /** Use implementation from runtime/math library. */ #define LABS(x) labs(x) #else /** Fallback implementation of labs() for systems without. @param l Value to obtain absolute value for. @return Absolute value. */ static long dk3ma_fallback_labs(long l) { long back; if(l >= 0UL) back = l; else back = 0L - l; return back; } /** Use fallback implementation. */ #define LABS(x) dk3ma_fallback_labs(x) #endif long dk3ma_l_add_ok(long a, long b, int *ec) { long back = 0L; $? "+ dk3ma_l_add_ok %ld %ld (%08lx %08lx)", a, b, a, b if(a >= 0L) { if(b >= 0L) { $? ". a>=0 b>=0" back = a + b; if((0x7FFFFFFFL - a) < b) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { $? ". a>=0 b<0" back = a + b; } } else { if(b >= 0L) { $? ". a<0 b>=0" back = a + b; } else { $? ". a<0 b<0" if(dk3ma_is_l_msb(a)) { back = a + b; if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } else { if(dk3ma_is_l_msb(b)) { back = a + b; if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } else { back = 0L - dk3ma_l_add_ok(LABS(a), LABS(b), ec); } } } } $? "- dk3ma_l_add_ok %ld (%08lx)", back, back return back; } long dk3ma_l_sub_ok(long a, long b, int *ec) { long back = 0L; if(a >= 0L) { if(b >= 0L) { back = a - b; } else { if(dk3ma_is_l_msb(b)) { back = a - b; if(a) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { back = dk3ma_l_add_ok(a, LABS(b), ec); } } } else { if(b >= 0L) { if(dk3ma_is_l_msb(a)) { back = a - b; if(b) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { back = 0L - dk3ma_l_add_ok(b, LABS(a), ec); } } else { back = a - b; } } return back; } long dk3ma_l_mul_ok(long a, long b, int *ec) { long back = 0L; if(a >= 0L) { if(b >= 0L) { back = a * b; if(a) { if((0x7FFFFFFF / a) < b) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } } else { if(dk3ma_is_l_msb(b)) { back = a * b; if((a > 1L) || (a < -1L)) if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } else { back = 0L - dk3ma_l_mul_ok(a, LABS(b), ec); } } } else { if(b >= 0L) { if(dk3ma_is_l_msb(a)) { back = a * b; if((b > 1L) || (b < -1L)) if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } else { back = 0L - dk3ma_l_mul_ok(LABS(a), b, ec); } } else { if(dk3ma_is_l_msb(a)) { back = a * b; if((b > 1L) || (b < -1L)) if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } else { if(dk3ma_is_l_msb(b)) { back = a * b; if((a > 1L) || (a < -1L)) if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } else { back = dk3ma_l_mul_ok(LABS(a), LABS(b), ec); } } } } return back; } long dk3ma_l_div_ok(long a, long b, int *ec) { long back = 0L; if(b) { back = a / b; } else { if(ec) { *ec = DK3_ERROR_MATH_DIVZERO; } } return back; } long dk3ma_l_add(long a, long b) { long back = 0L; back = dk3ma_l_add_ok(a, b, NULL); return back; } long dk3ma_l_sub(long a, long b) { long back = 0L; back = dk3ma_l_sub_ok(a, b, NULL); return back; } long dk3ma_l_mul(long a, long b) { long back = 0L; back = dk3ma_l_mul_ok(a, b, NULL); return back; } long dk3ma_l_div(long a, long b) { long back = 0L; back = dk3ma_l_div_ok(a, b, NULL); return back; } /* double */ #if DK3_HAVE_FABS /** Use fabs() implementation from runtime/math library. */ #define FABS(x) fabs(x) #else /** Fallback implementation of fabs(). @param x Argument. @return Absolute value. */ static double dk3ma_fallback_fabs(double x) { double back; if(x >= 0.0) back = x; else back = 0.0 - x; return back; } /** Use fallback implementation of fabs(). */ #define FABS(x) dk3ma_fallback_fabs(x) #endif double dk3ma_d_add_ok(double a, double b, int *ec) { double back = 0.0; if(a >= 0.0) { if(b >= 0.0) { back = a + b; if((DK3_MAX_DOUBLE - a) < b) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { back = a + b; } } else { if(b >= 0.0) { back = a + b; } else { back = 0.0 - dk3ma_d_add_ok(FABS(a), FABS(b), ec); } } return back; } double dk3ma_d_sub_ok(double a, double b, int *ec) { double back = 0.0; if(a >= 0.0) { if(b >= 0.0) { back = a - b; } else { back = dk3ma_d_add_ok(a, FABS(b), ec); } } else { if(b >= 0.0) { back = 0.0 - dk3ma_d_add_ok(b, FABS(a), ec); } else { back = a - b; } } return back; } double dk3ma_d_mul_ok(double a, double b, int *ec) { double back = 0.0; if(a >= 0.0) { if(b >= 0.0) { back = a * b; if(a >= 1.0) { if((DK3_MAX_DOUBLE / a) < b) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } } else { back = 0.0 - dk3ma_d_mul_ok(a, FABS(b), ec); } } else { if(b >= 0.0) { back = 0.0 - dk3ma_d_mul_ok(b, FABS(a), ec); } else { back = dk3ma_d_mul_ok(FABS(a), FABS(b), ec); } } return back; } double dk3ma_d_div_ok(double a, double b, int *ec) { double back = 0.0; if(a >= 0.0) { if(b >= 0.0) { if(b >= 1.0) { back = a / b; } else { if((b * DK3_MAX_DOUBLE) > a) { back = a / b; } else { if(ec) { *ec = DK3_ERROR_MATH_DIVZERO; } } } } else { back = 0.0 - dk3ma_d_div_ok(a, FABS(b), ec); } } else { if(b >= 0.0) { back = 0.0 - dk3ma_d_div_ok(FABS(a), b, ec); } else { back = dk3ma_d_div_ok(FABS(a), FABS(b), ec); } } return back; } double dk3ma_d_add(double a, double b) { double back = 0.0; back = dk3ma_d_add_ok(a, b, NULL); return back; } double dk3ma_d_sub(double a, double b) { double back = 0.0; back = dk3ma_d_sub_ok(a, b, NULL); return back; } double dk3ma_d_mul(double a, double b) { double back = 0.0; back = dk3ma_d_mul_ok(a, b, NULL); return back; } double dk3ma_d_div(double a, double b) { double back = 0.0; back = dk3ma_d_div_ok(a, b, NULL); return back; } int dk3ma_uintmax_to_c8_string(char *rb, size_t sz, dk3_um_t va) { int back = 0; char buffer[128]; /* Temporary 8-bit character buffer for result. */ if((rb) && (sz)) { #if DK3_ON_WINDOWS sprintf(buffer, "%I64u", va); #else #if DK3_HAVE_LONG_LONG sprintf(buffer, "%llu", va); #else sprintf(buffer, "%lu", (unsigned long)va); #endif #endif if(dk3str_c8_len(buffer) < sz) { dk3str_c8_cpy(rb, buffer); back = 1; } } return back; } int dk3ma_uintmax_to_string(dkChar *rb, size_t sz, dk3_um_t va) { int back = 0; char buffer[128]; /* Temporary 8-bit character buffer for result. */ if((rb) && (sz)) { #if DK3_ON_WINDOWS sprintf(buffer, "%I64u", va); #else #if DK3_HAVE_LONG_LONG sprintf(buffer, "%llu", va); #else sprintf(buffer, "%lu", (unsigned long)va); #endif #endif if(dk3str_c8_len(buffer) < sz) { back = dk3str_cnv_c8_to_str_app(rb, sz, buffer, NULL); } } return back; } int dk3ma_uintmax_to_hex_string(dkChar *rb, size_t sz, dk3_um_t va) { int back = 0; char buffer[128]; /* Temporary 8-bit character buffer for result. */ if((rb) && (sz)) { #if DK3_ON_WINDOWS sprintf(buffer, "%016I64x", va); #else #if DK3_HAVE_LONG_LONG sprintf(buffer, "%016llx", va); #else sprintf(buffer, "%08lx", (unsigned long)va); #endif #endif if(dk3str_c8_len(buffer) < sz) { back = dk3str_cnv_c8_to_str_app(rb, sz, buffer, NULL); } } return back; } int dk3ma_uintmax_from_c8_string(dk3_um_t *va, char const *s) { int back = 0; char const *ptr; if((va) && (s)) { ptr = dk3str_c8_start(s, NULL); if(ptr) { switch(*ptr) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { #if DK3_ON_WINDOWS if(sscanf(s, "%I64u", va) == 1) { back = 1; } #else #if DK3_HAVE_LONG_LONG if(sscanf(s, "%llu", va) == 1) { back = 1; } #else unsigned long ul; if(sscanf(s, "%lu", &ul) == 1) { *va = (dk3_um_t)ul; back = 1; } #endif #endif } break; } } } return back; } int dk3ma_uintmax_from_string(dk3_um_t *va, dkChar const *s) { int back = 0; char buffer[1024]; /* Temporary 8-bit character buffer for conversion. */ if((va) && (s)) { dk3str_string_to_c8_simple_app(buffer, sizeof(buffer), s, NULL); back = dk3ma_uintmax_from_c8_string(va, buffer); } return back; } int dk3ma_intmax_to_c8_string(char *rb, size_t sz, dk3_im_t va) { int back = 0; char buffer[128]; /* Temporary 8-bit character buffer for conversion. */ if((rb) && (sz)) { #if DK3_ON_WINDOWS sprintf(buffer, "%I64d", va); #else #if DK3_HAVE_LONG_LONG sprintf(buffer, "%lld", va); #else sprintf(buffer, "%ld", (unsigned long)va); #endif #endif if(dk3str_c8_len(buffer) < sz) { dk3str_c8_cpy(rb, buffer); back = 1; } } return back; } int dk3ma_intmax_to_string(dkChar *rb, size_t sz, dk3_im_t va) { int back = 0; char buffer[128]; /* Temporary 8-bit character buffer for conversion. */ if((rb) && (sz)) { #if DK3_ON_WINDOWS sprintf(buffer, "%I64d", va); #else #if DK3_HAVE_LONG_LONG sprintf(buffer, "%lld", va); #else sprintf(buffer, "%ld", (unsigned long)va); #endif #endif if(dk3str_c8_len(buffer) < sz) { back = dk3str_cnv_c8_to_str_app(rb, sz, buffer, NULL); } } return back; } int dk3ma_intmax_from_c8_string(dk3_im_t *va, char const *s) { int back = 0; char const *ptr; if((va) && (s)) { ptr = dk3str_c8_start(s, NULL); if(ptr) { switch(*ptr) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': { #if DK3_ON_WINDOWS if(sscanf(s, "%I64d", va) == 1) { back = 1; } #else #if DK3_HAVE_LONG_LONG if(sscanf(s, "%lld", va) == 1) { back = 1; } #else unsigned long ul; if(sscanf(s, "%ld", &ul) == 1) { *va = (dk3_im_t)ul; back = 1; } #endif #endif } break; } } } return back; } int dk3ma_intmax_from_string(dk3_im_t *va, dkChar const *s) { int back = 0; char buffer[1024]; /* Temporary 8-bit character buffer for conversion. */ if((va) && (s)) { dk3str_string_to_c8_simple_app(buffer, sizeof(buffer), s, NULL); back = dk3ma_intmax_from_c8_string(va, buffer); } return back; } dk3_um_t dk3ma_mu_gcd(dk3_um_t u1, dk3_um_t u2) { dk3_um_t a = DK3_MAX_UINT_0; dk3_um_t b = DK3_MAX_UINT_0; dk3_um_t h = DK3_MAX_UINT_0; a = u1; b = u2; while(b > DK3_MAX_UINT_0) { h = a % b; a = b; b = h; } if(a == DK3_MAX_UINT_0) a = DK3_MAX_UINT_1; return a; } dk3_im_t dk3ma_mi_gcd(dk3_im_t u1, dk3_im_t u2) { dk3_im_t a = DK3_MAX_INT_0; dk3_im_t b = DK3_MAX_INT_0; dk3_im_t h = DK3_MAX_INT_0; if(u1 >= DK3_MAX_INT_0) { if(u2 >= DK3_MAX_INT_0) { a = u1; b = u2; while(b > DK3_MAX_INT_0) { h = a % b; a = b; b = h; } } else { a = dk3ma_mi_gcd(u1, dk3ma_mi_abs(u2)); } } else { if(u2 >= DK3_MAX_INT_0) { a = dk3ma_mi_gcd(dk3ma_mi_abs(u1), u2); } else { a = dk3ma_mi_gcd(dk3ma_mi_abs(u1), dk3ma_mi_abs(u2)); } } if(a == DK3_MAX_INT_0) a = DK3_MAX_INT_1; return a; } unsigned long dk3ma_ul_gcd(unsigned long u1, unsigned long u2) { unsigned long a = 0UL; unsigned long b = 0UL; unsigned long h = 0UL; a = u1; b = u2; while(b > 0UL) { h = a % b; a = b; b = h; } if(a == 0UL) a = 1UL; return a; } long dk3ma_l_gcd(long u1, long u2) { long a = 0L; long b = 0L; long h = 0L; if(u1 >= 0L) { if(u2 >= 0L) { a = u1; b = u2; while(b > 0L) { h = a % b; a = b; b = h; } } else { a = dk3ma_l_gcd(u1, LABS(u2)); } } else { if(u2 >= 0L) { a = dk3ma_l_gcd(LABS(u1), u2); } else { a = dk3ma_l_gcd(LABS(u1), LABS(u2)); } } if(a == 0L) a = 1L; return a; } double dk3ma_rint(double x) { double back; #if DK3_HAVE_RINT back = rint(x); #else if(x < 0.0) { back = 0.0 - dk3ma_rint(0.0 - x); } else { #if DK3_HAVE_FLOOR back = floor(x + 0.5); #else #error "Not supported!" #endif } #endif return back; } #if !DK3_HAVE_COMPILER_CONVERSIONS /* untested */ /** Convert double to long. @param x Double to convert. @return Conversion result. */ static unsigned long my_d_to_ul(double x) { unsigned long back = 0UL; unsigned long testbit = 0UL; /* Current bit to test. */ double v = 0.0; /* Remaining value. */ double testval = 0.0; /* Test value. */ v = x; testbit = DK3_UL_FIRST_BIT; testval = DK3_UL_FIRST_BIT_AS_DOUBLE; while(testbit) { if(v >= testval) { v = v - testval; back |= testbit; } testbit = testbit / 2UL; testval = testval / 2.0; } return back; } /* untested */ /** Convert double to long. @param x Value to convert. @return Conversion result. */ static long my_d_to_l(double x) { long back = 0L; long testbit = 0L; /* Bit to test/add. */ double v = 0.0; /* Remaining value. */ double testval = 0.0; /* Test value. */ v = x; testbit = DK3_L_FIRST_BIT; testval = DK3_L_FIRST_BIT_AS_DOUBLE; while(testbit) { if(v >= testval) { v = v - testval; back |= testbit; } testbit = testbit / 2L; testval = testval / 2.0; } return back; } /* untested */ /** Convert double to maximum length unsigned. @param x Value to convert. @return Conversion result. */ static dk3_um_t my_d_to_mu(double x) { dk3_um_t back = DK3_MAX_UINT_0; dk3_um_t testbit = DK3_MAX_UINT_0; /* Bit to test/add. */ double v = 0.0; /* Remaining value. */ double testval = 0.0; /* Test value. */ v = x; testbit = DK3_MAX_UINT_FIRST_BIT; testval = DK3_MAX_UINT_FIRST_BIT_AS_DOUBLE; while(testbit) { if(v >= testval) { v = v - testval; back |= testbit; } testbit = testbit / DK3_MAX_UINT_2; testval = testval / 2.0; } return back; } /* untested */ /** Convert double to maximum length integer. @param x Value to convert. @return Conversion result. */ static dk3_im_t my_d_to_mi(double x) { dk3_im_t back = DK3_MAX_INT_0; dk3_im_t testbit = DK3_MAX_INT_0; /* Bit to test/add. */ double v = 0.0; /* Remaining value. */ double testval = 0.0; /* Test value. */ v = x; testbit = DK3_MAX_INT_FIRST_BIT; testval = DK3_MAX_INT_FIRST_BIT_AS_DOUBLE; while(testbit) { if(v >= testval) { v = v - testval; back |= testbit; } testbit = testbit / DK3_MAX_INT_2; testval = testval / 2.0; } return back; } /* untested */ /** Convert maximum length unsigned to double. @param x Value to convert. @return Conversion result. */ static double my_mu_to_d(dk3_um_t x) { double back = 0.0; dk3_um_t testbit = DK3_MAX_UINT_FIRST_BIT; /* Bit to test/add. */ double testval = DK3_MAX_UINT_FIRST_BIT_AS_DOUBLE; /* Test value. */ while(testbit) { if(x & testbit) { back += testval; } testbit = testbit / DK3_MAX_UINT_2; testval = testval / 2.0; } return back; } /* untested */ /** Convert maximum length integer to double. @param x Value to convert. @return Conversion result. */ static double my_mi_to_d(dk3_im_t x) { double back = 0.0; dk3_im_t testbit = DK3_MAX_INT_FIRST_BIT; /* Bit to test/add. */ double testval = DK3_MAX_UINT_FIRST_BIT_AS_DOUBLE; /* Test value. */ if(x >= DK3_MAX_INT_0) { while(testbit) { if(x & testbit) { back += testval; } testbit = testbit / DK3_MAX_INT_2; testval = testval / 2.0; } } else { back = 0.0 - my_mi_to_d(DK3_MAX_INT_0 - x); } return back; } /* untested */ /** Convert unsigned long to double. @param x Value to convert. @return Conversion result. */ static double my_ul_to_d(unsigned long x) { double back = 0.0; unsigned long testbit = DK3_UL_FIRST_BIT; /* Bit to test/add. */ double testval = 2147483647.0; /* Test value. */ while(testbit) { if(x & testbit) { back += testval; } testbit = testbit / 2UL; testval = testval / 2.0; } return back; } /* untested */ /** Convert long to double. @param x Value to convert. @return Conversion result. */ static double my_l_to_d(long x) { double back = 0.0; long testbit = DK3_L_FIRST_BIT; /* Bit to test/add. */ double testval = DK3_L_FIRST_BIT_AS_DOUBLE; /* Test value. */ if(x >= 0L) { while(testbit) { if(x & testbit) { back += testval; } testbit = testbit / 2L; testval = testval / 2.0; } } else { back = 0.0 - my_l_to_d(0L - x); } return back; } #endif /* untested */ unsigned long dk3ma_d_to_ul_ok(double x, int *ec) { unsigned long back = 0UL; double y = 0.0; /* Rounded value. */ if(x >= 0.0) { y = dk3ma_rint(x); if(y > DK3_UL_MAX_AS_DOUBLE) { if(ec) *ec = DK3_ERROR_MATH_OVERFLOW; } else { #if DK3_HAVE_COMPILER_CONVERSIONS back = (unsigned long)y; #else back = my_d_to_ul(y); #endif } } else { if(ec) *ec = DK3_ERROR_MATH_OVERFLOW; } return back; } /* untested */ long dk3ma_d_to_l_ok(double x, int *ec) { double y = 0.0; /* Rounded value. */ long back = 0L; y = dk3ma_rint(x); if(y >= 0.0) { if(y > DK3_L_MAX_AS_DOUBLE) { if(ec) *ec = DK3_ERROR_MATH_OVERFLOW; } else { #if DK3_HAVE_COMPILER_CONVERSIONS back = (long)y; #else back = my_d_to_l(y); #endif } } else { back = 0L - dk3ma_d_to_l_ok(0.0 - x, ec); } return back; } /* untested */ dk3_um_t dk3ma_d_to_mu_ok(double x, int *ec) { dk3_um_t back = DK3_MAX_UINT_0; double y = 0.0; /* Rounded value. */ if(x >= 0.0) { y = dk3ma_rint(x); if(y > DK3_MAX_UINT_AS_DOUBLE) { if(ec) *ec = DK3_ERROR_MATH_OVERFLOW; } else { #if DK3_HAVE_COMPILER_CONVERSIONS back = (dk3_um_t)y; #else back = my_d_to_mu(y); #endif } } else { if(ec) *ec = DK3_ERROR_MATH_OVERFLOW; } return back; } /* untested */ dk3_im_t dk3ma_d_to_mi_ok(double x, int *ec) { dk3_im_t back = DK3_MAX_INT_0; double y = 0.0; /* Rounded value. */ if(x >= 0.0) { y = dk3ma_rint(x); if(y > DK3_MAX_INT_AS_DOUBLE) { if(ec) *ec = DK3_ERROR_MATH_OVERFLOW; } else { #if DK3_HAVE_COMPILER_CONVERSIONS back = (dk3_im_t)y; #else back = my_d_to_mi(y); #endif } } else { back = DK3_MAX_INT_0 - dk3ma_d_to_mi_ok(0.0 - x, ec); } return back; } double dk3ma_mu_to_d(dk3_um_t x) { double back; #if DK3_HAVE_COMPILER_CONVERSIONS back = (double)x; #else back = my_mu_to_d(x); #endif return back; } double dk3ma_mi_to_d(dk3_im_t x) { double back; #if DK3_HAVE_COMPILER_CONVERSIONS back = (double)x; #else back = my_mi_to_d(x); #endif return back; } double dk3ma_ul_to_d(unsigned long x) { double back; #if DK3_HAVE_COMPILER_CONVERSIONS back = (double)x; #else back = my_ul_to_d(x); #endif return back; } double dk3ma_l_to_d(long x) { double back; #if DK3_HAVE_COMPILER_CONVERSIONS back = (double)x; #else back = my_l_to_d(x); #endif return back; } size_t dk3ma_sz_add_ok(size_t a, size_t b, int *ec) { size_t back = 0; back = a + b; if(b >= (DK3_SIZE_T_MAX - a)) { back = 0; if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } return back; } size_t dk3ma_sz_mul_ok(size_t a, size_t b, int *ec) { size_t back = 0; if((a) && (b)) { if(b < (DK3_SIZE_T_MAX / a)) { back = a * b; } else { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } return back; } double dk3ma_atan2(double y, double x) { #if DK3_HAVE_ATAN2 double back; $? "+ dk3ma_atan2_ok y=%lg x=%lg", y, x back = atan2(y, x); $? ". back = %lg", back while(back < 0.0) { back += (2.0 * M_PI); } while(back > (2.0 * M_PI)) { back -= (2.0 * M_PI); } $? "- dk3ma_atan2_ok (atan2) %lg", back return back; #else double back = -5.0 * M_PI; double v; $? "+ dk3ma_atan2_ok y=%lg x=%lg", y, x v = dk3ma_d_div_ok(y, x, &mec); if(mec) { $? ". division error" if(y < 0.0) { $? ". negative y" back = 1.5 * M_PI; } else { $? ". positive y" back = 0.5 * M_PI; } } else { $? ". use atan" back = atan(v); if(x < 0.0) { $? ". add pi" back += M_PI; } } $? ". back = %lg", back while(back < 0.0) { back += (2.0 * M_PI); } while(back > (2.0 * M_PI)) { back -= (2.0 * M_PI); } $? "- dk3ma_atan2_ok (atan) %lg", back return back; #endif } int dk3ma_d_equal(double a, double b, double epsilon) { int back = 0; int ec = 0; if(fabs(dk3ma_d_sub_ok(a, b, &ec)) < epsilon) { back = 1; if(ec) { back = 0; } } return back; } double dk3ma_d_square_ok(double x, int *ec) { double back; back = dk3ma_d_mul_ok(x, x, ec); return back; } double dk3ma_restrict_digits(double x, size_t n) { double back; double newval; size_t i; size_t mult; int ec = 0; back = x; mult = 0; /* Multiplications */ for(i = 0; ((0 == ec) && (i < n)); i++) { newval = dk3ma_d_mul_ok(back, 10.0, &ec); if(0 == ec) { back = newval; mult++; } } /* Rounding */ back = dk3ma_rint(back); /* Divisions */ for(i = 0; i < mult; i++) { back = back / 10.0; } return back; } double dk3ma_restrict_digits_ceil(double x, size_t n) { double back; double newval; size_t i; size_t mult; int ec = 0; back = x; mult = 0; /* Multiplications */ for(i = 0; ((0 == ec) && (i < n)); i++) { newval = dk3ma_d_mul_ok(back, 10.0, &ec); if(0 == ec) { back = newval; mult++; } } /* Rounding */ back = ceil(back); /* Divisions */ for(i = 0; i < mult; i++) { back = back / 10.0; } return back; } double dk3ma_restrict_digits_floor(double x, size_t n) { double back; double newval; size_t i; size_t mult; int ec = 0; back = x; mult = 0; /* Multiplications */ for(i = 0; ((0 == ec) && (i < n)); i++) { newval = dk3ma_d_mul_ok(back, 10.0, &ec); if(0 == ec) { back = newval; mult++; } } /* Rounding */ back = floor(back); /* Divisions */ for(i = 0; i < mult; i++) { back = back / 10.0; } return back; } size_t dk3ma_d_to_size_ok(double v, int *ec) { size_t back = 0; if(0 <= v) { if((double)(DK3_SIZE_T_MAX) > v) { #if DK3_HAVE_COMPILER_CONVERSIONS back = (size_t)v; #else back = (size_t)dk3ma_d_to_ul_ok(v, ec); #endif } else { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } } else { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } return back; } #if VERSION_BEFORE_20130105 void dk3ma_print_double_c8_str_no_sci(FILE *of, char *buffer) { char *start; /* Start of string. */ char *eptr; /* Start of exponent substring. */ char *ptr; /* Traverse string. */ size_t lgt; /* String length. */ int dp; /* Decimal dot position. */ int exponent; /* Exponent. */ int i; /* Traverse the string. */ $? "+ dk3ma_print_double_c8_str_no_sci" if((of) && (buffer)) { eptr = NULL; start = buffer; /* Print sign. */ switch(*start) { case '-': { fputc('-', of); start++; } break; case '+': { start++; } break; } /* Find exponent substring. */ eptr = NULL; ptr = start; while(*ptr) { switch(*ptr) { case 'e': case 'E': { eptr = ptr; } break; } ptr++; } if(eptr) { *(eptr++) = '\0'; if(sscanf(eptr, "%d", &exponent) == 1) { if(0 == exponent) { /* Exponent is 0, print string as is. */ fputs(start, of); } else { /* Find decimal dot. */ eptr = strchr(start, '.'); if(eptr) { /* Keep dot position in dp, squeeze string. */ *eptr = '\0'; dp = (int)strlen(start); *eptr = '.'; while(*eptr) { eptr[0] = eptr[1]; eptr++; } } else { /* Dot position is after the string. */ dp = (int)strlen(start); } /* Correct dot position. */ dp = dp + exponent; /* Remove leading zeroes (if any). */ while('0' == *start) { start++; dp--; } /* Remove trailing zeroes (if any). */ eptr = NULL; ptr = start; while(*ptr) { if('0' == *ptr) { if(!(eptr)) { eptr = ptr; } } else { eptr = NULL; } ptr++; } if(eptr) { *eptr = '\0'; } lgt = strlen(start); if(0 < lgt) { if(dp >= (int)lgt) { /* Decimal dot is at end or after string. */ fputs(start, of); /* Decimal dot is after the string. */ for(i = 0; i < (dp - (int)lgt); i++) { fputc('0', of); } } else { if(dp <= 0) { /* Decimal dot is before the string. */ fputc('0', of); fputc('.', of); while(dp++ < 0) { fputc('0', of); } fputs(start, of); } else { /* Decimal dot is in the string. */ for(i = 0; i < (int)lgt; i++) { if(dp == i) { fputc('.', of); } fputc(start[i], of); } } } } else { /* No non-zero digits in string. */ fputc('0', of); } } } else { /* Failed to read exponent substring. Print string as is. */ fputs(start, of); } } else { /* No exponent substring, print string as is. */ fputs(start, of); } } $? "- dk3ma_print_double_c8_str_no_sci" } #endif void dk3ma_print_double_c8_str_no_sci(FILE *of, char *buffer) { char *start; /* Start of string. */ char *eptr; /* Start of exponent substring. */ char *ptr; /* Traverse string. */ size_t lgt; /* String length. */ int dp; /* Decimal dot position. */ int exponent; /* Exponent. */ int i; /* Traverse the string. */ $? "+ dk3ma_print_double_c8_str_no_sci" if((of) && (buffer)) { eptr = NULL; start = buffer; /* Print sign. */ switch(*start) { case '-': { fputc('-', of); start++; } break; case '+': { start++; } break; } /* Find exponent substring and exponent. */ eptr = NULL; ptr = start; while(*ptr) { switch(*ptr) { case 'e': case 'E': { eptr = ptr; } break; } ptr++; } if(eptr) { *(eptr++) = '\0'; if(sscanf(eptr, "%d", &exponent) != 1) { exponent = 0; } } else { exponent = 0; } /* Find decimal dot. */ eptr = strchr(start, '.'); if(eptr) { /* Keep dot position in dp, squeeze string. */ *eptr = '\0'; dp = (int)strlen(start); *eptr = '.'; while(*eptr) { eptr[0] = eptr[1]; eptr++; } } else { /* Dot position is after the string. */ dp = (int)strlen(start); } /* Correct dot position. */ dp = dp + exponent; /* Remove leading zeroes (if any). */ while('0' == *start) { start++; dp--; } /* Remove trailing zeroes (if any). */ eptr = NULL; ptr = start; while(*ptr) { if('0' == *ptr) { if(!(eptr)) { eptr = ptr; } } else { eptr = NULL; } ptr++; } if(eptr) { *eptr = '\0'; } lgt = strlen(start); if(0 < lgt) { if(dp >= (int)lgt) { /* Decimal dot is at end or after string. */ fputs(start, of); /* Decimal dot is after the string. */ for(i = 0; i < (dp - (int)lgt); i++) { fputc('0', of); } } else { if(dp <= 0) { /* Decimal dot is before the string. */ fputc('0', of); fputc('.', of); while(dp++ < 0) { fputc('0', of); } fputs(start, of); } else { /* Decimal dot is in the string. */ for(i = 0; i < (int)lgt; i++) { if(dp == i) { fputc('.', of); } fputc(start[i], of); } } } } else { /* No non-zero digits in string. */ fputc('0', of); } } $? "- dk3ma_print_double_c8_str_no_sci" } void dk3ma_print_double_c8_no_sci(FILE *of, double x) { char buffer[64]; $? "+ dk3ma_print_double_c8_no_sci" if(of) { sprintf(buffer, "%lg", x); dk3ma_print_double_c8_str_no_sci(of, buffer); } $? "- dk3ma_print_double_c8_no_sci" } /* vim: set ai sw=2 : */