# [ntp:questions] Re: Clock accuracy & auto setting : digital television does a crap job of providing time services...

Terje Mathisen terje.mathisen at hda.hydro.com
Thu May 4 06:52:51 UTC 2006

```user at domain.invalid wrote:
> Max,
>
> Have you seen the white paper "The NTP Era and Era Numbering" on the
> NTP project page at www.ntp.org
> http://www.eecis.udel.edu/~mills/y2k.html? It includes a 128-bit date
> format, which  has enough seconds bits to measure the age of the
> Universe until the Sun grows dim and enough fraction bits to measure
> the time a photon crosses an atomic nucleus. The mapping to and from
> this format and NTP timestamps is transparent, even when the NTP era
> rolls in 2036, 2172, ...

I just started reading that paper, and I've found a bug/typo:

> The era number is the integer quotient 2^32 / s and the timstamp is
> the integer s mod 2^32.

The first operations should of course be s / 2^32, not the reciprocal!

BTW, it is only when working with unsigned integers that the C standard
guarantees that subtraction of two values will behave as required by
NTP, in your paper you implicitly acknowledge this by stating the need
for twos-complement arithmetic. :-)

It seems to me that for absolute maximum portability, the subtractions
could be done on unsigned values, then the result inspected:

If the high (sign) bit is set, negate the 64-bit result manually (using
twos-complement rules) and remember the sign bit. Next convert the
(small) positive value to double, then re-apply the correct sign bit:

double ntp_diff(uint32_t ah, uint32_t al, uint32_t bh, uint32_t bl)
/* Calculate A-B and return the result as a double: */
{
uint32_t dl, dh;
double d, sign;

dl = al - bl;
dh = ah - bh;
if (dl > al) { /* Wrap-around, so borrow: */
dh--;
}

sign = 1.0;
if (dh & 0x80000000) { /* Negative difference? */
sign = -1.0;
/* Negate by inverting all bits... */
dl = ~dl;
dh = ~dh;
/* ... and increment the result, taking care of any carries: */
if (++dl == 0) {
dh++;
if (dh == 0x80000000) { /* Maximal negative value: -2^31 */
return -65536.0*32768.0;
}
}
}
d = (double) dl;
d *= 1.0/(65536.0*65536.0); /* Shift the fractional bits down */
d += (double) dh;

d *= sign;

return d;
}

(I believe that this is probably one of the smaller problems you'd have
if/when porting NTP to something like a 60-bit sign-magnitude machine. :-)

Terje
--
- <Terje.Mathisen at hda.hydro.com>
"almost all programming can be viewed as an exercise in caching"

```