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

2024-11-11 08:27:00
admin
原创
22
摘要:问题描述:我的 C API 有一个以 a 作为输入的函数double。只有 3 或 4 个值才是有效输入,所有其他值都是非有效输入并被拒绝。我想检查是否所有有效输入值都可以准确表示,以便我可以避免 epsilon 检查以简化可读性。是否有一个工具(最好在命令行上)可以告诉我十进制值是否具有与浮点值精确的二进制...

问题描述:

我的 C API 有一个以 a 作为输入的函数double。只有 3 或 4 个值才是有效输入,所有其他值都是非有效输入并被拒绝。

我想检查是否所有有效输入值都可以准确表示,以便我可以避免 epsilon 检查以简化可读性。

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


解决方案 1:

下面是一个 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")

使用方法:将脚本保存为“exactly_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:

为了好玩,我编写了一个十进制到浮点数/双精度数的转换器,并让它产生一个额外的输出标志,告诉结果浮点值是否准确地代表输入的十进制字符串。

主要思想很简单。只要在转换过程中发生截断或舍入,就会被记住。

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

#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("
");
#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("
");
#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("
");
#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("
");
#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("
");
#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
",
           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
",
           testData[i].Decimal,
           "!="[!inexactf],
           resf ? 0xBADBADBADBADBADBULL : ff,
           "!="[!memcmp(&f, &ff, MIN(sizeof(f), sizeof(testData[i].Flt)))],
           f);
  }

  printf("errors: %d
", 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

输出的每一行上的第一个==!=表明所获得的浮点数/双精度数是否准确表示十进制输入。

第二个==!=表示计算出的浮点数/双精度数是否与编译器生成的浮点数/双精度数匹配。第一个十六进制数来自DecimalToIeee754Binary(),第二个十六进制数来自编译器。

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

解决方案 3:

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

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

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

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

如果我们检查二进制表示形式,我们会发现尾数似乎是一个重复序列,这已经表明我们无法准确地表示该值:

0 0111101 110011001100110011001101

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

另一个指示是“双精度”字段。它的作用是将单精度二进制浮点数扩展为双精度,方法是用零扩展尾数,然后转换回十进制。如果数字可以精确表示,我们希望看到我们最初输入的数字;但在本例中,我们看到的是 0.10000000149011612。这又表明 0.1 不能用二进制浮点数精确表示。

解决方案 4:

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

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

需要小心确保在与双精度数的转换过程中不会发生舍入。

解决方案 5:

我的任意精度十进制到二进制转换器可能会有所帮助。有两种情况需要考虑:

1)整数值:只需检查第 53 位位置后没有 1 位(您必须手动计算)

2) 小数或混合数:如果小数部分的“位数”有无穷大符号 (∞),则该值不精确;如果该字段不是无穷大,则只要两个位数字段的总和不超过 53,该数字就是精确的。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用