是否有工具可以知道某个值是否具有精确的二进制表示形式作为浮点变量?

Did*_*set 8 c linux floating-point binary

我的C API有一个函数,它作为输入a double.只有3或4个值是有效输入,所有其他值都是无效输入和拒绝.

我想检查是否可以准确表示所有有效输入值,以便我可以避免epsilon检查以提高可读性.

是否有一个工具(最好在命令行上)可以告诉我十进制值是否具有精确的二进制表示作为浮点值?

Ale*_*nze 6

I've written a decimal to float/double converter for fun and made it produce an extra output flag telling whether or not the resultant floating-point value represents the input decimal string exactly.

The main idea is very simple. Whenever truncation or rounding occurs during conversion, it's remembered.

The code is not the most efficient nor does it fully validate input for all possible problems (e.g. too large exponent), but it seems to do the job for well-formed decimal strings:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>

#define DEBUG_PRINT 0

#ifndef MIN
#define MIN(A,B) (((A) <= (B)) ? (A) : (B))
#endif

#ifndef MAX
#define MAX(A,B) (((A) >= (B)) ? (A) : (B))
#endif

static
int ParseDecimal(const char*  s,
                 int*         pSign,
                 const char** ppIntStart,
                 const char** ppIntEnd,
                 const char** ppFrcStart,
                 const char** ppFrcEnd,
                 int*         pExp)
{
  int sign = 1;
  const char* pIntStart = NULL;
  const char* pIntEnd = NULL;
  const char* pFrcStart = NULL;
  const char* pFrcEnd = NULL;
  int expSign = 1;
  const char* pExpStart = NULL;
  const char* pExpEnd = NULL;
  const char* p;
  int exp = 0;

  if (s == NULL) return -1;

  // Parse the sign and the integer part
  if (*s == '-') sign = -1, s++;
  else if (*s == '+') s++;
  while (*s && *s != '.' && *s != 'e' && *s != 'E')
  {
    if (*s < '0' || *s > '9') return -1;
    if (pIntStart == NULL) pIntStart = s;
    pIntEnd = s++;
  }

  // Parse the fractional part
  if (*s == '.')
  {
    s++;
    while (*s && *s != 'e' && *s != 'E')
    {
      if (*s < '0' || *s > '9') return -1;
      if (pFrcStart == NULL) pFrcStart = s;
      pFrcEnd = s++;
    }
  }

  if (pIntStart == NULL && pFrcStart == NULL) return -1;

  // Parse the exponent
  if (*s == 'e' || *s == 'E')
  {
    s++;

    if (*s == '-') expSign = -1, s++;
    else if (*s == '+') s++;

    if (!*s) return -1;

    while (*s)
    {
      if (*s < '0' || *s > '9') return -1;
      if (pExpStart == NULL) pExpStart = s;
      pExpEnd = s++;
    }
  }

  // Calculate the exponent
  for (p = pExpStart; p && p <= pExpEnd; p++)
    exp = exp * 10 + *p - '0';
  exp *= expSign;

  // Skip any trailing and leading zeroes
  // in the fractional and integer parts
  if (pFrcStart != NULL)
  {
    exp -= pFrcEnd + 1 - pFrcStart;
    if (pIntStart == NULL)
      while (pFrcStart < pFrcEnd && *pFrcStart == '0') pFrcStart++;
    while (pFrcEnd > pFrcStart && *pFrcEnd == '0') pFrcEnd--, exp++;
    if (*pFrcEnd == '0' && pIntStart != NULL) pFrcStart = pFrcEnd = NULL, exp++;
  }
  if (pIntStart != NULL)
  {
    if (pFrcStart == NULL)
      while (pIntEnd > pIntStart && *pIntEnd == '0') pIntEnd--, exp++;
    while (pIntStart < pIntEnd && *pIntStart == '0') pIntStart++;
    if (*pIntStart == '0' && pFrcStart != NULL)
    {
      pIntStart = pIntEnd = NULL;
      while (pFrcStart < pFrcEnd && *pFrcStart == '0') pFrcStart++;
    }
  }
  if ((pIntStart != NULL && *pIntStart == '0') ||
      (pFrcEnd != NULL && *pFrcEnd == '0'))
  {
    exp = 0;
  }

  *pSign = sign;
  *ppIntStart = pIntStart;
  *ppIntEnd   = pIntEnd;
  *ppFrcStart = pFrcStart;
  *ppFrcEnd   = pFrcEnd;
  *pExp = exp;

  return 0;
}

static
void ChainMultiplyAdd(unsigned char* pChain,
                      size_t         ChainLen,
                      unsigned char  Multiplier,
                      unsigned char  Addend)
{
  unsigned carry = Addend;

  while (ChainLen--)
  {
    carry += *pChain * Multiplier;
    *pChain++ = (unsigned char)(carry & 0xFF);
    carry >>= 8;
  }
}

static
void ChainDivide(unsigned char* pChain,
                 size_t         ChainLen,
                 unsigned char  Divisor,
                 unsigned char* pRemainder)
{
  unsigned remainder = 0;

  while (ChainLen)
  {
    remainder += pChain[ChainLen - 1];
    pChain[ChainLen - 1] = remainder / Divisor;
    remainder = (remainder % Divisor) << 8;
    ChainLen--;
  }

  if (pRemainder != NULL)
    *pRemainder = (unsigned char)(remainder >> 8);
}

int DecimalToIeee754Binary(const char* s,
                           unsigned FractionBitCnt,
                           unsigned ExponentBitCnt,
                           int* pInexact,
                           unsigned long long* pFloat)
{
  const char* pIntStart;
  const char* pIntEnd;
  const char* pFrcStart;
  const char* pFrcEnd;
  const char* p;
  int sign;
  int exp;
  int tmp;
  size_t numDecDigits;
  size_t denDecDigits;
  size_t numBinDigits;
  size_t numBytes;
  unsigned char* pNum = NULL;
  unsigned char remainder;
  int binExp = 0;
  int inexact = 0;
  int lastInexact = 0;

  if (FractionBitCnt < 3 ||
      ExponentBitCnt < 3 ||
      FractionBitCnt >= CHAR_BIT * sizeof(*pFloat) ||
      ExponentBitCnt >= CHAR_BIT * sizeof(*pFloat) ||
      FractionBitCnt + ExponentBitCnt >= CHAR_BIT * sizeof(*pFloat))
  {
    return -1;
  }

  tmp = ParseDecimal(s,
                     &sign,
                     &pIntStart,
                     &pIntEnd,
                     &pFrcStart,
                     &pFrcEnd,
                     &exp);
  if (tmp) return tmp;

  numDecDigits = ((pIntStart != NULL) ? pIntEnd + 1 - pIntStart : 0) +
                 ((pFrcStart != NULL) ? pFrcEnd + 1 - pFrcStart : 0) +
                 ((exp >= 0) ? exp : 0);
  denDecDigits = 1 + ((exp < 0) ? -exp : 0);

#if DEBUG_PRINT
  printf("%s    ", s);

  printf("%c", "- +"[1+sign]);
  for (p = pIntStart; p && p <= pIntEnd; p++) printf("%c", *p);
  for (p = pFrcStart; p && p <= pFrcEnd; p++) printf("%c", *p);
  printf(" E %d", exp);
  printf("    %zu/%zu    ", numDecDigits, denDecDigits);
//  fflush(stdout);
  printf("\n");
#endif

  // 10/3=3.3(3) > log2(10)~=3.32
  if (exp >= 0)
    numBinDigits = MAX((numDecDigits * 10 + 2) / 3,
                       FractionBitCnt + 1);
  else
    numBinDigits = MAX((numDecDigits * 10 + 2) / 3,
                       (denDecDigits * 10 + 2) / 3 + FractionBitCnt + 1 + 1);

  numBytes = (numBinDigits + 7) / 8;

  pNum = malloc(numBytes);
  if (pNum == NULL) return -2;
  memset(pNum, 0, numBytes);

  // Convert the numerator to binary
  for (p = pIntStart; p && p <= pIntEnd; p++)
    ChainMultiplyAdd(pNum, numBytes, 10, *p - '0');
  for (p = pFrcStart; p && p <= pFrcEnd; p++)
    ChainMultiplyAdd(pNum, numBytes, 10, *p - '0');
  for (tmp = exp; tmp > 0; tmp--)
    ChainMultiplyAdd(pNum, numBytes, 10, 0);

#if DEBUG_PRINT
  printf("num   : ");
  for (p = pNum + numBytes - 1; p >= (char*)pNum; p--)
    printf("%02X", (unsigned char)*p);
  printf("\n");
#endif

  // If the denominator isn't 1, divide the numerator by the denominator
  // getting at least FractionBitCnt+2 significant bits of quotient
  if (exp < 0)
  {
    binExp = -(int)(numBinDigits - (numDecDigits * 10 + 2) / 3);
    for (tmp = binExp; tmp < 0; tmp++)
      ChainMultiplyAdd(pNum, numBytes, 2, 0);
#if DEBUG_PRINT
  printf("num <<: ");
  for (p = pNum + numBytes - 1; p >= (char*)pNum; p--)
    printf("%02X", (unsigned char)*p);
  printf("\n");
#endif
    for (tmp = exp; tmp < 0; tmp++)
      ChainDivide(pNum, numBytes, 10, &remainder),
      lastInexact = inexact, inexact |= !!remainder;
  }

#if DEBUG_PRINT
  for (p = pNum + numBytes - 1; p >= (char*)pNum; p--)
    printf("%02X", (unsigned char)*p);
  printf(" * 2^%d (%c)", binExp, "ei"[inexact]);
  printf("\n");
#endif

  // Find the most significant bit and normalize the mantissa
  // by shifting it left
  for (tmp = numBytes - 1; tmp >= 0 && !pNum[tmp]; tmp--);
  if (tmp >= 0)
  {
    tmp = tmp * 8 + 7;
    while (!(pNum[tmp / 8] & (1 << tmp % 8))) tmp--;
    while (tmp < (int)FractionBitCnt)
      ChainMultiplyAdd(pNum, numBytes, 2, 0), binExp--, tmp++;
  }

  // Find the most significant bit and normalize the mantissa
  // by shifting it right
  do
  {
    remainder = 0;
    for (tmp = numBytes - 1; tmp >= 0 && !pNum[tmp]; tmp--);
    if (tmp >= 0)
    {
      tmp = tmp * 8 + 7;
      while (!(pNum[tmp / 8] & (1 << tmp % 8))) tmp--;
      while (tmp > (int)FractionBitCnt)
        ChainDivide(pNum, numBytes, 2, &remainder),
        lastInexact = inexact, inexact |= !!remainder, binExp++, tmp--;
      while (binExp < 2 - (1 << ((int)ExponentBitCnt - 1)) - (int)FractionBitCnt)
        ChainDivide(pNum, numBytes, 2, &remainder),
        lastInexact = inexact, inexact |= !!remainder, binExp++;
    }
    // Round to nearest even
    remainder &= (lastInexact | (pNum[0] & 1));
    if (remainder)
      ChainMultiplyAdd(pNum, numBytes, 1, 1);
  } while (remainder);

#if DEBUG_PRINT
  for (p = pNum + numBytes - 1; p >= (char*)pNum; p--)
    printf("%02X", (unsigned char)*p);
  printf(" * 2^%d", binExp);
  printf("\n");
#endif

  // Collect the result's mantissa
  *pFloat = 0;
  while (tmp >= 0)
  {
    *pFloat <<= 8;
    *pFloat |= pNum[tmp / 8];
    tmp -= 8;
  }

  // Collect the result's exponent
  binExp += (1 << ((int)ExponentBitCnt - 1)) - 1 + (int)FractionBitCnt;
  if (!(*pFloat & (1ull << FractionBitCnt))) binExp = 0; // Subnormal or 0
  *pFloat &= ~(1ull << FractionBitCnt);
  if (binExp >= (1 << (int)ExponentBitCnt) - 1)
    binExp = (1 << (int)ExponentBitCnt) - 1, *pFloat = 0, inexact |= 1; // Infinity
  *pFloat |= (unsigned long long)binExp << FractionBitCnt;

  // Collect the result's sign
  *pFloat |= (unsigned long long)(sign < 0) <<
             (ExponentBitCnt + FractionBitCnt);

  free(pNum);

  *pInexact = inexact;

  return 0;
}

#define TEST_ENTRY(n)  { #n, n, n##f }
#define TEST_ENTRYI(n) { #n, n, n }

struct
{
  const char* Decimal;
  double Dbl;
  float Flt;
} const testData[] =
{
  TEST_ENTRYI(0),
  TEST_ENTRYI(000),
  TEST_ENTRY(00.),
  TEST_ENTRY(.00),
  TEST_ENTRY(00.00),
  TEST_ENTRYI(1),
  TEST_ENTRY(10e-1),
  TEST_ENTRY(.1e1),
  TEST_ENTRY(.01e2),
  TEST_ENTRY(00.00100e3),
  TEST_ENTRYI(12),
  TEST_ENTRY(12.),
  TEST_ENTRYI(+12),
  TEST_ENTRYI(-12),
  TEST_ENTRY(.12),
  TEST_ENTRY(+.12),
  TEST_ENTRY(-.12),
  TEST_ENTRY(12.34),
  TEST_ENTRY(+12.34),
  TEST_ENTRY(-12.34),
  TEST_ENTRY(00.100),
  TEST_ENTRY(00100.),
  TEST_ENTRY(00100.00100),
  TEST_ENTRY(1e4),
  TEST_ENTRY(0.5),
  TEST_ENTRY(0.6),
  TEST_ENTRY(0.25),
  TEST_ENTRY(0.26),
  TEST_ENTRY(0.125),
  TEST_ENTRY(0.126),
  TEST_ENTRY(0.0625),
  TEST_ENTRY(0.0624),
  TEST_ENTRY(0.03125),
  TEST_ENTRY(0.03124),
  TEST_ENTRY(1e23),
  TEST_ENTRY(1E-23),
  TEST_ENTRY(1e+23),
  TEST_ENTRY(12.34E56),
  TEST_ENTRY(+12.34E+56),
  TEST_ENTRY(-12.34e-56),
  TEST_ENTRY(+.12E+34),
  TEST_ENTRY(-.12e-34),
  TEST_ENTRY(3.4028234e38),
  TEST_ENTRY(3.4028235e38),
  TEST_ENTRY(3.4028236e38),
  TEST_ENTRY(1.7976931348623158e308),
  TEST_ENTRY(1.7976931348623159e308),
  TEST_ENTRY(1e1000),
  TEST_ENTRY(-1.7976931348623158e308),
  TEST_ENTRY(-1.7976931348623159e308),
  TEST_ENTRY(2.2250738585072014e-308),
  TEST_ENTRY(2.2250738585072013e-308),
  TEST_ENTRY(2.2250738585072012e-308),
  TEST_ENTRY(2.2250738585072011e-308),
  TEST_ENTRY(4.9406564584124654e-324),
  TEST_ENTRY(2.4703282292062328e-324),
  TEST_ENTRY(2.4703282292062327e-324),
  TEST_ENTRY(-4.9406564584124654e-325),
  TEST_ENTRY(1e-1000),

  // Extra test data from Vern Paxson's paper
  // "A Program for Testing IEEE Decimal–Binary Conversion"
  TEST_ENTRY(5e-20                     ),
  TEST_ENTRY(67e+14                    ),
  TEST_ENTRY(985e+15                   ),
  TEST_ENTRY(7693e-42                  ),
  TEST_ENTRY(55895e-16                 ),
  TEST_ENTRY(996622e-44                ),
  TEST_ENTRY(7038531e-32               ),
  TEST_ENTRY(60419369e-46              ),
  TEST_ENTRY(702990899e-20             ),
  TEST_ENTRY(6930161142e-48            ),
  TEST_ENTRY(25933168707e+13           ),
  TEST_ENTRY(596428896559e+20          ),
  TEST_ENTRY(3e-23                     ),
  TEST_ENTRY(57e+18                    ),
  TEST_ENTRY(789e-35                   ),
  TEST_ENTRY(2539e-18                  ),
  TEST_ENTRY(76173e+28                 ),
  TEST_ENTRY(887745e-11                ),
  TEST_ENTRY(5382571e-37               ),
  TEST_ENTRY(82381273e-35              ),
  TEST_ENTRY(750486563e-38             ),
  TEST_ENTRY(3752432815e-39            ),
  TEST_ENTRY(75224575729e-45           ),
  TEST_ENTRY(459926601011e+15          ),
  TEST_ENTRY(7e-27                     ),
  TEST_ENTRY(37e-29                    ),
  TEST_ENTRY(743e-18                   ),
  TEST_ENTRY(7861e-33                  ),
  TEST_ENTRY(46073e-30                 ),
  TEST_ENTRY(774497e-34                ),
  TEST_ENTRY(8184513e-33               ),
  TEST_ENTRY(89842219e-28              ),
  TEST_ENTRY(449211095e-29             ),
  TEST_ENTRY(8128913627e-40            ),
  TEST_ENTRY(87365670181e-18           ),
  TEST_ENTRY(436828350905e-19          ),
  TEST_ENTRY(5569902441849e-49         ),
  TEST_ENTRY(60101945175297e-32        ),
  TEST_ENTRY(754205928904091e-51       ),
  TEST_ENTRY(5930988018823113e-37      ),
  TEST_ENTRY(51417459976130695e-27     ),
  TEST_ENTRY(826224659167966417e-41    ),
  TEST_ENTRY(9612793100620708287e-57   ),
  TEST_ENTRY(93219542812847969081e-39  ),
  TEST_ENTRY(544579064588249633923e-48 ),
  TEST_ENTRY(4985301935905831716201e-48),
  TEST_ENTRY(9e+26                     ),
  TEST_ENTRY(79e-8                     ),
  TEST_ENTRY(393e+26                   ),
  TEST_ENTRY(9171e-40                  ),
  TEST_ENTRY(56257e-16                 ),
  TEST_ENTRY(281285e-17                ),
  TEST_ENTRY(4691113e-43               ),
  TEST_ENTRY(29994057e-15              ),
  TEST_ENTRY(834548641e-46             ),
  TEST_ENTRY(1058695771e-47            ),
  TEST_ENTRY(87365670181e-18           ),
  TEST_ENTRY(872580695561e-36          ),
  TEST_ENTRY(6638060417081e-51         ),
  TEST_ENTRY(88473759402752e-52        ),
  TEST_ENTRY(412413848938563e-27       ),
  TEST_ENTRY(5592117679628511e-48      ),
  TEST_ENTRY(83881765194427665e-50     ),
  TEST_ENTRY(638632866154697279e-35    ),
  TEST_ENTRY(3624461315401357483e-53   ),
  TEST_ENTRY(75831386216699428651e-30  ),
  TEST_ENTRY(356645068918103229683e-42 ),
  TEST_ENTRY(7022835002724438581513e-33),
};

int main(void)
{
  int i;
  int errors = 0;

  for (i = 0; i < sizeof(testData) / sizeof(testData[0]); i++)
  {
    unsigned long long fd;
    unsigned long long ff;
    unsigned long long f = 0;
    unsigned long long d = 0;
    int inexactf = 1;
    int inexactd = 1;
    int resf;
    int resd;
    int cmpf;
    int cmpd;

    memcpy(&d, &testData[i].Dbl, MIN(sizeof(d), sizeof(testData[i].Dbl)));
    memcpy(&f, &testData[i].Flt, MIN(sizeof(f), sizeof(testData[i].Flt)));

    resd = DecimalToIeee754Binary(testData[i].Decimal, 52, 11, &inexactd, &fd);
    resf = DecimalToIeee754Binary(testData[i].Decimal, 23,  8, &inexactf, &ff);

    cmpd = !!memcmp(&d, &fd, MIN(sizeof(d), sizeof(testData[i].Dbl)));
    cmpf = !!memcmp(&f, &ff, MIN(sizeof(f), sizeof(testData[i].Flt)));

    errors += !!resd + !!resf + !!cmpd + !!cmpf;

    printf("%26s %c= 0x%016llX %c= 0x%016llX\n",
           testData[i].Decimal,
           "!="[!inexactd],
           resd ? 0xBADBADBADBADBADBULL : fd,
           "!="[!memcmp(&d, &fd, MIN(sizeof(d), sizeof(testData[i].Dbl)))],
           d);

    printf("%26s %c=         0x%08llX %c= 0x%08llX\n",
           testData[i].Decimal,
           "!="[!inexactf],
           resf ? 0xBADBADBADBADBADBULL : ff,
           "!="[!memcmp(&f, &ff, MIN(sizeof(f), sizeof(testData[i].Flt)))],
           f);
  }

  printf("errors: %d\n", errors);

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

Output (on x86 PC in 32-bit mode under Windows XP):

                         0 == 0x0000000000000000 == 0x0000000000000000
                         0 ==         0x00000000 == 0x00000000
                       000 == 0x0000000000000000 == 0x0000000000000000
                       000 ==         0x00000000 == 0x00000000
                       00. == 0x0000000000000000 == 0x0000000000000000
                       00. ==         0x00000000 == 0x00000000
                       .00 == 0x0000000000000000 == 0x0000000000000000
                       .00 ==         0x00000000 == 0x00000000
                     00.00 == 0x0000000000000000 == 0x0000000000000000
                     00.00 ==         0x00000000 == 0x00000000
                         1 == 0x3FF0000000000000 == 0x3FF0000000000000
                         1 ==         0x3F800000 == 0x3F800000
                     10e-1 == 0x3FF0000000000000 == 0x3FF0000000000000
                     10e-1 ==         0x3F800000 == 0x3F800000
                      .1e1 == 0x3FF0000000000000 == 0x3FF0000000000000
                      .1e1 ==         0x3F800000 == 0x3F800000
                     .01e2 == 0x3FF0000000000000 == 0x3FF0000000000000
                     .01e2 ==         0x3F800000 == 0x3F800000
                00.00100e3 == 0x3FF0000000000000 == 0x3FF0000000000000
                00.00100e3 ==         0x3F800000 == 0x3F800000
                        12 == 0x4028000000000000 == 0x4028000000000000
                        12 ==         0x41400000 == 0x41400000
                       12. == 0x4028000000000000 == 0x4028000000000000
                       12. ==         0x41400000 == 0x41400000
                       +12 == 0x4028000000000000 == 0x4028000000000000
                       +12 ==         0x41400000 == 0x41400000
                       -12 == 0xC028000000000000 == 0xC028000000000000
                       -12 ==         0xC1400000 == 0xC1400000
                       .12 != 0x3FBEB851EB851EB8 == 0x3FBEB851EB851EB8
                       .12 !=         0x3DF5C28F == 0x3DF5C28F
                      +.12 != 0x3FBEB851EB851EB8 == 0x3FBEB851EB851EB8
                      +.12 !=         0x3DF5C28F == 0x3DF5C28F
                      -.12 != 0xBFBEB851EB851EB8 == 0xBFBEB851EB851EB8
                      -.12 !=         0xBDF5C28F == 0xBDF5C28F
                     12.34 != 0x4028AE147AE147AE == 0x4028AE147AE147AE
                     12.34 !=         0x414570A4 == 0x414570A4
                    +12.34 != 0x4028AE147AE147AE == 0x4028AE147AE147AE
                    +12.34 !=         0x414570A4 == 0x414570A4
                    -12.34 != 0xC028AE147AE147AE == 0xC028AE147AE147AE
                    -12.34 !=         0xC14570A4 == 0xC14570A4
                    00.100 != 0x3FB999999999999A == 0x3FB999999999999A
                    00.100 !=         0x3DCCCCCD == 0x3DCCCCCD
                    00100. == 0x4059000000000000 == 0x4059000000000000
                    00100. ==         0x42C80000 == 0x42C80000
               00100.00100 != 0x40590010624DD2F2 == 0x40590010624DD2F2
               00100.00100 !=         0x42C80083 == 0x42C80083
                       1e4 == 0x40C3880000000000 == 0x40C3880000000000
                       1e4 ==         0x461C4000 == 0x461C4000
                       0.5 == 0x3FE0000000000000 == 0x3FE0000000000000
                       0.5 ==         0x3F000000 == 0x3F000000
                       0.6 != 0x3FE3333333333333 == 0x3FE3333333333333
                       0.6 !=         0x3F19999A == 0x3F19999A
                      0.25 == 0x3FD0000000000000 == 0x3FD0000000000000
                      0.25 ==         0x3E800000 == 0x3E800000
                      0.26 != 0x3FD0A3D70A3D70A4 == 0x3FD0A3D70A3D70A4
                      0.26 !=         0x3E851EB8 == 0x3E851EB8
                     0.125 == 0x3FC0000000000000 == 0x3FC0000000000000
                     0.125 ==         0x3E000000 == 0x3E000000
                     0.126 != 0x3FC020C49BA5E354 == 0x3FC020C49BA5E354
                     0.126 !=         0x3E010625 == 0x3E010625
                    0.0625 == 0x3FB0000000000000 == 0x3FB0000000000000
                    0.0625 ==         0x3D800000 == 0x3D800000
                    0.0624 != 0x3FAFF2E48E8A71DE == 0x3FAFF2E48E8A71DE
                    0.0624 !=         0x3D7F9724 == 0x3D7F9724
                   0.03125 == 0x3FA0000000000000 == 0x3FA0000000000000
                   0.03125 ==         0x3D000000 == 0x3D000000
                   0.03124 != 0x3F9FFD60E94EE393 == 0x3F9FFD60E94EE393
                   0.03124 !=         0x3CFFEB07 == 0x3CFFEB07
                      1e23 != 0x44B52D02C7E14AF6 == 0x44B52D02C7E14AF6
                      1e23 !=         0x65A96816 == 0x65A96816
                     1E-23 != 0x3B282DB34012B251 == 0x3B282DB34012B251
                     1E-23 !=         0x19416D9A == 0x19416D9A
                     1e+23 != 0x44B52D02C7E14AF6 == 0x44B52D02C7E14AF6
                     1e+23 !=         0x65A96816 == 0x65A96816
                  12.34E56 != 0x4BC929C7D37D0D30 == 0x4BC929C7D37D0D30
                  12.34E56 !=         0x7F800000 == 0x7F800000
                +12.34E+56 != 0x4BC929C7D37D0D30 == 0x4BC929C7D37D0D30
                +12.34E+56 !=         0x7F800000 == 0x7F800000
                -12.34e-56 != 0xB48834C13CBF331D == 0xB48834C13CBF331D
                -12.34e-56 !=         0x80000000 == 0x80000000
                  +.12E+34 != 0x46CD95108F882522 == 0x46CD95108F882522
                  +.12E+34 !=         0x766CA884 == 0x766CA884
                  -.12e-34 != 0xB8AFE6C6DCC3C5AC == 0xB8AFE6C6DCC3C5AC
                  -.12e-34 !=         0x857F3637 == 0x857F3637
              3.4028234e38 != 0x47EFFFFFD586B834 == 0x47EFFFFFD586B834
              3.4028234e38 !=         0x7F7FFFFF == 0x7F7FFFFF
              3.4028235e38 != 0x47EFFFFFE54DAFF8 == 0x47EFFFFFE54DAFF8
              3.4028235e38 !=         0x7F7FFFFF == 0x7F7FFFFF
              3.4028236e38 != 0x47EFFFFFF514A7BC == 0x47EFFFFFF514A7BC
              3.4028236e38 !=         0x7F800000 == 0x7F800000
    1.7976931348623158e308 != 0x7FEFFFFFFFFFFFFF == 0x7FEFFFFFFFFFFFFF
    1.7976931348623158e308 !=         0x7F800000 == 0x7F800000
    1.7976931348623159e308 != 0x7FF0000000000000 == 0x7FF0000000000000
    1.7976931348623159e308 !=         0x7F800000 == 0x7F800000
                    1e1000 != 0x7FF0000000000000 == 0x7FF0000000000000
                    1e1000 !=         0x7F800000 == 0x7F800000
   -1.7976931348623158e308 != 0xFFEFFFFFFFFFFFFF == 0xFFEFFFFFFFFFFFFF
   -1.7976931348623158e308 !=         0xFF800000 == 0xFF800000
   -1.7976931348623159e308 != 0xFFF0000000000000 == 0xFFF0000000000000
   -1.7976931348623159e308 !=         0xFF800000 == 0xFF800000
   2.2250738585072014e-308 != 0x0010000000000000 == 0x0010000000000000
   2.2250738585072014e-308 !=         0x00000000 == 0x00000000
   2.2250738585072013e-308 != 0x0010000000000000 == 0x0010000000000000
   2.2250738585072013e-308 !=         0x00000000 == 0x00000000
   2.2250738585072012e-308 != 0x0010000000000000 == 0x0010000000000000
   2.2250738585072012e-308 !=         0x00000000 == 0x00000000
   2.2250738585072011e-308 != 0x000FFFFFFFFFFFFF == 0x000FFFFFFFFFFFFF
   2.2250738585072011e-308 !=         0x00000000 == 0x00000000
   4.9406564584124654e-324 != 0x0000000000000001 == 0x0000000000000001
   4.9406564584124654e-324 !=         0x00000000 == 0x00000000
   2.4703282292062328e-324 != 0x0000000000000001 == 0x0000000000000001
   2.4703282292062328e-324 !=         0x00000000 == 0x00000000
   2.4703282292062327e-324 != 0x0000000000000000 == 0x0000000000000000
   2.4703282292062327e-324 !=         0x00000000 == 0x00000000
  -4.9406564584124654e-325 != 0x8000000000000000 == 0x8000000000000000
  -4.9406564584124654e-325 !=         0x80000000 == 0x80000000
                   1e-1000 != 0x0000000000000000 == 0x0000000000000000
                   1e-1000 !=         0x00000000 == 0x00000000
                     5e-20 != 0x3BED83C94FB6D2AC == 0x3BED83C94FB6D2AC
                     5e-20 !=         0x1F6C1E4A == 0x1F6C1E4A
                    67e+14 == 0x4337CD9D4FFEC000 == 0x4337CD9D4FFEC000
                    67e+14 !=         0x59BE6CEA == 0x59BE6CEA
                   985e+15 == 0x43AB56D88FFF8500 == 0x43AB56D88FFF8500
                   985e+15 !=         0x5D5AB6C4 == 0x5D5AB6C4
                  7693e-42 != 0x3804F13D0FFFE4A1 == 0x3804F13D0FFFE4A1
                  7693e-42 !=         0x0053C4F4 == 0x0053C4F4
                 55895e-16 != 0x3D989537AFFFFFE1 == 0x3D989537AFFFFFE1
                 55895e-16 !=         0x2CC4A9BD == 0x2CC4A9BD
                996622e-44 != 0x380B21710FFFFFFB == 0x380B21710FFFFFFB
                996622e-44 !=         0x006C85C4 == 0x006C85C4
               7038531e-32 != 0x3AB5C87FB0000000 == 0x3AB5C87FB0000000
               7038531e-32 !=         0x15AE43FD == 0x15AE43FD
              60419369e-46 != 0x3800729D90000000 == 0x3800729D90000000
              60419369e-46 !=         0x0041CA76 == 0x0041CA76
             702990899e-20 != 0x3D9EEAF950000000 == 0x3D9EEAF950000000
             702990899e-20 !=         0x2CF757CA == 0x2CF757CA
            6930161142e-48 != 0x3802DD9E10000000 == 0x3802DD9E10000000
            6930161142e-48 !=         0x004B7678 == 0x004B7678
           25933168707e+13 != 0x44CB753310000000 == 0x44CB753310000000
           25933168707e+13 !=         0x665BA998 == 0x665BA998
          596428896559e+20 != 0x4687866490000000 == 0x4687866490000000
          596428896559e+20 !=         0x743C3324 == 0x743C3324
                     3e-23 != 0x3B422246700E05BD == 0x3B422246700E05BD
                     3e-23 !=         0x1A111234 == 0x1A111234
                    57e+18 == 0x4408B84570022A20 == 0x4408B84570022A20
                    57e+18 !=         0x6045C22C == 0x6045C22C
                   789e-35 != 0x39447BCDF000340C == 0x39447BCDF000340C
                   789e-35 !=         0x0A23DE70 == 0x0A23DE70
...
errors: 0
Run Code Online (Sandbox Code Playgroud)

The first == or != on each line of the output tells whether or not the obtained float/double represents the decimal input exactly.

第二个==!=告诉计算的float/double是否与编译器生成的float/double匹配.第一个十六进制数来自DecimalToIeee754Binary(),第二个来自编译器.

UPD:代码是用gcc 4.6.2和Open Watcom C/C++ 1.9编译的.


Mar*_*son 6

这是一个完全符合您要求的Python代码段; 它需要Python 2.7或Python 3.x. (早期版本的Python对浮点转换不太仔细.)

import decimal, sys
input = sys.argv[1]
if decimal.Decimal(input) == float(input):
    print("Exactly representable")
else:
    print("Not exactly representable")
Run Code Online (Sandbox Code Playgroud)

用法:在名称'exact_representable.py'下保存脚本后,

mdickinson$ python exactly_representable.py 1.25
Exactly representable
mdickinson$ python exactly_representable.py 0.1
Not exactly representable
mdickinson$ python exactly_representable.py 1e22
Exactly representable
mdickinson$ python exactly_representable.py 1e23
Not exactly representable
Run Code Online (Sandbox Code Playgroud)