我有一个与编程/数学相关的问题,涉及在大字节序和小字节序之间进行转换并进行算术运算。
假设我们在小端模式下有两个整数:
int a = 5;
int b = 6;
//a+b = 11
让我们翻转字节并再次添加它们:
int a = 1280;
int b = 1536;
//a+b = 2816
现在,如果我们翻转2816
的字节顺序,我们将得到11
。那么从本质上讲,我们可以在小端和大端之间进行算术计算,一旦转换,它们就代表相同的数字?
在计算机科学界,它背后是否有理论/名称?
答案 0 :(得分:1)
如果加法涉及进位,则无效,因为进位是从右向左传播的。交换数字并不意味着携带切换方向,因此溢出到下一个字节的任何字节都会不同。
让我们看一个十六进制的示例,假装字节序意味着每个4位半字节被交换:
int a = 0x68;
int b = 0x0B;
//a+b: 0x73
int a = 0x86;
int b = 0xB0;
//a+b: 0x136
8 16 + B 16 是13 16 。 1被携带并加到第一个和中的6上。但是在第二个和中,它没有被右移并加到6,它被左移并溢出到第三个十六进制数字。
答案 1 :(得分:0)
这似乎是可行的,因为您碰巧选择了足够小的数字,以便它们及其和适合一个字节。只要数字中发生的所有事情都停留在其各自的字节之内,您显然可以随意对字节进行洗牌和洗牌,这不会有任何不同。如果您选择较大的数字,例如1234和4321,您会注意到它不再起作用。实际上,您极有可能最终会调用未定义的行为,因为您的int
将溢出…
除此之外,您几乎肯定会想要阅读以下内容:ip-masq-agent
答案 2 :(得分:0)
首先,应注意,您对C中的int
具有16位的假设是错误的。在大多数现代系统中,int
是32位类型,因此如果我们反转(而不是翻转,这是补码)5个字节,我们将得到83886080,而不是1280
现在就如其他人所说,ntohl(htonl(5) + htonl(6))
可能与5 + 6相同,只是因为您的数字很小,他们的反向求和不会溢出。选择较大的数字,您会立即看到差异
对于在这种情况下将值存储在2个较小的部分中的系统,该属性保留在ones' complement 中
在一个补语中,一个人通过向进位进位传播进位来对end-around carry进行算术运算。如果一个补语中只有一个内部“进位”,则补语就成为 endian独立中断”(即,存储的值分为两个单独的块)
假设我们有xxyy和zztt,那么xxyy + zztt就是这样
carry
xx yy
+ zz <───── tt
──────────────
carry aa bb
│ ↑
└─────────────┘
当我们反转这些块时,yyxx + ttzz的携带方式相同。因为xx,yy,zz,tt是任意长度的位块,所以它适用于PDP的混合字节序,或者当您将32位数字存储在两个16位部分中时,将64位数字存储在两个32位部分中...
例如:
或者上面的John Kugelman的示例:0x68 + 0x0B = 0x73; 0x86 + 0xB0 = 0x136→0x36 + 1 = 0x37
末端进位进位是选择TCP校验和的补码的原因之一,因为您可以轻松地以较高的精度计算和。 16位CPU可以像通常一样以16位单元工作,但是32位和64位CPU可以并行添加32位和64位块,而不必担心SWAR技术无法使用SIMD时的进位。