其他回复中的讨论很棒,所以我不会重复其中的任何一个,但没有代码。这里有一些代码来实际检查一对浮点数在相乘时是否正好给出 1.0。
代码做了一些假设/断言(通常在 x86 平台上遇到):
-float
是 32 位二进制(AKA single precision
)IEEE-754
- 要么int
'要么 'long
是 32 位(我决定不依赖可用性of uint32_t
)
-memcpy()
将浮点数复制到整数/长整数,使得 8873283.0f 变为 0x4B076543(即,预期某些“字节序”)
一个额外的假设是:
- 它接收*
可以相乘的实际浮点数(即浮点数的乘法不会使用数学硬件/库可以在内部使用的更高精度值)
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <assert.h>
#define C_ASSERT(expr) extern char CAssertExtern[(expr)?1:-1]
#if UINT_MAX >= 0xFFFFFFFF
typedef unsigned int uint32;
#else
typedef unsigned long uint32;
#endif
typedef unsigned long long uint64;
C_ASSERT(CHAR_BIT == 8);
C_ASSERT(sizeof(uint32) == 4);
C_ASSERT(sizeof(float) == 4);
int ProductIsOne(float f1, float f2)
{
uint32 m1, m2;
int e1, e2, s1, s2;
int e;
uint64 m;
// Make sure floats are 32-bit IEE754 and
// reinterpreted as integers as we expect
{
static const float testf = 8873283.0f;
uint32 testi;
memcpy(&testi, &testf, sizeof(testf));
assert(testi == 0x4B076543);
}
memcpy(&m1, &f1, sizeof(f1));
s1 = m1 >= 0x80000000;
m1 &= 0x7FFFFFFF;
e1 = m1 >> 23;
m1 &= 0x7FFFFF;
if (e1 > 0) m1 |= 0x800000;
memcpy(&m2, &f2, sizeof(f2));
s2 = m2 >= 0x80000000;
m2 &= 0x7FFFFFFF;
e2 = m2 >> 23;
m2 &= 0x7FFFFF;
if (e2 > 0) m2 |= 0x800000;
if (e1 == 0xFF || e2 == 0xFF || s1 != s2) // Inf, NaN, different signs
return 0;
m = (uint64)m1 * m2;
if (!m || (m & (m - 1))) // not a power of 2
return 0;
e = e1 + !e1 - 0x7F - 23 + e2 + !e2 - 0x7F - 23;
while (m > 1) m >>= 1, e++;
return e == 0;
}
const float testData[][2] =
{
{ .1f, 10.0f },
{ 0.5f, 2.0f },
{ 0.25f, 2.0f },
{ 4.0f, 0.25f },
{ 0.33333333f, 3.0f },
{ 0.00000762939453125f, 131072.0f }, // 2^-17 * 2^17
{ 1.26765060022822940E30f, 7.88860905221011805E-31f }, // 2^100 * 2^-100
{ 5.87747175411143754E-39f, 1.70141183460469232E38f }, // 2^-127 (denormalized) * 2^127
};
int main(void)
{
int i;
for (i = 0; i < sizeof(testData) / sizeof(testData[0]); i++)
printf("%g * %g %c= 1\n",
testData[i][0], testData[i][1],
"!="[ProductIsOne(testData[i][0], testData[i][1])]);
return 0;
}
输出(见ideone.com):
0.1 * 10 != 1
0.5 * 2 == 1
0.25 * 2 != 1
4 * 0.25 == 1
0.333333 * 3 != 1
7.62939e-06 * 131072 == 1
1.26765e+30 * 7.88861e-31 == 1
5.87747e-39 * 1.70141e+38 == 1