I've got this function that adds two hexadecimal numbers together one byte at a time by acessing the number stored in each object. However this sometimes results in the incorrect output, which I believe is due to an error with the carry value.
我有一个函数,它通过访问存储在每个对象中的数字,一次一个字节地将两个十六进制数字相加。然而,这有时会导致不正确的输出,我认为这是由于进位值的错误。
IntStatus_t intN_add(IntN_t opa, IntN_t opb, IntN_t* result)
{
uint8_t i = NBYTES;
uint8_t carry = 0;
uint16_t sum = 0;
do {
i--;
sum = opa.data[i] + opb.data[i] + carry;
if (sum > 255) {
result->data[i] = sum;
carry = (sum - 255);
} else {
result->data[i] = sum;
carry = 0;
}
} while (i > 0);
For example,
例如
Provide an intN number in hex encoded form: 00 80 ff
Provide an intN number in hex encoded form: 01 80 01
The sum is:0x030100
Returns 0x030100 instead of 0x20100.
返回0x030100,而不是0x20100。
更多回答
The first thing you need to do is to get rid of the custom integer types and switch to stdint.h
everywhere. We can't really answer if there's an overflow or such without knowing the actual type of these variables - if there is integer promotion or not etc.
您需要做的第一件事是去掉自定义的整数类型,并到处切换到stdint.h。如果不知道这些变量的实际类型,我们就无法真正回答是否存在溢出等问题——是否存在整数提升等。
优秀答案推荐
This is wrong:
这是错误的:
carry = (sum - 255);
If you add 200
and 200
, you'll get 400
, which should be 400 - 256 = 144
with a carry of 1
. However, your carry calculation would give you a number in the hundreds, which is clearly not what you want.
如果你把200和200相加,你会得到400,应该是400-256=144,进位为1。然而,你的进位计算会给你一个数百的数字,这显然不是你想要的。
Taking that into account would give you something like:
考虑到这一点,你会得到这样的东西:
sum = opa.data[i] + opb.data[i] + carry;
result->data[i] = sum % 256;
carry = sum / 256;
/*
if (sum > 255) {
result->data[i] = sum - 256;
carry = 1;
} else {
result->data[i] = sum;
carry = 0;
}
*/
You'll notice there I've replaced the if
statement with a shorter snippet. The correct if
-based solution is given in the comment that follows it, but the shorter form will give you the same result with less code, and also work if you expand your code to handle more than two input numbers at once(1).
您会注意到,我用一个较短的代码段替换了if语句。正确的基于if的解决方案在其后面的注释中给出,但较短的形式将用更少的代码为您提供相同的结果,并且如果您扩展代码以同时处理两个以上的输入数字(1),也会起作用。
What's happening with your given example and code, 0x0080ff + 0x018001
, is:
- Add
0xff
and 0x01
, with carry 0
: 255 + 1 + 1 = 256
which gives you 0
and a carry of 1
. That's the correct value and carry but more by accident than anything else :-)
- Add
0x80
and 0x80
, with carry 1
: 128 + 128 + 1 = 257
which gives you 1
and a carry of 2
.
- Add
0x00
and 0x01
, with carry 2
: 0 + 1 + 2 = 3
which gives you 3
and a carry of 0
.
- Hence final result is
0x030100
, rather than the correct 0x020100
.
(1) Adding two "digits" with a valid carry can never give you more than 255 + 255 + 1 = 511
, so the highest carry you can get from that would be 1
. However, adding three numbers digit-wise could see 255 + 255 + 255 + 1 = 765
, which would be 253
with carry 2
.
更多回答
(uint16_t)(opa.data[i])
What does this cast achieve? We know nothing about the types of the original integers and this cast is only meaningful in a system with 16 bit integer. On a 32 bit system, integer promotion will happen. You'd turn one operand unsigned even if it was negative but left the other as it was. Then everything gets promoted to int
if it wasn't already int
or larger.
(uint16_t)(opa.data[i])这个演员阵容实现了什么?我们对原始整数的类型一无所知,这种强制转换只在具有16位整数的系统中有意义。在32位系统上,将进行整数提升。即使一个操作数为负数,您也会将其变为无符号,但另一个则保持原样。如果它还不是int或更大,那么所有的东西都会被提升为int。
@Lundin, the fact that the code is using uint8/16_t
would suggest each digit is actually of the former type. But you're correct that there's no proof that this is the case (and also on the promotion of lesser-ranked integers to int
) so I'll adjust the answer.
@Lundin,代码使用uint8/16_t的事实表明,每个数字实际上都是前一种类型。但你是对的,没有证据表明是这样的(还有关于将排名较低的整数提升为int的问题),所以我会调整答案。
我是一名优秀的程序员,十分优秀!