我的C API有一个函数,它将double
作为输入。只有3或4个值是有效输入,所有其他值都是无效输入和拒绝。
我想检查是否可以准确表示所有有效输入值,以便我可以避免使用epsilon检查来提高可读性。
是否有工具(最好在命令行上)可以告诉我十进制值是否具有精确的二进制表示作为浮点值?
答案 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或更少,该数字就是精确的。