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

时间:2011-12-08 09:33:56

标签: c linux binary floating-point

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

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

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

5 个答案:

答案 0 :(得分:6)

我为浮动/双转换器编写了一个十进制数字,以获得乐趣,并使它产生一个额外的输出标志,告诉结果浮点值是否完全代表输入的十进制字符串。

主要思想很简单。无论何时在转换过程中发生截断或舍入,都会记住它。

代码不是最有效的,也不是完全验证所有可能问题的输入(例如,指数太大),但它似乎可以完成格式良好的十进制字符串:

#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;
}

输出(在Windows XP下以32位模式在x86 PC上):

                         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

输出每行的第一个==!=告诉获取的float / double是否完全代表十进制输入。

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

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

答案 1 :(得分: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")

用法:以“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

答案 2 :(得分:2)

编写这样的工具应该非常简单:

input value as string
convert to double
convert back to string
compare with input

需要注意确保在转换为/从双倍转换中不会发生舍入。

答案 3 :(得分:2)

虽然这不是你所需要的,但它很接近:

http://www.h-schmidt.net/FloatApplet/IEEE754.html

您需要一些解释来确定您的值是否可以在二进制浮点中精确表示,但由于您只有三个或四个值,因此应该没问题。

作为如何使用它的示例,请在“十进制表示”字段中输入“0.1”。

如果我们检查二进制表示,我们会​​看到尾数似乎是一个重复序列,这已经是我们无法准确表示该值的标志:

0 0111101 110011001100110011001101

(为了更好的可读性,我在符号,指数和尾数之间添加了空格。)

另一个指示是“双精度”字段。它的作用是通过用尾数扩展尾数,然后转换回十进制,将单精度二进制浮点数扩展为双精度。如果数字可以准确表示,我们可以看到我们最初输入的数字;但在这种情况下,我们看到0.10000000149011612。这是一个额外的指示,即无法使用二进制浮点精确表示0.1。

答案 4 :(得分:1)

我的任意精确度decimal to binary converter可能会有所帮助。有两种情况需要考虑:

1)整数值:只检查第53位后的1位(你必须手工计数)

2)小数值或混合数:如果小数部分的'Num Digits'具有无穷大符号(∞),则该值不准确;如果该字段不是无穷大,则只要两个num数字字段加起来为53或更少,该数字就是精确的。