MS Visual C things

I use a different algorithm for uint64_t to double on VC 6 than your code, which is how VC 2003 does its [brand new] uint64_t to double conversion

((NV)(I64)((x) & U64_CONST(0x7FFFFFFFFFFFFFFF)) + -(NV)(I64)((x) & U64_CONST(0x8000000000000000)))

vs your

static NV
u642nv(uint64_t u64) {
    unsigned long h = u64 >> 32;
    unsigned long l = u64 & 0xffffffff;
    return ((((NV)65536) * ((NV)65536)) * h) + (NV)l;
}

which looks like in asm after optimizing by VC

static NV
u642nv(uint64_t u64) {
  uint32_t hi = u64.HighPart;
  u64.HighPart = 0;
  return (double)hi * 4294967296.0 + (double)(signed __int64)u64;
}

I dont know which you prefer.

I also tested the nv2u64 code on various VCs, commenting out nv2u64 to a simple cast, VC 6 32 failed,  VC 2003 32 failed, VC 2008 32 failed, VC 2008 x64 passed (with a 64 bit Perl of course).  Because so many permutations failed, I didn't touch nv2u64, 1 permutation did pass, so consider that as an optimization, so maybe that bug you linked to in http://connect.microsoft.com/VisualStudio/feedback/details/270762/error-in-converting-double-to-unsigned-long-long was fixed for x64-only in atleast 2008 and newer and the fix can be #if'ed out.