以IEEE-754格式添加正数和负数



我的问题似乎很简单:我写了一个程序,手动将浮点数相加。此程序有某些限制。(比如没有iostream或使用任何一元运算符(,所以这就是缺乏这些东西的原因。至于这个问题,当添加两个正浮点数(例如,1.5+1.5=3.0(时,程序似乎能正常工作,但添加两个负数(10.0+-5.0(时,我得到了非常古怪的数字。这是代码:

#include <cstdio>
#define BIAS32 127
struct Real
{
//sign bit
int sign;
//UNBIASED exponent
long exponent;
//Fraction including implied 1. at bit index 23
unsigned long fraction;
};
Real Decode(int float_value);
int Encode(Real real_value);
Real Normalize(Real value);
Real Add(Real left, Real right);
unsigned long Add(unsigned long leftop, unsigned long rightop);
unsigned long Multiply(unsigned long leftop, unsigned long rightop);
void alignExponents(Real* left, Real* right);
bool is_neg(Real real);
int Twos(int op);
int main(int argc, char* argv[])
{
int left, right;
char op;
int value;
Real rLeft, rRight, result;
if (argc < 4) {
printf("Usage: %s <left> <op> <right>n", argv[0]);
return -1;
}
sscanf(argv[1], "%f", (float*)&left);
sscanf(argv[2], "%c", &op);
sscanf(argv[3], "%f", (float*)&right);
rLeft = Decode(left);
rRight = Decode(right);
if (op == '+') {
result = Add(rLeft, rRight);
}
else {
printf("Unknown operator '%c'n", op);
return -2;
}
value = Encode(result);
printf("%.3f %c %.3f = %.3f (0x%08x)n",
*((float*)&left),
op,
*((float*)&right),
*((float*)&value),
value
);
return 0;
}
Real Decode(int float_value)
{             // Test sign bit of float_value - Test exponent bits of float_value & apply bias - Test mantissa bits of float_value
Real result{ float_value >> 31 & 1 ? 1 : 0, ((long)Add(float_value >> 23 & 0xFF, -BIAS32)), (unsigned long)float_value & 0x7FFFFF };
return result;
};

int Encode(Real real_value)
{
int x = 0;
x |= real_value.fraction; // Set the fraction bits of x 
x |= real_value.sign << 31; // Set the sign bits of x
x |= Add(real_value.exponent, BIAS32) << 23; // Set the exponent bits of x
return x;
}
Real Normalize(Real value)
{
if (is_neg(value))
{
value.fraction = Twos(value.fraction);
}
unsigned int i = 0;
while (i < 9)
{
if ((value.fraction >> Add(23, i)) & 1) // If there are set bits past the mantissa section
{
value.fraction >>= 1; // shift mantissa right by 1
value.exponent = Add(value.exponent, 1); // increment exponent to accomodate for shift
}
i = Add(i, 1);
}
return value;
}
Real Add(Real left, Real right)
{
Real a = left, b = right;
alignExponents(&a, &b); // Aligns exponents of both operands
unsigned long sum = Add(a.fraction, b.fraction);
Real result = Normalize({ a.sign, a.exponent, sum }); // Normalize result if need be
return result;
}
unsigned long Add(unsigned long leftop, unsigned long rightop)
{
unsigned long sum = 0, test = 1; // sum initialized to 0, test created to compare bits
while (test) // while test is not 0
{
if (leftop & test) // if the digit being tested is 1
{
if (sum & test) sum ^= test << 1; // if the sum tests to 1, carry a bit over
sum ^= test;
}
if (rightop & test)
{
if (sum & test) sum ^= test << 1;
sum ^= test;
}
test <<= 1;
}
return sum;
}
void alignExponents(Real* a, Real* b)
{
if (a->exponent != b->exponent) // If the exponents are not equal
{
if (a->exponent > b->exponent)
{
int disp = a->exponent - b->exponent; // number of shifts needed based on difference between two exponents
b->fraction |= 1 << 23; // sets the implicit bit for shifting
b->exponent = a->exponent; // sets exponents equal to each other
b->fraction >>= disp; // mantissa is shifted over to accomodate for the increase in power
return;
}
int disp = b->exponent - a->exponent;
a->fraction |= 1 << 23;
a->exponent = b->exponent;
a->fraction >>= disp;
return;
}
return;
}
bool is_neg(Real real)
{
if (real.sign) return true;
return false;
}
int Twos(int op)
{
return Add(~op, -1); // NOT the operand and add 1 to it
}

最重要的是,我刚刚测试了10.5+5.5的值,得到了24.0,所以这似乎比我最初想象的更错误。我已经为此工作了好几天了,希望能得到一些帮助/建议。

这里有一些帮助/建议。既然您已经处理了一些代码,我建议您回去重新设计数据结构。这样一个关键数据结构的声明将受益于更多的注释,确保您确切地知道每个字段的含义。

例如,隐式位并不总是1。如果指数为零,则为零。这应该在编码和解码函数中处理。对于代码的其余部分,它只是一个有效位,不应该有任何特殊处理。

当你开始考虑四舍五入时,你会发现在一个中间结果中通常需要超过23位。

将负数2的有效位设为补码将产生以两种方式存储相同信息的问题。您将有一个符号位,就像做符号和幅度一样,并将符号编码在有符号整数significand中。保持它们的一致性将是一团糟。无论你决定Real如何存储负数,都要记录下来,并始终保持一致。

如果我要实现这一点,我会从非常非常仔细地定义Real开始。然后,我将决定我希望能够在Real上执行什么操作,并编写函数来执行这些操作。如果你做对了,每个功能都会相对简单。

最新更新