Java中的Unsigned Int

13

我正在尝试实现一种现有的网络协议,该协议大量使用Java不支持的无符号数据类型。我目前的做法是为每种数据类型选择下一个更大的数据类型,以便无符号数字可以适应正数区间,然后使用字节移位来获得所需的效果。由于这种方法容易出错,并且对于无符号长整型及以上数据类型,我必须使用比扩展类型更重的BigInteger,我想知道是否有更好的方法来实现这个问题?

1个回答

16
根据你的需求,你可以将long视为64位值,将int视为32位值。大多数操作(尤其是readInt / Long writeInt / Long)通过忽略符号性而正常工作。
你能给出一个你对这些数字执行的操作的示例吗?也许我们可以建议如何做相同的事情,而不必扩展类型。
例如,++,--,+,-,*,==,!=,<<都无论符号性都能正常工作(即给出相同的答案)。对于>>,你可以替换为>>>。
除法/,取模%,>,>=,<,<=和打印函数假定有符号值,但如果您使用它们,则应该能够解决这些问题。
例如:
long unsignedA = 
long unsignedB = 
boolean greater = unsignedA + Long.MIN_VALUE > unsignedB + Long.MIN_VALUE

编辑:为什么这个代码能够运行?部分原因是Java没有溢出/下溢异常。

例如:

byte unsignedA = 0;
unsignedA--; 
// unsignedA == FF, is this -1 or 255? Java assumes the former but you assume the later

byte unsignedB = unsignedA * unsignedA;
// unsignedB is -1 * -1 = 1 or (byte) (255*255) = (byte) 65525 = 1.

嗯,听起来很有前途,我希望只需创建一个InputStream,然后按预期处理值,而不是在程序中拖着它们四处移动。问题是,它们大多数表示IP地址、版本号(非常依赖于>、<、<=和>=),加密哈希(可能没有问题)和时间戳(再次重视比较)。 - cdecker
对于IP地址,您需要使用偏置技巧或扩展为long类型。对于长时间戳,如果它们是以毫秒为单位的,则应该能够假定它们介于0和Long.MAX_VALUE之间。您的版本号是否也使用了最高位?您能给一个使用了最高位的例子吗?(如果是这样,您还需要调整比较)。 - Peter Lawrey
如果你从公元前1年开始计算(因为没有0年),那么有符号的长整型毫秒时间戳最大只能表示到292,471,208年。 - Peter Lawrey
@cdecker,如果你忽略秒的最高位,你仍然可以到达2930亿年,因为太阳只剩下60亿年的寿命... ;) 将日期偏移1970年是相当无意义的。;) 他本来可以从公元前1年开始计算微秒,我想你也不会有问题。 - Peter Lawrey
@Desolator 你可以使用 >>> 进行无符号位移。 - Peter Lawrey
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接