简体   繁体   English

通过减法签名无符号

[英]Signed to unsigned with subtraction

I've recently decided to make the leap and read through a bunch of computer science books to better equip myself for the future. 我最近决定实现这一目标并阅读一系列计算机科学书籍,以便更好地为未来做好准备。

At the moment I'm reading through converting signed to unsigned decimals. 目前我正在通过将有符号转换为无符号小数来阅读。 I understand the majority if it (hopefully it becomes easier to eventually), but struggling with the following (in 32-bit): 我理解大多数人(希望它最终会变得容易),但是对于以下(32位)挣扎:

-2147483647-1U < -2147483647 -2147483647-1U <-2147483647

According the book, this evaluates to true. 根据这本书,这评估是真的。 There's a bit about this that I'm still struggling with as I cant see why it evaluates to this. 有一点关于这一点,我仍然在努力,因为我不知道为什么它评估这个。

With my understanding, I know that they are both converted to unsigned values in this calculation due to the first number being cast as unsigned. 根据我的理解,我知道在这个计算中它们都被转换为无符号值,因为第一个数字被转换为无符号。 The first number is therefore -2147483648 after subtraction and then converted to unsigned, or does that unsigned conversion happen prior to the subtraction? 因此,减法后的第一个数字是-2147483648,然后转换为无符号,或者在减法之前进行无符号转换?

Sorry for the lengthy post, just trying to get my head around understanding this. 对于冗长的帖子感到抱歉,只是试着理解这一点。

Thanks! 谢谢!

The first number is therefore -2147483648 after subtraction and then converted to unsigned, or does that unsigned conversion happen prior to the subtraction? 因此,减法后的第一个数字是-2147483648,然后转换为无符号,或者在减法之前进行无符号转换?

The latter is true. 后者是真的。 According to C11 Standard "6.3.1.8 Usual arithmetic conversions" : 根据C11标准“6.3.1.8常规算术转换”

...Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type. ...否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数的类型的等级,则具有有符号整数类型的操作数将转换为具有无符号整数类型的操作数的类型。

So, all of the operands, both the ones for subtraction and for the comparison are converted to unsigned. 因此, 所有操作数,包括减法和比较的操作数都将转换为无符号。

PS For completeness, the conversion procedure is described in "6.3.1.3 Signed and unsigned integers" : PS为完整起见 ,转换过程在“6.3.1.3有符号和无符号整数”中描述

... if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type. ...如果新类型是无符号的,则通过重复加或减一个可以在新类型中表示的最大值来转换该值,直到该值在新类型的范围内。

PPS The answer is assuming int being 32-bit long. PPS答案是假设int是32位长。 If it is less than that, then the negative constant -2147483647 will have type long which is higher rank than unsigned int , which is 1U and then the above will not apply and no conversion will be performed (thanks @Olaf for pointing out). 如果它小于那个,则负常数-2147483647将具有类型long ,其等级高于unsigned int ,即1U ,然后上述将不适用并且不执行转换(感谢@Olaf指出)。

The first number is therefore -2147483648 after subtraction 因此,减法后的第一个数字是-2147483648

Not quite. 不完全的。 The conversion to unsigned happens first. 首先转换为unsigned With mixed int/unsigned math, the int is converted to an unsigned . 使用混合的int/unsigned math, int将转换为unsigned

Subtracting 2 unsigned results in an unsigned and an unsigned is never negative. unsignedunsigned减去2个unsigned结果绝不是负数。


Assume 32-bit or wider unsigned/int 假设32位或更宽的unsigned/int

-2147483647-1U is a int minus an unsigned , so -2147483647 is converted to unsigned 2147483649 and the difference is unsigned 2147483648 . -2147483647-1Uint减去无符号 ,因此-2147483647转换为unsigned 2147483649 ,差值为unsigned 2147483648 Now an unsigned is compare to an int , so the int is converted to unsigned 2147483649 . 现在将unsignedint进行比较,因此int将转换为unsigned 2147483649 The left is less than the right, so the result is true. 左边小于右边,结果是真的。


[Edit] [编辑]

Assume narrower than 32-bit unsigned/int , yet long uses the common 2's complement encoding. 假设窄于32位unsigned/int ,但long使用公共2的补码编码。 Often seen in embedded 8/16-bit processors in 2017. 经常在2017年的嵌入式8/16位处理器中看到。

-2147483647-1U is a long minus a narrower unsigned , so -2147483647 remains a long and 1U is converted to int 1 and the difference is long -2147483648 . -2147483647-1U是一个长的减去一个较窄的无符号 ,所以-2147483647仍然是long1U被转换为int 1 ,差异是long -2147483648 Now an long is compare to an long . 现在很long时间比较long The left is less than the right, so the result is true. 左边小于右边,结果是真的。

Both are promoted to unsigned and -2147483647-1U == 0x8000000 , (unsigned)-2147483647 == 0x80000001 . 两者都被提升为无符号和-2147483647-1U == 0x8000000(unsigned)-2147483647 == 0x80000001

0x8000000 < 0x8000001 is true 0x8000000 < 0x8000001true

same with signed only 与仅签名相同

-2147483647-1 == `-2147483648`
-2147483648 < -2147483647

It's really quite simple. 这真的很简单。 According to 6.3.1.8 Usual arithmetic conversions if an int meets an unsigned int in an operation, the operands are both converted to unsigned int . 根据6.3.1.8通常的算术转换如果int满足一个unsigned int在操作中,操作数都转换为unsigned int

The conversion formalized as repeatedly adding or subtracting one more than maximum value that can be represented in the new type really describes how natural signed/unsigned reinterpretation works in two's complement arithmetic (the most common way, though not the only way, to represent signed integers in hardware). 转换形式化为重复加法或减去一个可以在新类型中表示的最大值,实际上描述了自然有符号/无符号重新解释如何在二进制补码算法中工作(最常见的方式,但不是唯一的方式,表示有符号整数)在硬件中)。

Two's complement arithmetic on a 32 bit signed number works as follows: 32位有符号数的二进制补码算法如下:

  • the most significant bit, if set, stands for -2^31 最重要的位,如果设置,则代表-2 ^ 31
  • the rest stand for themselves 其余的代表自己

-2147483647 is therefore 2^31+1 == 0b10000000000000000000000000000001 . 因此, -21474836472^31+1 == 0b10000000000000000000000000000001 Now since it comes into a subtraction operation with 1U ( 0b00000000000000000000000000000001 ), you should convert it to a uint32_t number by repeatedly adding or subtracting UINT32_MAX+1 == 2^32 , which after overflow will result in the same binary representation (the rules, I suppose, were made so that the bits could be straightforwardly reinterpreted on 2's complement (most common) platforms), and subtracting 1U from it will straightforwardly yield 0b10000000000000000000000000000000 == 2^31 , which is less than 2^31+1 . 现在,由于它进入1U0b00000000000000000000000000000001 )的减法运算,你应该通过重复加或减UINT32_MAX+1 == 2^32将其转换为uint32_t数,溢出后将导致相同的二进制表示(规则,我想,这样做是为了在2的补码(最常见)平台上直接重新解释这些位,并从中减去1U将直接产生0b10000000000000000000000000000000 == 2^31 ,小于2^31+1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM