[Git][NTPsec/ntpsec][master] 3 commits: Simplify dtolfp an lfptod conversions
Eric S. Raymond
gitlab at mg.gitlab.com
Sun Mar 12 19:01:04 UTC 2017
Eric S. Raymond pushed to branch master at NTPsec / ntpsec
Commits:
3dd0816b by Achim Gratz at 2017-03-12T15:00:33-04:00
Simplify dtolfp an lfptod conversions
include/ntp_fp.h (dtolfp, lfptod): Assume that C99/POSIX standard
library functions are implemented correctly.
- - - - -
11128723 by Achim Gratz at 2017-03-12T15:00:33-04:00
Remove s_fp, simplify DTOUFP and FPTOD macros dealing with u_fp.
include/ntp_fp.h (s_fp, DTOFP, FPTOD, FRIC, fptoa, fptoms):
Remove. (DTOUFP): Leave the actual work to the FPU via ldexp.
libntp/dofptoa.c ()fptoa, fptoms: Remove.
ntpd/ntp_proto.c (peer_xmit, pool_xmit): Replace DTOFP with DTOUFP,
produces the same bit pattern anyway. (ctl_putsfp): Replace FPTOD
with direct conversion via ldexp.
tests/libntp/sfptostr.c: Remove.
tests/common/tests_main.c (RunAllTests): Remove sfptostr tests.
tests/wscript: Remove build recipe for libntp/sfptostr.c
devel/tour.txt: Hopefully more clear description of the internal NTP
date and timestamp types. Mention removal of s_fp.
- - - - -
a58fe23d by Achim Gratz at 2017-03-12T15:00:33-04:00
Provide FP scaling macros and use them.
include/ntp_fp.h (FP_SCALE, FP_UNSCALE): Scale and unscale 16
bits. (DTOUFP): use new macro.
ntpd/ntp_control.c: Use new macro and remove direct scaling.
ntptime/ntptime.c (main): Use new macros instead of direct computations.
- - - - -
9 changed files:
- devel/tour.txt
- include/ntp_fp.h
- libntp/dofptoa.c
- ntpd/ntp_control.c
- ntpd/ntp_proto.c
- ntptime/ntptime.c
- tests/common/tests_main.c
- − tests/libntp/sfptostr.c
- tests/wscript
Changes:
=====================================
devel/tour.txt
=====================================
--- a/devel/tour.txt
+++ b/devel/tour.txt
@@ -23,13 +23,29 @@ home-brews three fixed-point types of its own. Of these l_fp is the
most common, with 32 bits of precision in both integer and fractional
parts. Gory details are in include/ntp_fp.h.
-One point not covered there is that when used to represent dates
-internally an l_fp is normally interpreted as a pair consisting of
-an *unsigned* number of seconds since 1900-01-01T00:00:00Z (the
-NTP epoch) and unsigned decimal fractional seconds. Just to complicate
-matters, however, some uses of l_fp are time offsets with a signed
-seconds part - how it's interpreted depends on which member of a union
-is used.
+One point not covered there is that an l_fp is actually a symmetrical
+truncation of the full NTP date (for which no data type exists) about
+the fixed point location. The full NTP date has 64 bits for both the
+integer and fractional part, which get truncated to the right 32bit
+for the fractional and the left 32bit for the fractional part to
+become an l_fp. For most calculations with l_fp it's easier to
+envision it as a 64bit integer that represents time with a unit of
+2^-32s, slightly short of 233 ps.
+
+When used to represent dates internally an l_fp must be interpreted in
+relation to the NTP era (the left 32 bits of the integer part of the
+NTP date that got cut off). The NTP prime epoch (or epoch 0) is then
+an *unsigned* number of seconds since 1900-01-01T00:00:00Z and
+unsigned decimal fractional seconds. Just to complicate matters,
+however, some uses of l_fp are time offsets with a signed seconds
+part. Under the assumption that only adjacent epochs get compared,
+the offset calculations work correctly without taking the era number
+into account.
+
+Most time offsets are much smaller than the NTP epoch, so a 32 bit
+representation is used for these. Actually, there were two of these:
+s_fp for signed offsets and u_fp for strictly non-negative ones. The
+signed version has already been removed in NTPsec.
The comments in libntp/ntp_calendar.c are pretty illuminating about
calendar representations. A high-level point they don't make is
=====================================
include/ntp_fp.h
=====================================
--- a/include/ntp_fp.h
+++ b/include/ntp_fp.h
@@ -101,7 +101,6 @@ static inline l_fp lfpinit_u(uint32_t sec, uint32_t frac)
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
-typedef int32_t s_fp;
typedef uint32_t u_fp;
/*
@@ -149,12 +148,12 @@ static inline l_fp ntohl_fp(l_fp_w lfpw) {
#define L_ISGTU(a, b) ((a) > (b))
/*
- * s_fp/double and u_fp/double conversions
+ * scaling to 32bit FP format
+ * double to u_fp conversion
*/
-#define FRIC 65536.0 /* 2^16 as a double */
-#define DTOFP(r) ((s_fp)((r) * FRIC))
-#define DTOUFP(r) ((u_fp)((r) * FRIC))
-#define FPTOD(r) ((double)(r) / FRIC)
+#define FP_SCALE(r) (ldexp((double)(r), 16))
+#define FP_UNSCALE(r) (ldexp((double)(r), -16))
+#define DTOUFP(r) ((u_fp)FP_SCALE(r))
/*
* l_fp/double conversions
@@ -164,41 +163,19 @@ static inline l_fp ntohl_fp(l_fp_w lfpw) {
#include <math.h> /* ldexp() */
static inline l_fp dtolfp(double d)
-/* double to l_fp */
+/* double to l_fp
+ * assumes signed l_fp, i.e. a time offset
+ */
{
- double d_tmp;
- uint64_t q_tmp;
- int M_isneg;
-
- d_tmp = (d);
- M_isneg = (d_tmp < 0.);
- if (M_isneg) {
- d_tmp = -d_tmp;
- }
- q_tmp = (uint64_t)ldexp(d_tmp, 32);
- if (M_isneg) {
- q_tmp = ~q_tmp + 1;
- }
- return lfpinit_u(q_tmp >> 32, (uint32_t)q_tmp);
+ return (l_fp)((int64_t)ldexp(d, 32));
}
static inline double lfptod(l_fp r)
-/* l_fp to double */
+/* l_fp to double
+ * assumes signed l_fp, i.e. a time offset
+ */
{
- double d;
- uint64_t q_tmp;
- int M_isneg;
-
- q_tmp = ((uint64_t)lfpuint(r) << 32) + lfpfrac(r);
- M_isneg = M_ISNEG(lfpuint(r));
- if (M_isneg) {
- q_tmp = ~q_tmp + 1;
- }
- d = ldexp((double)q_tmp, -32);
- if (M_isneg) {
- d = -d;
- }
- return d;
+ return ldexp((double)((int64_t)r), -32);
}
/*
@@ -210,8 +187,6 @@ extern char * mfptoa (l_fp, short);
extern char * mfptoms (l_fp, short);
extern bool atolfp (const char *, l_fp *);
-extern char * fptoa (s_fp, short);
-extern char * fptoms (s_fp, short);
extern bool hextolfp (const char *, l_fp *);
extern void gpstolfp (int, int, unsigned long, l_fp *);
extern bool mstolfp (const char *, l_fp *);
=====================================
libntp/dofptoa.c
=====================================
--- a/libntp/dofptoa.c
+++ b/libntp/dofptoa.c
@@ -117,43 +117,3 @@ dofptoa(
*bp = '\0';
return buf;
}
-
-
-char *
-fptoa(
- s_fp fpv,
- short ndec
- )
-{
- u_fp plusfp;
- bool isneg;
-
- isneg = (fpv < 0);
- if (isneg) {
- plusfp = (u_fp)(-fpv);
- } else {
- plusfp = (u_fp)fpv;
- }
-
- return dofptoa(plusfp, isneg, ndec, false);
-}
-
-
-char *
-fptoms(
- s_fp fpv,
- short ndec
- )
-{
- u_fp plusfp;
- bool isneg;
-
- isneg = (fpv < 0);
- if (isneg) {
- plusfp = (u_fp)(-fpv);
- } else {
- plusfp = (u_fp)fpv;
- }
-
- return dofptoa(plusfp, isneg, ndec, true);
-}
=====================================
ntpd/ntp_control.c
=====================================
--- a/ntpd/ntp_control.c
+++ b/ntpd/ntp_control.c
@@ -58,7 +58,7 @@ static void ctl_putdblf (const char *, int, int, double);
#define ctl_putdbl(tag, d) ctl_putdblf(tag, 1, 3, d)
#define ctl_putdbl6(tag, d) ctl_putdblf(tag, 1, 6, d)
#define ctl_putsfp(tag, sfp) ctl_putdblf(tag, 0, -1, \
- FPTOD(sfp))
+ FP_UNSCALE(sfp))
static void ctl_putuint (const char *, u_long);
static void ctl_puthex (const char *, u_long);
static void ctl_putint (const char *, long);
=====================================
ntpd/ntp_proto.c
=====================================
--- a/ntpd/ntp_proto.c
+++ b/ntpd/ntp_proto.c
@@ -2164,7 +2164,7 @@ peer_xmit(
xpkt.ppoll = peer->hpoll;
xpkt.precision = sys_precision;
xpkt.refid = sys_refid;
- xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
+ xpkt.rootdelay = HTONS_FP(DTOUFP(sys_rootdelay));
xpkt.rootdisp = HTONS_FP(DTOUFP(sys_rootdisp));
xpkt.reftime = htonl_fp(sys_reftime);
xpkt.org = htonl_fp(peer->rec);
@@ -2324,7 +2324,7 @@ fast_xmit(
xpkt.ppoll = max(rpkt->ppoll, ntp_minpoll);
xpkt.precision = sys_precision;
xpkt.refid = sys_refid;
- xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
+ xpkt.rootdelay = HTONS_FP(DTOUFP(sys_rootdelay));
xpkt.rootdisp = HTONS_FP(DTOUFP(sys_rootdisp));
#ifdef ENABLE_LEAP_SMEAR
@@ -2474,7 +2474,7 @@ pool_xmit(
xpkt.ppoll = pool->hpoll;
xpkt.precision = sys_precision;
xpkt.refid = sys_refid;
- xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
+ xpkt.rootdelay = HTONS_FP(DTOUFP(sys_rootdelay));
xpkt.rootdisp = HTONS_FP(DTOUFP(sys_rootdisp));
xpkt.reftime = htonl_fp(sys_reftime);
get_systime(&xmt_tx);
=====================================
ntptime/ntptime.c
=====================================
--- a/ntptime/ntptime.c
+++ b/ntptime/ntptime.c
@@ -63,8 +63,6 @@ int ntp_gettime(struct ntptimeval *ntv)
\11PPSSIGNAL\12PPSJITTER\13PPSWANDER\14PPSERROR\15CLOCKERR\
\16NANO\17MODE\20CLK"
-#define SCALE_FREQ 65536 /* frequency scale */
-
/*
* These constants are used to round the time stamps computed from
* a struct timeval to the microsecond (more or less). This keeps
@@ -152,7 +150,7 @@ main(
case 'f':
ntx.modes |= MOD_FREQUENCY;
- ntx.freq = (long)(atof(ntp_optarg) * SCALE_FREQ);
+ ntx.freq = (long)FP_SCALE(atof(ntp_optarg));
break;
case 'j':
@@ -378,14 +376,14 @@ main(
snprintb(sizeof(binbuf), binbuf, ntx.modes, TIMEX_MOD_BITS));
ftemp = (double)ntx.offset/NS_PER_MS_FLOAT;
printf(json ? jfmt9 : ofmt9, ftemp);
- ftemp = (double)ntx.freq / SCALE_FREQ;
+ ftemp = FP_UNSCALE(ntx.freq);
printf(json ? jfmt10 : ofmt10, ftemp, 1 << ntx.shift);
printf(json ? jfmt11 : ofmt11,
(u_long)ntx.maxerror, (u_long)ntx.esterror);
printf(json ? jfmt12 : ofmt12,
snprintb(sizeof(binbuf), binbuf,
(u_int)ntx.status, TIMEX_STA_BITS));
- ftemp = (double)ntx.tolerance / SCALE_FREQ;
+ ftemp = FP_UNSCALE(ntx.tolerance);
/*
* Before the introduction of ntp_adjtime_ns() the
* ntptime code divided this by 1000 when the STA_NANO
@@ -397,8 +395,8 @@ main(
printf(json ? jfmt13 : ofmt13,
(u_long)ntx.constant, gtemp, ftemp);
if (ntx.shift != 0) {
- ftemp = (double)ntx.ppsfreq / SCALE_FREQ;
- gtemp = (double)ntx.stabil / SCALE_FREQ;
+ ftemp = FP_UNSCALE(ntx.ppsfreq);
+ gtemp = FP_UNSCALE(ntx.stabil);
htemp = (double)ntx.jitter/NS_PER_MS_FLOAT;
printf(json ? jfmt14 : ofmt14,
ftemp, gtemp, htemp);
=====================================
tests/common/tests_main.c
=====================================
--- a/tests/common/tests_main.c
+++ b/tests/common/tests_main.c
@@ -54,7 +54,6 @@ static void RunAllTests(void)
RUN_TEST_GROUP(prettydate);
RUN_TEST_GROUP(recvbuff);
RUN_TEST_GROUP(refidsmear);
- RUN_TEST_GROUP(sfptostr);
RUN_TEST_GROUP(socktoa);
RUN_TEST_GROUP(statestr);
RUN_TEST_GROUP(strtolfp);
=====================================
tests/libntp/sfptostr.c deleted
=====================================
--- a/tests/libntp/sfptostr.c
+++ /dev/null
@@ -1,89 +0,0 @@
-#include "config.h"
-#include "ntp_stdlib.h"
-
-#include "unity.h"
-#include "unity_fixture.h"
-
-TEST_GROUP(sfptostr);
-
-TEST_SETUP(sfptostr) {}
-
-TEST_TEAR_DOWN(sfptostr) {}
-
-/*
- * This file contains test for both fptoa and fptoms (which uses dofptoa),
- * since all these functions are very similar.
- */
-
-
-#include "ntp_fp.h"
-
-static const int SFP_MAX_PRECISION = 6;
-
-TEST(sfptostr, PositiveInteger) {
- s_fp test = 300 << 16; // exact 300.000000
-
- TEST_ASSERT_EQUAL_STRING("300.000000", fptoa(test, SFP_MAX_PRECISION));
- TEST_ASSERT_EQUAL_STRING("300000.000", fptoms(test, SFP_MAX_PRECISION));
-}
-
-TEST(sfptostr, NegativeInteger) {
- /* Mask to avoid warnings. See issue #71 */
- s_fp test = (-200 & 0xffff) << 16; // exact -200.000000
-
- TEST_ASSERT_EQUAL_STRING("-200.000000", fptoa(test, SFP_MAX_PRECISION));
- TEST_ASSERT_EQUAL_STRING("-200000.000", fptoms(test, SFP_MAX_PRECISION));
-}
-
-TEST(sfptostr, PositiveIntegerPositiveFraction) {
- s_fp test = (300 << 16) + (1 << 15); // 300 + 0.5
-
- TEST_ASSERT_EQUAL_STRING("300.500000", fptoa(test, SFP_MAX_PRECISION));
- TEST_ASSERT_EQUAL_STRING("300500.000", fptoms(test, SFP_MAX_PRECISION));
-}
-
-TEST(sfptostr, NegativeIntegerNegativeFraction) {
- s_fp test = ((-200 & 0xffff) << 16) - (1 << 15); // -200 - 0.5
-
- TEST_ASSERT_EQUAL_STRING("-200.500000", fptoa(test, SFP_MAX_PRECISION));
- TEST_ASSERT_EQUAL_STRING("-200500.000", fptoms(test, SFP_MAX_PRECISION));
-}
-
-TEST(sfptostr, PositiveIntegerNegativeFraction) {
- s_fp test = (300 << 16) - (1 << 14); // 300 - 0.25
-
- TEST_ASSERT_EQUAL_STRING("299.750000", fptoa(test, SFP_MAX_PRECISION));
- TEST_ASSERT_EQUAL_STRING("299750.000", fptoms(test, SFP_MAX_PRECISION));
-}
-
-TEST(sfptostr, NegativeIntegerPositiveFraction) {
- s_fp test = ((-200 & 0xffff) << 16) + (1 << 14)*3; // -200 + 0.75
-
- TEST_ASSERT_EQUAL_STRING("-199.250000", fptoa(test, SFP_MAX_PRECISION));
- TEST_ASSERT_EQUAL_STRING("-199250.000", fptoms(test, SFP_MAX_PRECISION));
-}
-
-TEST(sfptostr, SingleDecimalInteger) {
- s_fp test = 300 << 16; // 300
-
- TEST_ASSERT_EQUAL_STRING("300.0", fptoa(test, 1));
- TEST_ASSERT_EQUAL_STRING("300000.0", fptoms(test, 1));
-}
-
-TEST(sfptostr, SingleDecimalRounding) {
- s_fp test = (2 << 16) + (1 << 14)*3; // 2 + 0.25*3 = 2.75
-
- TEST_ASSERT_EQUAL_STRING("2.8", fptoa(test, 1));
- TEST_ASSERT_EQUAL_STRING("2750.0", fptoms(test, 1));
-}
-
-TEST_GROUP_RUNNER(sfptostr) {
- RUN_TEST_CASE(sfptostr, PositiveInteger);
- RUN_TEST_CASE(sfptostr, NegativeInteger);
- RUN_TEST_CASE(sfptostr, PositiveIntegerPositiveFraction);
- RUN_TEST_CASE(sfptostr, NegativeIntegerNegativeFraction);
- RUN_TEST_CASE(sfptostr, PositiveIntegerNegativeFraction);
- RUN_TEST_CASE(sfptostr, NegativeIntegerPositiveFraction);
- RUN_TEST_CASE(sfptostr, SingleDecimalInteger);
- RUN_TEST_CASE(sfptostr, SingleDecimalRounding);
-}
=====================================
tests/wscript
=====================================
--- a/tests/wscript
+++ b/tests/wscript
@@ -41,7 +41,6 @@ def build(ctx):
"libntp/prettydate.c",
"libntp/recvbuff.c",
"libntp/refidsmear.c",
- "libntp/sfptostr.c",
"libntp/socktoa.c",
"libntp/statestr.c",
"libntp/strtolfp.c",
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/compare/e0cd833887b6ad20819a0110ab16705ee2ebdc78...a58fe23d91eee1478f08a4e08d8d75a37ace6f8f
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ntpsec.org/pipermail/vc/attachments/20170312/6436a535/attachment.html>
More information about the vc
mailing list