xref: /netbsd-src/external/bsd/ntp/dist/include/ntp_fp.h (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: ntp_fp.h,v 1.12 2024/08/18 20:46:50 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel /*
4abb0f93cSkardel  * ntp_fp.h - definitions for NTP fixed/floating-point arithmetic
5abb0f93cSkardel  */
6abb0f93cSkardel 
7abb0f93cSkardel #ifndef NTP_FP_H
8abb0f93cSkardel #define NTP_FP_H
9abb0f93cSkardel 
10abb0f93cSkardel #include "ntp_types.h"
11abb0f93cSkardel 
12abb0f93cSkardel /*
13abb0f93cSkardel  * NTP uses two fixed point formats.  The first (l_fp) is the "long"
14abb0f93cSkardel  * format and is 64 bits long with the decimal between bits 31 and 32.
15abb0f93cSkardel  * This is used for time stamps in the NTP packet header (in network
16abb0f93cSkardel  * byte order) and for internal computations of offsets (in local host
17abb0f93cSkardel  * byte order). We use the same structure for both signed and unsigned
18abb0f93cSkardel  * values, which is a big hack but saves rewriting all the operators
19abb0f93cSkardel  * twice. Just to confuse this, we also sometimes just carry the
20abb0f93cSkardel  * fractional part in calculations, in both signed and unsigned forms.
21abb0f93cSkardel  * Anyway, an l_fp looks like:
22abb0f93cSkardel  *
23abb0f93cSkardel  *    0			  1		      2			  3
24abb0f93cSkardel  *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
25abb0f93cSkardel  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26abb0f93cSkardel  *   |			       Integral Part			     |
27abb0f93cSkardel  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28abb0f93cSkardel  *   |			       Fractional Part			     |
29abb0f93cSkardel  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
30abb0f93cSkardel  *
31abb0f93cSkardel  */
32abb0f93cSkardel typedef struct {
33abb0f93cSkardel 	union {
34abb0f93cSkardel 		u_int32 Xl_ui;
35abb0f93cSkardel 		int32 Xl_i;
36abb0f93cSkardel 	} Ul_i;
372950cc38Schristos 	u_int32	l_uf;
38abb0f93cSkardel } l_fp;
39abb0f93cSkardel 
40abb0f93cSkardel #define l_ui	Ul_i.Xl_ui		/* unsigned integral part */
41abb0f93cSkardel #define	l_i	Ul_i.Xl_i		/* signed integral part */
42abb0f93cSkardel 
43abb0f93cSkardel /*
44abb0f93cSkardel  * Fractional precision (of an l_fp) is actually the number of
45abb0f93cSkardel  * bits in a long.
46abb0f93cSkardel  */
47abb0f93cSkardel #define	FRACTION_PREC	(32)
48abb0f93cSkardel 
49abb0f93cSkardel 
50abb0f93cSkardel /*
51abb0f93cSkardel  * The second fixed point format is 32 bits, with the decimal between
52abb0f93cSkardel  * bits 15 and 16.  There is a signed version (s_fp) and an unsigned
53abb0f93cSkardel  * version (u_fp).  This is used to represent synchronizing distance
54abb0f93cSkardel  * and synchronizing dispersion in the NTP packet header (again, in
55abb0f93cSkardel  * network byte order) and internally to hold both distance and
56abb0f93cSkardel  * dispersion values (in local byte order).  In network byte order
57abb0f93cSkardel  * it looks like:
58abb0f93cSkardel  *
59abb0f93cSkardel  *    0			  1		      2			  3
60abb0f93cSkardel  *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
61abb0f93cSkardel  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62abb0f93cSkardel  *   |		  Integer Part	     |	   Fraction Part	     |
63abb0f93cSkardel  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
64abb0f93cSkardel  *
65abb0f93cSkardel  */
66abb0f93cSkardel typedef int32 s_fp;
67abb0f93cSkardel typedef u_int32 u_fp;
68abb0f93cSkardel 
69abb0f93cSkardel /*
70abb0f93cSkardel  * A unit second in fp format.	Actually 2**(half_the_bits_in_a_long)
71abb0f93cSkardel  */
72abb0f93cSkardel #define	FP_SECOND	(0x10000)
73abb0f93cSkardel 
74abb0f93cSkardel /*
75abb0f93cSkardel  * Byte order conversions
76abb0f93cSkardel  */
77abb0f93cSkardel #define	HTONS_FP(x)	(htonl(x))
78abb0f93cSkardel #define	NTOHS_FP(x)	(ntohl(x))
79abb0f93cSkardel 
802950cc38Schristos #define	NTOHL_MFP(ni, nf, hi, hf)				\
812950cc38Schristos 	do {							\
822950cc38Schristos 		(hi) = ntohl(ni);				\
832950cc38Schristos 		(hf) = ntohl(nf);				\
842950cc38Schristos 	} while (FALSE)
852950cc38Schristos 
862950cc38Schristos #define	HTONL_MFP(hi, hf, ni, nf)				\
872950cc38Schristos 	do {							\
882950cc38Schristos 		(ni) = htonl(hi);				\
892950cc38Schristos 		(nf) = htonl(hf);				\
902950cc38Schristos 	} while (FALSE)
912950cc38Schristos 
922950cc38Schristos #define HTONL_FP(h, n)						\
932950cc38Schristos 	HTONL_MFP((h)->l_ui, (h)->l_uf, (n)->l_ui, (n)->l_uf)
942950cc38Schristos 
952950cc38Schristos #define NTOHL_FP(n, h)						\
962950cc38Schristos 	NTOHL_MFP((n)->l_ui, (n)->l_uf, (h)->l_ui, (h)->l_uf)
972950cc38Schristos 
982950cc38Schristos /* Convert unsigned ts fraction to net order ts */
99abb0f93cSkardel #define	HTONL_UF(uf, nts)					\
1002950cc38Schristos 	do {							\
1012950cc38Schristos 		(nts)->l_ui = 0;				\
1022950cc38Schristos 		(nts)->l_uf = htonl(uf);			\
1032950cc38Schristos 	} while (FALSE)
104abb0f93cSkardel 
105abb0f93cSkardel /*
106abb0f93cSkardel  * Conversions between the two fixed point types
107abb0f93cSkardel  */
1082950cc38Schristos #define	MFPTOFP(x_i, x_f)	(((x_i) >= 0x00010000) ? 0x7fffffff : \
1092950cc38Schristos 				(((x_i) <= -0x00010000) ? 0x80000000 : \
1102950cc38Schristos 				(((x_i)<<16) | (((x_f)>>16)&0xffff))))
1112950cc38Schristos #define	LFPTOFP(v)		MFPTOFP((v)->l_i, (v)->l_uf)
112abb0f93cSkardel 
113abb0f93cSkardel #define UFPTOLFP(x, v) ((v)->l_ui = (u_fp)(x)>>16, (v)->l_uf = (x)<<16)
114abb0f93cSkardel #define FPTOLFP(x, v)  (UFPTOLFP((x), (v)), (x) < 0 ? (v)->l_ui -= 0x10000 : 0)
115abb0f93cSkardel 
1162950cc38Schristos #define MAXLFP(v) ((v)->l_ui = 0x7fffffffu, (v)->l_uf = 0xffffffffu)
1172950cc38Schristos #define MINLFP(v) ((v)->l_ui = 0x80000000u, (v)->l_uf = 0u)
118abb0f93cSkardel 
119abb0f93cSkardel /*
120abb0f93cSkardel  * Primitive operations on long fixed point values.  If these are
121abb0f93cSkardel  * reminiscent of assembler op codes it's only because some may
122abb0f93cSkardel  * be replaced by inline assembler for particular machines someday.
123abb0f93cSkardel  * These are the (kind of inefficient) run-anywhere versions.
124abb0f93cSkardel  */
125abb0f93cSkardel #define	M_NEG(v_i, v_f)		/* v = -v */ \
126abb0f93cSkardel 	do { \
1272950cc38Schristos 		(v_f) = ~(v_f) + 1u; \
1282950cc38Schristos 		(v_i) = ~(v_i) + ((v_f) == 0); \
1292950cc38Schristos 	} while (FALSE)
130abb0f93cSkardel 
131abb0f93cSkardel #define	M_NEGM(r_i, r_f, a_i, a_f)	/* r = -a */ \
132abb0f93cSkardel 	do { \
1332950cc38Schristos 		(r_f) = ~(a_f) + 1u; \
1342950cc38Schristos 		(r_i) = ~(a_i) + ((r_f) == 0); \
1352950cc38Schristos 	} while (FALSE)
136abb0f93cSkardel 
137abb0f93cSkardel #define M_ADD(r_i, r_f, a_i, a_f)	/* r += a */ \
138abb0f93cSkardel 	do { \
1392950cc38Schristos 		u_int32 add_t = (r_f); \
1402950cc38Schristos 		(r_f) += (a_f); \
1412950cc38Schristos 		(r_i) += (a_i) + ((u_int32)(r_f) < add_t); \
1422950cc38Schristos 	} while (FALSE)
143abb0f93cSkardel 
1442950cc38Schristos #define M_ADD3(r_o, r_i, r_f, a_o, a_i, a_f) /* r += a, three word */ \
145abb0f93cSkardel 	do { \
1462950cc38Schristos 		u_int32 add_t, add_c; \
1472950cc38Schristos 		add_t  = (r_f); \
1482950cc38Schristos 		(r_f) += (a_f); \
1492950cc38Schristos 		add_c  = ((u_int32)(r_f) < add_t); \
1502950cc38Schristos 		(r_i) += add_c; \
1512950cc38Schristos 		add_c  = ((u_int32)(r_i) < add_c); \
1522950cc38Schristos 		add_t  = (r_i); \
1532950cc38Schristos 		(r_i) += (a_i); \
1542950cc38Schristos 		add_c |= ((u_int32)(r_i) < add_t); \
1552950cc38Schristos 		(r_o) += (a_o) + add_c; \
1562950cc38Schristos 	} while (FALSE)
157abb0f93cSkardel 
158abb0f93cSkardel #define M_SUB(r_i, r_f, a_i, a_f)	/* r -= a */ \
159abb0f93cSkardel 	do { \
1602950cc38Schristos 		u_int32 sub_t = (r_f); \
1612950cc38Schristos 		(r_f) -= (a_f); \
1622950cc38Schristos 		(r_i) -= (a_i) + ((u_int32)(r_f) > sub_t); \
1632950cc38Schristos 	} while (FALSE)
164abb0f93cSkardel 
165abb0f93cSkardel #define	M_RSHIFTU(v_i, v_f)		/* v >>= 1, v is unsigned */ \
166abb0f93cSkardel 	do { \
1672950cc38Schristos 		(v_f) = ((u_int32)(v_f) >> 1) | ((u_int32)(v_i) << 31);	\
1682950cc38Schristos 		(v_i) = ((u_int32)(v_i) >> 1); \
1692950cc38Schristos 	} while (FALSE)
170abb0f93cSkardel 
171abb0f93cSkardel #define	M_RSHIFT(v_i, v_f)		/* v >>= 1, v is signed */ \
172abb0f93cSkardel 	do { \
1732950cc38Schristos 		(v_f) = ((u_int32)(v_f) >> 1) | ((u_int32)(v_i) << 31);	\
1742950cc38Schristos 		(v_i) = ((u_int32)(v_i) >> 1) | ((u_int32)(v_i) & 0x80000000);	\
1752950cc38Schristos 	} while (FALSE)
176abb0f93cSkardel 
177abb0f93cSkardel #define	M_LSHIFT(v_i, v_f)		/* v <<= 1 */ \
178abb0f93cSkardel 	do { \
1792950cc38Schristos 		(v_i) = ((u_int32)(v_i) << 1) | ((u_int32)(v_f) >> 31);	\
1802950cc38Schristos 		(v_f) = ((u_int32)(v_f) << 1); \
1812950cc38Schristos 	} while (FALSE)
182abb0f93cSkardel 
1832950cc38Schristos #define	M_LSHIFT3(v_o, v_i, v_f)	/* v <<= 1, with overflow */ \
184abb0f93cSkardel 	do { \
1852950cc38Schristos 		(v_o) = ((u_int32)(v_o) << 1) | ((u_int32)(v_i) >> 31);	\
1862950cc38Schristos 		(v_i) = ((u_int32)(v_i) << 1) | ((u_int32)(v_f) >> 31);	\
1872950cc38Schristos 		(v_f) = ((u_int32)(v_f) << 1); \
1882950cc38Schristos 	} while (FALSE)
189abb0f93cSkardel 
190abb0f93cSkardel #define	M_ADDUF(r_i, r_f, uf)		/* r += uf, uf is u_int32 fraction */ \
191abb0f93cSkardel 	M_ADD((r_i), (r_f), 0, (uf))	/* let optimizer worry about it */
192abb0f93cSkardel 
193abb0f93cSkardel #define	M_SUBUF(r_i, r_f, uf)		/* r -= uf, uf is u_int32 fraction */ \
194abb0f93cSkardel 	M_SUB((r_i), (r_f), 0, (uf))	/* let optimizer worry about it */
195abb0f93cSkardel 
196abb0f93cSkardel #define	M_ADDF(r_i, r_f, f)		/* r += f, f is a int32 fraction */ \
197abb0f93cSkardel 	do { \
1982950cc38Schristos 		int32 add_f = (int32)(f); \
1992950cc38Schristos 		if (add_f >= 0) \
200*eabc0478Schristos 			M_ADD((r_i), (r_f), 0, (u_int32)( add_f)); \
2012950cc38Schristos 		else \
202*eabc0478Schristos 			M_SUB((r_i), (r_f), 0, (u_int32)(-add_f)); \
203abb0f93cSkardel 	} while(0)
204abb0f93cSkardel 
2052950cc38Schristos #define	M_ISNEG(v_i)			/* v < 0 */ \
206abb0f93cSkardel 	(((v_i) & 0x80000000) != 0)
207abb0f93cSkardel 
2082950cc38Schristos #define	M_ISGT(a_i, a_f, b_i, b_f)	/* a > b signed */ \
209ea66d795Schristos 	(((u_int32)((a_i) ^ 0x80000000) > (u_int32)((b_i) ^ 0x80000000)) || \
2102950cc38Schristos 	  ((a_i) == (b_i) && ((u_int32)(a_f)) > ((u_int32)(b_f))))
2112950cc38Schristos 
2122950cc38Schristos #define	M_ISGTU(a_i, a_f, b_i, b_f)	/* a > b unsigned */ \
2132950cc38Schristos 	(((u_int32)(a_i)) > ((u_int32)(b_i)) || \
2142950cc38Schristos 	  ((a_i) == (b_i) && ((u_int32)(a_f)) > ((u_int32)(b_f))))
2152950cc38Schristos 
216abb0f93cSkardel #define	M_ISHIS(a_i, a_f, b_i, b_f)	/* a >= b unsigned */ \
217abb0f93cSkardel 	(((u_int32)(a_i)) > ((u_int32)(b_i)) || \
218abb0f93cSkardel 	  ((a_i) == (b_i) && ((u_int32)(a_f)) >= ((u_int32)(b_f))))
219abb0f93cSkardel 
220abb0f93cSkardel #define	M_ISGEQ(a_i, a_f, b_i, b_f)	/* a >= b signed */ \
221ea66d795Schristos 	(((u_int32)((a_i) ^ 0x80000000) > (u_int32)((b_i) ^ 0x80000000)) || \
2222950cc38Schristos 	  ((a_i) == (b_i) && (u_int32)(a_f) >= (u_int32)(b_f)))
223abb0f93cSkardel 
224abb0f93cSkardel #define	M_ISEQU(a_i, a_f, b_i, b_f)	/* a == b unsigned */ \
225ea66d795Schristos 	((u_int32)(a_i) == (u_int32)(b_i) && (u_int32)(a_f) == (u_int32)(b_f))
226abb0f93cSkardel 
227abb0f93cSkardel /*
228abb0f93cSkardel  * Operations on the long fp format
229abb0f93cSkardel  */
230abb0f93cSkardel #define	L_ADD(r, a)	M_ADD((r)->l_ui, (r)->l_uf, (a)->l_ui, (a)->l_uf)
231abb0f93cSkardel #define	L_SUB(r, a)	M_SUB((r)->l_ui, (r)->l_uf, (a)->l_ui, (a)->l_uf)
232abb0f93cSkardel #define	L_NEG(v)	M_NEG((v)->l_ui, (v)->l_uf)
233abb0f93cSkardel #define L_ADDUF(r, uf)	M_ADDUF((r)->l_ui, (r)->l_uf, (uf))
234abb0f93cSkardel #define L_SUBUF(r, uf)	M_SUBUF((r)->l_ui, (r)->l_uf, (uf))
235abb0f93cSkardel #define	L_ADDF(r, f)	M_ADDF((r)->l_ui, (r)->l_uf, (f))
236abb0f93cSkardel #define	L_RSHIFT(v)	M_RSHIFT((v)->l_i, (v)->l_uf)
237abb0f93cSkardel #define	L_RSHIFTU(v)	M_RSHIFTU((v)->l_ui, (v)->l_uf)
238abb0f93cSkardel #define	L_LSHIFT(v)	M_LSHIFT((v)->l_ui, (v)->l_uf)
239abb0f93cSkardel #define	L_CLR(v)	((v)->l_ui = (v)->l_uf = 0)
240abb0f93cSkardel 
2412950cc38Schristos #define	L_ISNEG(v)	M_ISNEG((v)->l_ui)
2422950cc38Schristos #define L_ISZERO(v)	(((v)->l_ui | (v)->l_uf) == 0)
2432950cc38Schristos #define	L_ISGT(a, b)	M_ISGT((a)->l_i, (a)->l_uf, (b)->l_i, (b)->l_uf)
2442950cc38Schristos #define	L_ISGTU(a, b)	M_ISGTU((a)->l_ui, (a)->l_uf, (b)->l_ui, (b)->l_uf)
2452950cc38Schristos #define	L_ISHIS(a, b)	M_ISHIS((a)->l_ui, (a)->l_uf, (b)->l_ui, (b)->l_uf)
2462950cc38Schristos #define	L_ISGEQ(a, b)	M_ISGEQ((a)->l_ui, (a)->l_uf, (b)->l_ui, (b)->l_uf)
247abb0f93cSkardel #define	L_ISEQU(a, b)	M_ISEQU((a)->l_ui, (a)->l_uf, (b)->l_ui, (b)->l_uf)
248abb0f93cSkardel 
249abb0f93cSkardel /*
250abb0f93cSkardel  * s_fp/double and u_fp/double conversions
251abb0f93cSkardel  */
2522950cc38Schristos #define FRIC		65536.0			/* 2^16 as a double */
253abb0f93cSkardel #define DTOFP(r)	((s_fp)((r) * FRIC))
254abb0f93cSkardel #define DTOUFP(r)	((u_fp)((r) * FRIC))
255abb0f93cSkardel #define FPTOD(r)	((double)(r) / FRIC)
256abb0f93cSkardel 
257abb0f93cSkardel /*
258abb0f93cSkardel  * l_fp/double conversions
259abb0f93cSkardel  */
2602950cc38Schristos #define FRAC		4294967296.0 		/* 2^32 as a double */
2612950cc38Schristos 
2622950cc38Schristos /*
2632950cc38Schristos  * Use 64 bit integers if available.  Solaris on SPARC has a problem
2642950cc38Schristos  * compiling parsesolaris.c if ntp_fp.h includes math.h, due to
2652950cc38Schristos  * archaic gets() and printf() prototypes used in Solaris kernel
2662950cc38Schristos  * headers.  So far the problem has only been seen with gcc, but it
2672950cc38Schristos  * may also affect Sun compilers, in which case the defined(__GNUC__)
2682950cc38Schristos  * term should be removed.
2697476e6e4Schristos  * XSCALE also generates bad code for these, at least with GCC 3.3.5.
2707476e6e4Schristos  * This is unrelated to math.h, but the same solution applies.
2712950cc38Schristos  */
2722950cc38Schristos #if defined(HAVE_U_INT64) && \
2732950cc38Schristos     !(defined(__SVR4) && defined(__sun) && \
2747476e6e4Schristos       defined(sparc) && defined(__GNUC__) || \
2757476e6e4Schristos       defined(__arm__) && defined(__XSCALE__) && defined(__GNUC__))
2762950cc38Schristos 
2772950cc38Schristos #include <math.h>	/* ldexp() */
2782950cc38Schristos 
2792950cc38Schristos #define M_DTOLFP(d, r_ui, r_uf)		/* double to l_fp */	\
280abb0f93cSkardel 	do {							\
2812950cc38Schristos 		double	d_tmp;					\
2822950cc38Schristos 		u_int64	q_tmp;					\
2832950cc38Schristos 		int	M_isneg;					\
284abb0f93cSkardel 								\
285abb0f93cSkardel 		d_tmp = (d);					\
2862950cc38Schristos 		M_isneg = (d_tmp < 0.);				\
2872950cc38Schristos 		if (M_isneg) {					\
288abb0f93cSkardel 			d_tmp = -d_tmp;				\
289abb0f93cSkardel 		}						\
2902950cc38Schristos 		q_tmp = (u_int64)ldexp(d_tmp, 32);		\
2912950cc38Schristos 		if (M_isneg) {					\
2922950cc38Schristos 			q_tmp = ~q_tmp + 1;			\
2932950cc38Schristos 		}						\
2942950cc38Schristos 		(r_uf) = (u_int32)q_tmp;			\
2952950cc38Schristos 		(r_ui) = (u_int32)(q_tmp >> 32);		\
2962950cc38Schristos 	} while (FALSE)
2972950cc38Schristos 
2982950cc38Schristos #define M_LFPTOD(r_ui, r_uf, d) 	/* l_fp to double */	\
299abb0f93cSkardel 	do {							\
3002950cc38Schristos 		double	d_tmp;					\
3012950cc38Schristos 		u_int64	q_tmp;					\
3022950cc38Schristos 		int	M_isneg;				\
303abb0f93cSkardel 								\
3042950cc38Schristos 		q_tmp = ((u_int64)(r_ui) << 32) + (r_uf);	\
3052950cc38Schristos 		M_isneg = M_ISNEG(r_ui);			\
3062950cc38Schristos 		if (M_isneg) {					\
3072950cc38Schristos 			q_tmp = ~q_tmp + 1;			\
3082950cc38Schristos 		}						\
3092950cc38Schristos 		d_tmp = ldexp((double)q_tmp, -32);		\
3102950cc38Schristos 		if (M_isneg) {					\
3112950cc38Schristos 			d_tmp = -d_tmp;				\
3122950cc38Schristos 		}						\
3132950cc38Schristos 		(d) = d_tmp;					\
3142950cc38Schristos 	} while (FALSE)
3152950cc38Schristos 
3162950cc38Schristos #else /* use only 32 bit unsigned values */
3172950cc38Schristos 
3182950cc38Schristos #define M_DTOLFP(d, r_ui, r_uf) 		/* double to l_fp */ \
3192950cc38Schristos 	do { \
3202950cc38Schristos 		double d_tmp; \
3212950cc38Schristos 		if ((d_tmp = (d)) < 0) { \
3222950cc38Schristos 			(r_ui) = (u_int32)(-d_tmp); \
3232950cc38Schristos 			(r_uf) = (u_int32)(-(d_tmp + (double)(r_ui)) * FRAC); \
3242950cc38Schristos 			M_NEG((r_ui), (r_uf)); \
325abb0f93cSkardel 		} else { \
3262950cc38Schristos 			(r_ui) = (u_int32)d_tmp; \
3272950cc38Schristos 			(r_uf) = (u_int32)((d_tmp - (double)(r_ui)) * FRAC); \
328abb0f93cSkardel 		} \
329abb0f93cSkardel 	} while (0)
3302950cc38Schristos #define M_LFPTOD(r_ui, r_uf, d) 		/* l_fp to double */ \
3312950cc38Schristos 	do { \
3322950cc38Schristos 		u_int32 l_thi, l_tlo; \
3332950cc38Schristos 		l_thi = (r_ui); l_tlo = (r_uf); \
3342950cc38Schristos 		if (M_ISNEG(l_thi)) { \
3352950cc38Schristos 			M_NEG(l_thi, l_tlo); \
3362950cc38Schristos 			(d) = -((double)l_thi + (double)l_tlo / FRAC); \
3372950cc38Schristos 		} else { \
3382950cc38Schristos 			(d) = (double)l_thi + (double)l_tlo / FRAC; \
3392950cc38Schristos 		} \
3402950cc38Schristos 	} while (0)
3412950cc38Schristos #endif
3422950cc38Schristos 
343abb0f93cSkardel #define DTOLFP(d, v) 	M_DTOLFP((d), (v)->l_ui, (v)->l_uf)
344abb0f93cSkardel #define LFPTOD(v, d) 	M_LFPTOD((v)->l_ui, (v)->l_uf, (d))
345abb0f93cSkardel 
346abb0f93cSkardel /*
347abb0f93cSkardel  * Prototypes
348abb0f93cSkardel  */
349cdfa2a7eSchristos extern	char *	dofptoa		(u_fp, char, short, int);
350cdfa2a7eSchristos extern	char *	dolfptoa	(u_int32, u_int32, char, short, int);
351abb0f93cSkardel 
352abb0f93cSkardel extern	int	atolfp		(const char *, l_fp *);
353abb0f93cSkardel extern	int	buftvtots	(const char *, l_fp *);
354abb0f93cSkardel extern	char *	fptoa		(s_fp, short);
355abb0f93cSkardel extern	char *	fptoms		(s_fp, short);
356abb0f93cSkardel extern	int	hextolfp	(const char *, l_fp *);
357ccc794f0Schristos extern  void	gpstolfp	(u_int, u_int, unsigned long, l_fp *);
358abb0f93cSkardel extern	int	mstolfp		(const char *, l_fp *);
359abb0f93cSkardel extern	char *	prettydate	(l_fp *);
360abb0f93cSkardel extern	char *	gmprettydate	(l_fp *);
361abb0f93cSkardel extern	char *	uglydate	(l_fp *);
362abb0f93cSkardel extern  void	mfp_mul		(int32 *, u_int32 *, int32, u_int32, int32, u_int32);
363abb0f93cSkardel 
3642950cc38Schristos extern	void	set_sys_fuzz	(double);
3652950cc38Schristos extern	void	init_systime	(void);
366abb0f93cSkardel extern	void	get_systime	(l_fp *);
367abb0f93cSkardel extern	int	step_systime	(double);
368abb0f93cSkardel extern	int	adj_systime	(double);
3694eea345dSchristos extern	int	clamp_systime	(void);
370abb0f93cSkardel 
3712950cc38Schristos extern	struct tm * ntp2unix_tm (u_int32 ntp, int local);
372abb0f93cSkardel 
373abb0f93cSkardel #define	lfptoa(fpv, ndec)	mfptoa((fpv)->l_ui, (fpv)->l_uf, (ndec))
374abb0f93cSkardel #define	lfptoms(fpv, ndec)	mfptoms((fpv)->l_ui, (fpv)->l_uf, (ndec))
375abb0f93cSkardel 
376abb0f93cSkardel #define stoa(addr)		socktoa(addr)
377abb0f93cSkardel #define	ntoa(addr)		stoa(addr)
3782950cc38Schristos #define sptoa(addr)		sockporttoa(addr)
379abb0f93cSkardel #define stohost(addr)		socktohost(addr)
380abb0f93cSkardel 
381abb0f93cSkardel #define	ufptoa(fpv, ndec)	dofptoa((fpv), 0, (ndec), 0)
382abb0f93cSkardel #define	ufptoms(fpv, ndec)	dofptoa((fpv), 0, (ndec), 1)
383abb0f93cSkardel #define	ulfptoa(fpv, ndec)	dolfptoa((fpv)->l_ui, (fpv)->l_uf, 0, (ndec), 0)
384abb0f93cSkardel #define	ulfptoms(fpv, ndec)	dolfptoa((fpv)->l_ui, (fpv)->l_uf, 0, (ndec), 1)
385abb0f93cSkardel #define	umfptoa(fpi, fpf, ndec) dolfptoa((fpi), (fpf), 0, (ndec), 0)
386abb0f93cSkardel 
3872950cc38Schristos /*
3882950cc38Schristos  * Optional callback from libntp step_systime() to ntpd.  Optional
3892950cc38Schristos *  because other libntp clients like ntpdate don't use it.
3902950cc38Schristos  */
3912950cc38Schristos typedef void (*time_stepped_callback)(void);
3922950cc38Schristos extern time_stepped_callback	step_callback;
3932950cc38Schristos 
3942950cc38Schristos /*
3952950cc38Schristos  * Multi-thread locking for get_systime()
3962950cc38Schristos  *
3972950cc38Schristos  * On most systems, get_systime() is used solely by the main ntpd
3982950cc38Schristos  * thread, but on Windows it's also used by the dedicated I/O thread.
3992950cc38Schristos  * The [Bug 2037] changes to get_systime() have it keep state between
4002950cc38Schristos  * calls to ensure time moves in only one direction, which means its
4012950cc38Schristos  * use on Windows needs to be protected against simultaneous execution
4022950cc38Schristos  * to avoid falsely detecting Lamport violations by ensuring only one
4032950cc38Schristos  * thread at a time is in get_systime().
4042950cc38Schristos  */
4052950cc38Schristos #ifdef SYS_WINNT
4062950cc38Schristos extern CRITICAL_SECTION get_systime_cs;
4072950cc38Schristos # define INIT_GET_SYSTIME_CRITSEC()				\
4082950cc38Schristos 		InitializeCriticalSection(&get_systime_cs)
4092950cc38Schristos # define ENTER_GET_SYSTIME_CRITSEC()				\
4102950cc38Schristos 		EnterCriticalSection(&get_systime_cs)
4112950cc38Schristos # define LEAVE_GET_SYSTIME_CRITSEC()				\
4122950cc38Schristos 		LeaveCriticalSection(&get_systime_cs)
4132950cc38Schristos # define INIT_WIN_PRECISE_TIME()				\
4142950cc38Schristos 		init_win_precise_time()
4152950cc38Schristos #else	/* !SYS_WINNT follows */
4162950cc38Schristos # define INIT_GET_SYSTIME_CRITSEC()			\
4172950cc38Schristos 		do {} while (FALSE)
4182950cc38Schristos # define ENTER_GET_SYSTIME_CRITSEC()			\
4192950cc38Schristos 		do {} while (FALSE)
4202950cc38Schristos # define LEAVE_GET_SYSTIME_CRITSEC()			\
4212950cc38Schristos 		do {} while (FALSE)
4222950cc38Schristos # define INIT_WIN_PRECISE_TIME()			\
4232950cc38Schristos 		do {} while (FALSE)
4242950cc38Schristos #endif
4252950cc38Schristos 
426abb0f93cSkardel #endif /* NTP_FP_H */
427