FreeBSD/contrib/ntp/libntp/ntp_calendar.c
/*
 *---------------------------------------------------------------------
 * Do a periodic extension of 'value' around 'pivot' with a period of
 * 'cycle'.
 *
 * The result 'res' is a number that holds to the following properties:
 *
 *   1)	 res MOD cycle == value MOD cycle
 *   2)	 pivot <= res < pivot + cycle
 *	 (replace </<= with >/>= for negative cycles)
 *
 * where 'MOD' denotes the modulo operator for FLOOR DIVISION, which
 * is not the same as the '%' operator in C: C requires division to be
 * a truncated division, where remainder and dividend have the same
 * sign if the remainder is not zero, whereas floor division requires
 * divider and modulus to have the same sign for a non-zero modulus.
 *
 * This function has some useful applications:
 *
 * + let Y be a calendar year and V a truncated 2-digit year: then
 *	periodic_extend(Y-50, V, 100)
 *   is the closest expansion of the truncated year with respect to
 *   the full year, that is a 4-digit year with a difference of less
 *   than 50 years to the year Y. ("century unfolding")
 *
 * + let T be a UN*X time stamp and V be seconds-of-day: then
 *	perodic_extend(T-43200, V, 86400)
 *   is a time stamp that has the same seconds-of-day as the input
 *   value, with an absolute difference to T of <= 12hrs.  ("day
 *   unfolding")
 *
 * + Wherever you have a truncated periodic value and a non-truncated
 *   base value and you want to match them somehow...
 *
 * Basically, the function delivers 'pivot + (value - pivot) % cycle',
 * but the implementation takes some pains to avoid internal signed
 * integer overflows in the '(value - pivot) % cycle' part and adheres
 * to the floor division convention.
 *
 * If 64bit scalars where available on all intended platforms, writing a
 * version that uses 64 bit ops would be easy; writing a general
 * division routine for 64bit ops on a platform that can only do
 * 32/16bit divisions and is still performant is a bit more
 * difficult. Since most usecases can be coded in a way that does only
 * require the 32-bit version a 64bit version is NOT provided here.
 *---------------------------------------------------------------------
 */


The result 'res' is a number that holds to the following properties.

1)  res MOD cycle == value MOD cycle
2)  pivot <= res < pivot + cycle
(replace />= for negative cycles)



This function has some useful applications.

+ let Y be a calendar year and V a truncated 2-digit year: then
periodic_extend(Y-50, V, 100)
is the closest expansion of the truncated year with respect to
the full year, that is a 4-digit year with a difference of less
than 50 years to the year Y. ("century unfolding")



+ Wherever you have a truncated periodic value and a non-truncated
base value and you want to match them somehow

Basically, the function delivers 'pivot + (value - pivot) % cycle',
but the implementation takes some pains to avoid internal signed
integer overflows in the '(value - pivot) % cycle' part and adheres
to the floor division convention.

If 64bit scalars where available on all intended platforms, writing a
version that uses 64 bit ops would be easy; writing a general
division routine for 64bit ops on a platform that can only do
32/16bit divisions and is still performant is a bit more
difficult. Since most usecases can be coded in a way that does only
require the 32-bit version a 64bit version is NOT provided here.
The result ' res ' is a number that holds to the following properties . 1 ) res MOD cycle == value MOD cycle 2 ) pivot < = res < pivot + cycle ( replace / > = for negative cycles ) This function has some useful applications . + let Y be a calendar year and V a truncated 2 - digit year : then periodic_extend ( Y - 50 V 100 ) is the closest expansion of the truncated year with respect to the full year that is a 4 - digit year with a difference of less than 50 years to the year Y . ( " century unfolding " ) + Wherever you have a truncated periodic value and a non - truncated base value and you want to match them somehow Basically the function delivers ' pivot + ( value - pivot ) % cycle ' but the implementation takes some pains to avoid internal signed integer overflows in the ' ( value - pivot ) % cycle ' part and adheres to the floor division convention . If 64bit scalars where available on all intended platforms writing a version that uses 64 bit ops would be easy ; writing a general division routine for 64bit ops on a platform that can only do 32 / 16bit divisions and is still performant is a bit more difficult . Since most usecases can be coded in a way that does only require the 32 - bit version a 64bit version is NOT provided here .
int32_t
ntpcal_periodic_extend(
	int32_t pivot,
	int32_t value,
	int32_t cycle
	)
{
	uint32_t diff;
	char	 cpl = 0; 
	char	 neg = 0; 
	if (cycle < 0) {
		cycle = - cycle;
		neg ^= 1;
		cpl ^= 1;
	}
	if (cycle > 1) {
		if (value >= pivot) {
			diff = int32_to_uint32_2cpl(value)
			     - int32_to_uint32_2cpl(pivot);
		} else {
			diff = int32_to_uint32_2cpl(pivot)
			     - int32_to_uint32_2cpl(value);
			cpl ^= 1;
		}
		diff %= (uint32_t)cycle;
		if (diff) {
			if (cpl)
				diff = (uint32_t)cycle - diff;
			if (neg)
				diff = ~diff + 1;
			pivot += uint32_2cpl_to_int32(diff);
		}
	}
	return pivot;
}
int32_t ntpcal_periodic_extend ( int32_t pivot , int32_t value , int32_t cycle ) { uint32_t diff ; char cpl = 0 ; char neg = 0 ; if ( cycle < 0 ) { cycle = - cycle ; neg ^= 1 ; cpl ^= 1 ; } if ( cycle > 1 ) { if ( value >= pivot ) { diff = int32_to_uint32_2cpl ( value ) - int32_to_uint32_2cpl ( pivot ) ; } else { diff = int32_to_uint32_2cpl ( pivot ) - int32_to_uint32_2cpl ( value ) ; cpl ^= 1 ; } diff %= ( uint32_t ) cycle ; if ( diff ) { if ( cpl ) diff = ( uint32_t ) cycle - diff ; if ( neg ) diff = ~ diff + 1 ; pivot += uint32_2cpl_to_int32 ( diff ) ; } } return pivot ; }
Do a periodic extension of 'value' around 'pivot' with a period of
 'cycle'.
Do a periodic extension of ' value ' around ' pivot ' with a period of ' cycle ' .
/* modulo complement flag */ /* sign change flag	    */ /* make the cycle positive and adjust the flags */ /* guard against div by zero or one */ /*
		 * Get absolute difference as unsigned quantity and
		 * the complement flag. This is done by always
		 * subtracting the smaller value from the bigger
		 * one.
		 */