Java:无符号数

发布于 2024-08-07 02:04:12 字数 173 浏览 5 评论 0 原文

Java 中有没有一种方法可以像 (My)SQL 中那样使用无符号数字?

例如:我想使用一个 8 位变量 (byte),其范围如下:0 ... 256;而不是 -128 ... 127

Is there a way in Java to use unsigned numbers like in (My)SQL?

For example: I want to use an 8-bit variable (byte) with a range like: 0 ... 256; instead of -128 ... 127.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

黯淡〆 2024-08-14 02:04:12

不,除了 char(其值实际上为 0-65535)之外,Java 没有任何无符号基元类型。这很痛苦(特别是对于byte),但事实就是如此。

通常,您要么坚持使用相同的大小,并溢出到“高”数字的负数,要么使用更宽的类型(例如 short 表示 byte)并应对额外的情况内存要求。

No, Java doesn't have any unsigned primitive types apart from char (which has values 0-65535, effectively). It's a pain (particularly for byte), but that's the way it is.

Usually you either stick with the same size, and overflow into negatives for the "high" numbers, or use the wider type (e.g. short for byte) and cope with the extra memory requirements.

愁杀 2024-08-14 02:04:12

您可以使用类来模拟无符号数。例如

public class UInt8 implements Comparable<UInt8>,Serializable
   {
   public static final short MAX_VALUE=255;
   public static final short MIN_VALUE=0;
   private short storage;//internal storage in a int 16

   public UInt8(short value)
      {
      if(value<MIN_VALUE || value>MAX_VALUE) throw new IllegalArgumentException();
      this.storage=value;
      }

   public byte toByte()
      {
      //play with the shift operator ! << 
      }
  //etc...
   }

You can use a class to simulate an unsigned number. For example

public class UInt8 implements Comparable<UInt8>,Serializable
   {
   public static final short MAX_VALUE=255;
   public static final short MIN_VALUE=0;
   private short storage;//internal storage in a int 16

   public UInt8(short value)
      {
      if(value<MIN_VALUE || value>MAX_VALUE) throw new IllegalArgumentException();
      this.storage=value;
      }

   public byte toByte()
      {
      //play with the shift operator ! << 
      }
  //etc...
   }
淡写薰衣草的香 2024-08-14 02:04:12

大多数情况下,您可以像使用无符号数字一样使用有符号数字。大多数操作保持不变,有些需要修改。请参阅这篇文章

You can mostly use signed numbers as if they were unsigned. Most operations stay the same, some need to be modified. See this post.

你的背包 2024-08-14 02:04:12

在内部,您不应该使用较小的值——只需使用 int。据我了解,使用较小的单位只会减慢速度。它不会节省内存,因为 Java 在内部使用系统的字大小进行所有存储(它不会打包字)。

但是,如果您使用较小尺寸的存储单元,则必须对每个操作进行屏蔽或范围检查或其他操作。

有没有注意到 char (任何操作) char 都会产生 int ?他们只是真的不希望您使用这些其他类型。

例外是数组(我相信它们会被打包)和 I/O,您可能会发现使用较小的类型很有用……但屏蔽也可以工作。

Internally, you shouldn't be using the smaller values--just use int. As I understand it, using smaller units does nothing but slow things down. It doesn't save memory because internally Java uses the system's word size for all storage (it won't pack words).

However if you use a smaller size storage unit, it has to mask them or range check or something for every operation.

ever notice that char (any operation) char yields an int? They just really don't expect you to use these other types.

The exceptions are arrays (which I believe will get packed) and I/O where you might find using a smaller type useful... but masking will work as well.

岛徒 2024-08-14 02:04:12

不,你无法改变这一点。如果您需要大于 127 的值,请选择大于字节的值。

Nope, you can't change that. If you need something larger than 127 choose something larger than a byte.

浅紫色的梦幻 2024-08-14 02:04:12

如果您需要优化存储(例如大矩阵),您可以用负数编码更大的正数,以节省空间。然后,您必须在需要时移动数值才能获得实际值。例如,我只想操纵短正数。这在 Java 中是如何实现的:

        short n = 32767;
        n = (short) (n + 10);
        System.out.println(n);     
        int m = (int) (n>=0?n:n+65536); 
        System.out.println(m);

因此,当短整数超出范围时,它会变为负数。然而,至少你可以将这个数字存储在 16 位中,并通过添加移位值(可以编码的不同值的数量)来恢复其正确值。该值应该以更大的类型(在我们的例子中为 int )恢复。这可能不是很方便,但我发现对于我来说确实如此。

If you need to optimize your storage (e.g. large matrix) you can u can code bigger positive numbers with negatives numbers, so to save space. Then, you have to shift the number value to get the actual value when needed. For instance, I want to manipulate short positive numbers only. Here how this is possible in Java:

        short n = 32767;
        n = (short) (n + 10);
        System.out.println(n);     
        int m = (int) (n>=0?n:n+65536); 
        System.out.println(m);

So when a short integer exceeds range, it becomes negative. Yet, at least you can store this number in 16 bits, and restore its correct value by adding shift value (number of different values that can be coded). The value should be restored in a larger type (int in our case). This may not be very convenient, but I find it's so in my case.

雨巷深深 2024-08-14 02:04:12

我对 Java 和编程都很陌生。
然而,我最近遇到了同样的情况,需要无符号值。

我花了大约两周的时间来编写我想到的所有内容,但我完全是个菜鸟,所以你可以花更少的钱。

总体思路是创建接口,我将其命名为:UnsignedNumber 并扩展 Number.class,同时实现抽象 AbstractUnsigned> 类。

所以,Base参数化类型代表基本类型,Shifted代表实际的Java类型。 Impl 是实现这个抽象类的快捷方式。

大部分时间消耗在 Java 8 Lambda 的样板以及内部私有类和安全过程上。重要的是当减法或负加等数学运算产生零限制时,实现无符号的行为:向后溢出有符号上限。

最后,又花了几天时间来编写工厂和实现子类的代码。

到目前为止我已经知道:
UByte 和 MUByte
UShort 和 MUshort
UInt 和 MUInt
...等等。

他们是 AbstractUnsigned 的后代:
UByte 或 MUByte 扩展 AbstractUnsignedAbstractUnsigned
UShort 或 MUShort 扩展 AbstractUnsignedAbstractUnsigned
...ETC。

总体思想是将无符号上限作为移位(强制转换)类型和负值的代码转置,因为它们不是来自零,而是来自无符号上限。

更新:
(感谢 Ajeans 友善而礼貌的指示)

/**
* Adds value to the current number and returns either
* new or this {@linkplain UnsignedNumber} instance based on
* {@linkplain #isImmutable()}
*
* @param value value to add to the current value
* @return new or same instance
* @see #isImmutable()
*/
public Impl plus(N value) {
    return updater(number.plus(convert(value)));
}

这是 AbstractUnsigned 的外部可访问方法;(或者正如之前所说的AbstractUnsigned);
现在,进行底层工作:

private Impl updater(Shifted invalidated){
    if(mutable){
        number.setShifted(invalidated);
        return caster.apply(this);
    } else {
        return shiftedConstructor.apply(invalidated);
    }
}

在上面的私有方法中,mutable 是一个AbstractUnsigned私有最终布尔值number 是内部私有类之一,负责将 Base 转换为 Shifted,反之亦然。
与之前的“我去年夏天做了什么”相对应的重要内容
是两个内部对象:castershiftedConstructor

final private Function<UnsignedNumber<N, Shifted>, Impl> caster;
final private Function<Shifted, Impl> shiftedConstructor;

这些是将 N(或 Base)转换为的参数化函数Shifted 或创建新的 Impl 实例(如果 AbstractUnsigned<> 的当前实现实例是不可变的)。

Shifted plus(Shifted value){
    return spawnBelowZero.apply(summing.apply(shifted, value));
}

在此片段中显示了 number 对象的添加方法。这个想法是始终在内部使用 Shifted,因为不确定何时产生“原始”类型的正限制。 shifted 是一个内部参数化字段,它承载整个 AbstractUnsigned<> 的值。下面给出了另外两个 Function>> 派生对象:

final private BinaryOperator<Shifted> summing;
final private UnaryOperator<Shifted> spawnBelowZero;

前者执行两个 Shifted 值的加法。后者在零转位以下进行产卵。

现在是来自 AbstractUnsigned 的工厂样板“地狱”之一的示例,专门针对之前提到的 spawnBelowZero UnaryOperator >:

...,
         v-> v >= 0
         ? v
         : (short) (Math.abs(Byte.MIN_VALUE) + Byte.MAX_VALUE + 2 + v),
...

如果 Shifted v 为正,则不会发生任何事情,并且会返回原始值。否则:需要计算 Base 类型的上限(即 Byte),并将该值加起来为负值 v。假设,v == -8Math.abs(Byte.MIN_VALUE) 将生成 128Byte.MAX_VALUE 将产生 127 ,它给出 255 + 1 以获得原始上限,该上限被符号位切断,正如我所得到的那样,如此理想256 就在这个地方。但第一个负值实际上是256,这就是为什么再次+1或总共+2的原因。最后,255 + 2 + v(即-8)给出255 + 2 + (-8)249

或者以更直观的方式:

0 1 2 3 ... 245 246 247 248 249 250 251 252 253 254 255 256
                             -8  -7  -6  -5  -4  -3  -2  -1

最后确定所有这些:这绝对不会减轻您的工作或节省内存字节,但在需要时您会获得非常理想的行为。您几乎可以将这种行为与任何其他 Number.class 子类一起使用。 AbstractUnsignedNumber.class 的子类,它本身提供了所有方便的方法和常量
与其他“原生”Number.class 子类类似,包括 MIN_VALUEMAX_VALUE 等等,例如,我为可变代码编写了便捷方法名为 makeDivisibileBy(Number n) 的子类执行最简单的 value - (value % n) 操作。

我最初的努力是为了证明即使像我这样的菜鸟也可以编写代码。当我编写该类代码时,我最初的努力是获得方便的多功能工具以供持续使用。

I'm quite new to Java and to programming.
Yet, I encountered the same situation recently the need of unsigned values.

It took me around two weeks to code everything I had in mind, but I'm a total noob, so you could spend much less.

The general idea is to create interface, I have named it: UnsignedNumber<Base, Shifted> and to extend Number.class whilst implementing an abstract AbstractUnsigned<Base, Shifted, Impl extends AbstractUnsigned<Base, Shifted, Impl>> class.

So, Base parameterized type represents the base type, Shifted represents actual Java type. Impl is a shortcut for Implementation of this abstract class.

Most of the time consumed boilerplate of Java 8 Lambdas and internal private classes and safety procedures. The important thing was to achieve the behavior of unsigned when mathematical operation like subtraction or negative addition spawns the zero limit: to overflow the upper signed limit backwards.

Finally, it took another couple of days to code factories and implementation sub classes.

So far I have know:
UByte and MUByte
UShort and MUShort
UInt and MUInt
... Etc.

They are descendants of AbstractUnsigned:
UByte or MUByte extend AbstractUnsigned<Byte, Short, UByte> or AbstractUnsigned<Byte, Short, MUByte>
UShort or MUShort extend AbstractUnsigned<Short, Integer, UShort> or AbstractUnsigned<Short, Integer, MUShort>
...etc.

The general idea is to take unsigned upper limit as shifted (casted) type and code transposition of negative values as they were to come not from zero, but the unsigned upper limit.

UPDATE:
(Thanks to Ajeans kind and polite directions)

/**
* Adds value to the current number and returns either
* new or this {@linkplain UnsignedNumber} instance based on
* {@linkplain #isImmutable()}
*
* @param value value to add to the current value
* @return new or same instance
* @see #isImmutable()
*/
public Impl plus(N value) {
    return updater(number.plus(convert(value)));
}

This is an externally accessible method of AbstractUnsigned<N, Shifted, Impl> (or as it was said before AbstractUnsigned<Base, Shifted, Impl>);
Now, to the under-the-hood work:

private Impl updater(Shifted invalidated){
    if(mutable){
        number.setShifted(invalidated);
        return caster.apply(this);
    } else {
        return shiftedConstructor.apply(invalidated);
    }
}

In the above private method mutable is a private final boolean of an AbstractUnsigned. number is one of the internal private classes which takes care of transforming Base to Shifted and vice versa.
What matters in correspondence with previous 'what I did last summer part'
is two internal objects: caster and shiftedConstructor:

final private Function<UnsignedNumber<N, Shifted>, Impl> caster;
final private Function<Shifted, Impl> shiftedConstructor;

These are the parameterized functions to cast N (or Base) to Shifted or to create a new Impl instance if current implementation instance of the AbstractUnsigned<> is immutable.

Shifted plus(Shifted value){
    return spawnBelowZero.apply(summing.apply(shifted, value));
}

In this fragment is shown the adding method of the number object. The idea was to always use Shifted internally, because it is uncertain when the positive limits of 'original' type will be spawned. shifted is an internal parameterized field which bears the value of the whole AbstractUnsigned<>. The other two Function<> derivative objects are given below:

final private BinaryOperator<Shifted> summing;
final private UnaryOperator<Shifted> spawnBelowZero;

The former performs addition of two Shifted values. And the latter performs spawning below zero transposition.

And now an example from one of the factory boilerplates 'hell' for AbstractUnsigned<Byte, Short> specifically for the mentioned before spawnBelowZero UnaryOperator<Shifted>:

...,
         v-> v >= 0
         ? v
         : (short) (Math.abs(Byte.MIN_VALUE) + Byte.MAX_VALUE + 2 + v),
...

if Shifted v is positive nothing really happens and the original value is being returned. Otherwise: there's a need to calculate the upper limit of the Base type which is Byte and add up to that value negative v. If, let's say, v == -8 then Math.abs(Byte.MIN_VALUE) will produce 128 and Byte.MAX_VALUE will produce 127 which gives 255 + 1 to get the original upper limit which was cut of by the sign bit, as I got that, and the so desirable 256 is in the place. But the very first negative value is actually that 256 that's why +1 again or +2 in total. Finally, 255 + 2 + v which is -8 gives 255 + 2 + (-8) and 249

Or in a more visual way:

0 1 2 3 ... 245 246 247 248 249 250 251 252 253 254 255 256
                             -8  -7  -6  -5  -4  -3  -2  -1

And to finalize all that: this definitely does not ease your work or saves memory bytes, but you have a pretty much desirable behaviour when it is needed. And you can use that behaviour pretty much with any other Number.class subclasses. AbstractUnsigned being subclass of Number.class itself provides all the convenience methods and constants
similar to other 'native' Number.class subclasses, including MIN_VALUE and MAX_VALUE and a lot more, for example, I coded convenience method for mutable subclasses called makeDivisibileBy(Number n) which performs the simplest operation of value - (value % n).

My initial endeavour here was to show that even a noob, such as I am, can code it. My initial endeavour when I was coding that class was to get conveniently versatile tool for constant using.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文