#define msec_to_fosa_time(msec) (msec) * 1000000
#define fosa_time_to_usec(time) (time) / 1000
#define usec_to_fosa_time(usec) (usec) * 1000
+#define fosa_time_to_nsec(time) (time)
+#define nsec_to_fosa_time(nsec) (nsec)
+
#define timespec_to_fosa_time(time_type, tspec) ((time_type) (tspec).tv_sec) * 1000000000 + (time_type) (tspec).tv_nsec
(tspec).tv_nsec = (time) % 1000000000; \
} while(0)
-
+#define fosa_time_to_double(time) (double) (time) * 1e-9;
+#define fosa_double_to_time(time_type, time) (time_type) (time * 1e9)
#endif
#define msec_to_fosa_time(msec) (msec) * 1000
#define fosa_time_to_usec(time) (time)
#define usec_to_fosa_time(usec) (usec)
+#define fosa_time_to_nsec(time) (time) * 1000
+#define nsec_to_fosa_time(nsec) (nsec) / 1000
#define timespec_to_fosa_time(time_type, tspec) ( (time_type) (tspec).tv_sec) * 1000000 + (time_type) (tspec).tv_nsec/1000
(tspec).tv_nsec = ( (time) % 1000000) * 1000; \
} while(0)
+#define fosa_time_to_double(time) (double) (time) * 1e-6;
+#define fosa_double_to_time(time_type, time) (time_type) (time * 1e6)
#endif
#define msec_to_fosa_time(msec) (msec)
#define fosa_time_to_usec(time) (time) * 1000
#define usec_to_fosa_time(usec) (usec) / 1000
+#define fosa_time_to_nsec(time) (time) * 1000000
+#define nsec_to_fosa_time(nsec) (nsec) / 1000000
#define timespec_to_fosa_time(time_type, tspec) ( (time_type) (tspec).tv_sec) * 1000 + (time_type) (tspec).tv_nsec/1000000
(tspec).tv_nsec = ( (time) % 1000) * 1000000; \
} while(0)
+#define fosa_time_to_double(time) (double) (time) * 1e-3;
+#define fosa_double_to_time(time_type, time) (time_type) (time) * 1e3
+
#endif
return result;
}
+// ---------------------------------------------------------
+
+
+static inline fosa_rel_time_t fosa_rel_time_times_integer(fosa_rel_time_t time, long multiplier)
+{
+ fosa_rel_time_t result;
+
+ result = time * multiplier;
+
+ return result;
+}
+
+
+// ---------------------------------------------------------
+
+static inline fosa_rel_time_t fosa_rel_time_divided_by_integer(fosa_rel_time_t time, long divider)
+{
+ return time / divider;
+}
+
+
+
+
/* Comparison */
/**************/
}
+// -----------------------------------------------------------
+
+static inline bool fosa_rel_time_equal(fosa_rel_time_t relt1, fosa_rel_time_t relt2)
+{
+ bool result;
+
+ result = relt1 == relt2;
+
+ return result;
+}
+
+
+// -----------------------------------------------------------
+
+static inline bool fosa_abs_time_equal(fosa_abs_time_t abst1, fosa_abs_time_t abst2)
+{
+ bool result;
+
+ result = abst1 == abst2;
+
+ return result;
+}
+
+// -----------------------------------------------------------
+
+static inline bool fosa_rel_time_is_null(fosa_rel_time_t relt)
+{
+ bool result;
+
+ result = relt == 0;
+
+ return result;
+}
+
+
+// -----------------------------------------------------------
+
+static inline bool fosa_abs_time_is_null(fosa_abs_time_t abst)
+{
+ bool result;
+
+ result = abst == 0;
+
+ return result;
+}
+
+
+
/* Conversion */
/**************/
static inline fosa_rel_time_t fosa_msec_to_rel_time(long msec)
}
+
+// --------------------------------------------------
+
+static inline fosa_rel_time_t fosa_nsec_to_rel_time(long nsec)
+{
+ fosa_rel_time_t result;
+
+ result = nsec_to_fosa_time((fosa_rel_time_t ) nsec);
+
+ return result;
+}
+
+// --------------------------------------------------
+
+static inline long fosa_rel_time_to_nsec(fosa_rel_time_t relt)
+{
+ long result;
+
+ result = fosa_time_to_nsec(relt);
+
+ return result;
+}
+
+
+// --------------------------------------------------
+
+static inline fosa_abs_time_t fosa_nsec_to_abs_time(long nsec)
+{
+ fosa_abs_time_t result;
+
+ result = nsec_to_fosa_time( (fosa_abs_time_t) nsec);
+
+ return result;
+}
+
+// --------------------------------------------------
+
+static inline long fosa_abs_time_to_nsec(fosa_abs_time_t abst)
+{
+ long result;
+
+ result = fosa_time_to_nsec(abst);
+
+ return result;
+}
+
// --------------------------------------------------
static inline fosa_rel_time_t fosa_timespec_to_rel_time(struct timespec time_tspec)
}
+
+// --------------------------------------------------
+
+static inline double fosa_rel_time_to_double(fosa_rel_time_t relt)
+{
+ double result;
+
+ result = fosa_time_to_double(relt);
+ return result;
+}
+
+
+// --------------------------------------------------
+
+static inline double fosa_double_to_rel_time(double time)
+{
+ fosa_rel_time_t result;
+
+ result = fosa_double_to_time(fosa_rel_time_t, time);
+ return result;
+}
+
+
+
+
#endif /* !FOSA_TIME_H_ */
#ifndef FOSA_TIME_TIMESPEC_H_
#define FOSA_TIME_TIMESPEC_H_
+#include <stdlib.h>
+#include <assert.h>
/**********************************/
/* T I M E S P E C M A C R O S */
/**********************************/
+#define normalize_timespec(t1) \
+do \
+{ \
+ if ((t1).tv_nsec >= 1000000000) \
+ { \
+ (t1).tv_sec++; \
+ (t1).tv_nsec -= 1000000000; \
+ } \
+} while(0)
+
+
#define add_timespec(sum, t1, t2) \
do { \
(sum).tv_sec = (t1).tv_sec + (t2).tv_sec; \
(sum).tv_nsec = (t1).tv_nsec + (t2).tv_nsec; \
- if ((sum).tv_nsec >= 1000000000) \
- { \
- (sum).tv_sec++; \
- (sum).tv_nsec -= 1000000000; \
- } \
+ normalize_timespec(sum); \
} while(0)
+
// -------------------------------------------------------------------
/* TODO: Test that for past > future we obtain a correct negative
( ((t1).tv_sec % 2148) * 1000000 + (t1).tv_nsec/1000 )
+// ---------------------------------------------------------
+
+#define nsec_to_timespec(tspec, nsec) \
+do { \
+ if ((nsec) >= 1000000000) { \
+ (tspec).tv_sec = (nsec)/1000000000; \
+ (tspec).tv_nsec = (nsec) % 1000000000; \
+ } else { \
+ (tspec).tv_sec = 0; \
+ (tspec).tv_nsec = (nsec); \
+ } \
+} while(0)
+
+// ---------------------------------------------------------
+
+#define timespec_to_nsec(t1) \
+ ( ((t1).tv_sec % 2) * 1000000000 + (t1).tv_nsec )
+
+
+
+// ---------------------------------------------------------
+
+#define timespec_equal(t1, t2) ( (t1).tv_sec == (t2).tv_sec ) && ( (t1).tv_nsec == (t2).tv_nsec )
+
+#define timespec_is_null(t1) ( (t1).tv_sec == 0 ) && ( (t1).tv_nsec == 0 )
+
+
/***************************************/
/* T I M E S P E C F U N C T I O N S */
/***************************************/
{
fosa_abs_time_t result;
-
-
substract_timespec(result, base, interval);
return result;
}
-
// ---------------------------------------------------------
static inline fosa_rel_time_t fosa_rel_time_decr(fosa_rel_time_t total, fosa_rel_time_t part)
return result;
}
+// ---------------------------------------------------------
+
+/**
+ * exact_long_multiply_smaller_10e5()
+ *
+ * Same as below but with operands smaller than 10000 which allows
+ * to perform all component multiplications without an overflow risk.
+ **/
+static inline struct timespec exact_long_multiply_smaller_10e5(long t, long k)
+{
+ /* Since operands are smaller than 10e5 we can use 1000 */
+ /* the base without risking to cause overflows in the */
+ /* operations. */
+ /********************************************************/
+ assert(t < 10000);
+ assert(k < 10000);
+
+ struct timespec result;
+
+ long base = 1000;
+
+ long t_high = t / base;
+ long t_low = t % base;
+ long k_high = k / base;
+ long k_low = k % base;
+
+ long thkh = t_high * k_high;
+ long thkl = t_high * k_low;
+ long tlkh = t_low * k_high;
+ long tlkl = t_low * k_low;
+
+ long thkl_high = thkl / base;
+ long tlkh_high = tlkh / base;
+ long thkl_low = thkl % base;
+ long tlkh_low = tlkh % base;
+
+ long c2 = thkh + thkl_high + tlkh_high; // Normalized at 10^6
+ long c1 = thkl_low + tlkh_low; // Normalized at 10^3
+ long c0 = tlkl;
+
+ result.tv_sec = c2/1000 + c1/1000000;
+ result.tv_nsec = (c2 % 1000) * 1000000 + (c1 % 1000000) * 1000 + c0;
+
+ result.tv_sec += (result.tv_nsec / 1000000000);
+ result.tv_nsec %= 1000000000;
+
+ return result;
+}
+
+
+// -------------------------------------------------------------
+
+
+
+/**
+ * exact_long_multiply()
+ *
+ * This function performs an exact long * long operations on operands
+ * lower than 1e9 without using more than 32bit (1e9) arithmetic.
+ *
+ * To achieve this we decompose the operands in high and low:
+ *
+ * num = (num/base) * base + (num % base)
+ * ^^^^^^^^ ^^^^^^^^^^^^
+ * high component low component
+ *
+ * t * k = (th*kh + th*kl/base + tl*kh/base )*base^2
+ * + (th*kl % base)*base + (tl*kh % base) * base + tl*kl
+ *
+ * The problem is that we cannot use an exact base because sqrt(1e9)
+ * is not a multiple of 1e9 (in fact it is not even integer).
+ *
+ * So we use as a base 100000 which means that the last term tl*kl may
+ * need another exact calculation with a lower base (100)
+ **/
+static inline struct timespec exact_long_multiply(long t, long k)
+{
+ struct timespec result;
+
+ long t_high;
+ long t_low;
+ long k_high;
+ long k_low;
+
+ long base = 100000; /* Power of 10 closest to sqrt(1e9) from
+ * above */
+
+ t_high = t / base;
+ t_low = t % base; // Between 0 99999
+ k_high = k / base;
+ k_low = k % base; // Between 0 99999
+
+ /* These numbers are always lower than 1e9 */
+ long thkh = t_high * k_high;
+ long thkl = t_high * k_low;
+ long tlkh = t_low * k_high;
+
+ long thkl_high = thkl / base;
+ long thkl_low = thkl % base;
+ long tlkh_high = tlkh / base;
+ long tlkh_low = tlkh % base;
+
+ /* We can calculate the base^2 term (note however that this is 10
+ * times the tv_sec component because it is multiplied by 10^10 */
+ long c2 = thkh + thkl_high + tlkh_high; // scaled to 10^10
+ long c1 = thkl_low + tlkh_low; // scaled to 10^5
+
+ struct timespec c0;
+
+ /* Now we can write the initial values of result */
+ result.tv_sec = c2*10 + c1/10000;
+ result.tv_nsec = (c1 % 10000) * 100000;
+
+ normalize_timespec(result);
+
+ /* To calculate c0 we must check if there is a risk of overflow */
+ /* Remember operands cannot be larger than 99999 and result */
+ /* larger than 1e9. */
+ /****************************************************************/
+ bool overflow_risk;
+ overflow_risk = false;
+
+ if (
+ ( (t_low > 31622) && (k_low >= 10000) ) ||
+ ( (k_low > 31622) && (t_low >= 10000) )
+ )
+ {
+ overflow_risk = true;
+ }
+
+ if (! overflow_risk)
+ {
+ c0.tv_sec = 0;
+ c0.tv_nsec = t_low * k_low;
+ normalize_timespec(c0);
+ }
+ else
+ {
+ c0 = exact_long_multiply_smaller_10e5(t_low, k_low);
+ }
+ add_timespec(result, result, c0);
+
+ return result;
+}
+
+// -------------------------------------------------------------
+
+
+static inline fosa_rel_time_t fosa_rel_time_times_integer(fosa_rel_time_t time, long multiplier)
+{
+ struct timespec result;
+ struct timespec intermediate;
+
+ result.tv_sec = time.tv_sec * multiplier; // No overflow check here
+ result.tv_nsec = 0;
+
+ intermediate = exact_long_multiply(time.tv_nsec, multiplier);
+
+ add_timespec(result, result, intermediate);
+
+ return result;
+}
+
+// ---------------------------------------------------------
+
+static inline fosa_rel_time_t fosa_rel_time_divided_by_integer(fosa_rel_time_t time, long divider)
+{
+ struct timespec result;
+ long reminder;
+
+
+ result.tv_sec = time.tv_sec / divider;
+ result.tv_nsec = 0;
+
+ /* We iterate until the reminder is lower than 2 (to later fit in
+ * a 32 bit signed integer multiplied by 1e9 */
+
+ reminder = time.tv_sec % divider;
+
+
+ if (reminder == 0)
+ {
+ /* We are lucky no reminder so no need to transfer it to the
+ nsec scale.
+ */
+ result.tv_nsec = time.tv_nsec/divider;
+ return result;
+ }
+
+ long enhacer;
+ long back_enhacer;
+ long next_dividend;
+ int next_numeral; /* Between 0 and 9 */
+ enhacer = 1;
+ do
+ {
+ enhacer *= 10;
+ back_enhacer = 1000000000 / enhacer;
+ next_numeral = (time.tv_nsec / back_enhacer) % 10;
+
+ // Note: a possible overflow may happen here with large denominators
+ if (reminder > 200000000)
+ {
+ /* An overflow is going to be produced */
+ abort();
+ }
+ next_dividend = reminder * 10 + next_numeral;
+
+ result.tv_nsec += (next_dividend / divider) * back_enhacer;
+ reminder = next_dividend % divider;
+ } while (back_enhacer > 1);
+
+
+ return result;
+}
+
+// ---------------------------------------------------------
+
/* Comparison */
/**************/
}
+// -----------------------------------------------------------
+
+static inline bool fosa_rel_time_equal(fosa_rel_time_t relt1, fosa_rel_time_t relt2)
+{
+ bool result;
+
+ result = timespec_equal(relt1, relt2);
+
+ return result;
+}
+
+
+// -----------------------------------------------------------
+
+static inline bool fosa_abs_time_equal(fosa_abs_time_t abst1, fosa_abs_time_t abst2)
+{
+ bool result;
+
+ result = timespec_equal(abst1, abst2);
+
+ return result;
+}
+
+// -----------------------------------------------------------
+
+static inline bool fosa_rel_time_is_null(fosa_rel_time_t relt)
+{
+ bool result;
+
+ result = timespec_is_null(relt);
+
+ return result;
+}
+
+
+// -----------------------------------------------------------
+
+static inline bool fosa_abs_time_is_null(fosa_abs_time_t abst)
+{
+ bool result;
+
+ result = timespec_is_null(abst);
+
+ return result;
+}
+
+
+
+
/* Conversion */
/**************/
static inline fosa_rel_time_t fosa_msec_to_rel_time(long msec)
return result;
}
+// --------------------------------------------------
+
+static inline fosa_rel_time_t fosa_nsec_to_rel_time(long nsec)
+{
+ fosa_rel_time_t result;
+
+ nsec_to_timespec(result, nsec);
+
+ return result;
+}
+
+// --------------------------------------------------
+
+static inline long fosa_rel_time_to_nsec(fosa_rel_time_t relt)
+{
+ long result;
+
+ result = timespec_to_nsec(relt);
+
+ return result;
+}
+
+
+// --------------------------------------------------
+
+static inline fosa_abs_time_t fosa_nsec_to_abs_time(long nsec)
+{
+ fosa_abs_time_t result;
+
+ nsec_to_timespec(result, nsec);
+
+ return result;
+}
+
+// --------------------------------------------------
+
+static inline long fosa_abs_time_to_nsec(fosa_abs_time_t abst)
+{
+ long result;
+
+ result = timespec_to_nsec(abst);
+
+ return result;
+}
+
// --------------------------------------------------
return (struct timespec) abst;
}
+// --------------------------------------------------
+
+static inline double fosa_rel_time_to_double(fosa_rel_time_t relt)
+{
+ double result;
+
+ result = relt.tv_nsec*0.000000001 + (double)relt.tv_sec;
+
+ return result;
+}
+
+// --------------------------------------------------
+
+static inline fosa_rel_time_t fosa_double_to_rel_time(double time)
+{
+ fosa_rel_time_t result;
+
+ result.tv_sec = (long) time;
+ result.tv_nsec = (long) ( (time - (double)result.tv_sec) * 1e9 );
+
+ return result;
+}
#endif /* !FOSA_TIME_TIMESPEC_H_ */
/* fosa_rel_time_decr (negative) */
rel_time_result = fosa_rel_time_decr(rel_time2, rel_time1);
// assert( check_exact_rel_msec(rel_time_result, 1100) );
+
+/*
+ struct timespec t1 = {0, 876352172};
+ fosa_rel_time_t t1_rel = fosa_timespec_to_rel_time(t1);
+ long factor = 573102543;
+ struct timespec product = {502239658, 336773396};
+ fosa_rel_time_t product_rel = fosa_timespec_to_rel_time(product);
+*/
+
+ struct timespec t1 = {0, 876352172};
+ struct timespec product = {50223965, 570771688};
+ long factor = 57310254;
+ struct timespec product_divided_by_17 = {2954350, 915927746}; // inexact division
+ struct timespec product_divided_by_3 = {16741321, 856923896}; // exact division
+
+ fosa_rel_time_t t1_rel = fosa_timespec_to_rel_time(t1);
+ fosa_rel_time_t product_rel = fosa_timespec_to_rel_time(product);
+ fosa_rel_time_t product_17_rel = fosa_timespec_to_rel_time(product_divided_by_17);
+ fosa_rel_time_t product_3_rel = fosa_timespec_to_rel_time(product_divided_by_3);
+
+ /* fosa_rel_time_times_integer */
+ /* fosa_rel_time_divided_by_integer */
+ rel_time_result = fosa_rel_time_times_integer(rel_time2, 4);
+ assert( check_exact_rel_msec(rel_time_result, 1600) );
+
+ rel_time_result = fosa_rel_time_divided_by_integer(rel_time_result, 4);
+ assert( check_exact_rel_msec(rel_time_result, 400) );
+
+ rel_time_result = fosa_rel_time_times_integer(t1_rel, factor);
+ assert( fosa_rel_time_equal(rel_time_result, product_rel) );
+
+ rel_time_result = fosa_rel_time_divided_by_integer(product_rel, factor);
+ assert( fosa_rel_time_equal(rel_time_result, t1_rel) );
+
+ rel_time_result = fosa_rel_time_divided_by_integer(product_rel, 17);
+ assert( fosa_rel_time_equal(rel_time_result, product_17_rel) );
+
+ rel_time_result = fosa_rel_time_divided_by_integer(product_rel, 3);
+ assert( fosa_rel_time_equal(rel_time_result, product_3_rel) );
/* fosa_abs_time_smaller */
test = fosa_abs_time_smaller(abs_time1, abs_time2);
test = memcmp(&tspec_result, &tspec2, sizeof(tspec_result) );
assert(test == 0);
+
+
printf("End of test OK!!\n");
return 0;