Java'da imzasız bir int bildirme


316

Java'da imzasız bir int bildirmenin bir yolu var mı?

Veya soru şu şekilde de çerçevelenebilir: İmzasızın Java eşdeğeri nedir?

Sadece Java'nın uygulamasına baktığım bağlamı anlatmak için String.hashcode(). Eğer tamsayı 32 imzasız int olsaydı çarpışma olasılığını test etmek istedim.


7
Java'da imzasız tür yok.
Andrew Logvinov


2
Bir AFAICT yolu gibi görünmüyor. İlgili: stackoverflow.com/questions/430346/…
James Manning

11
Bu, elde etmeye çalıştığınız amaca bağlıdır. Çoğu amaç için, Java'daki tüm tamsayılar imzalanır. Bununla birlikte, imzalı bir tamsayıyı belirli bir durumda imzasız olarak ele alabilirsiniz : >>>yerine operatörünü kullanarak işaret uzatmadan sağa kaydırabilirsiniz >>.
dasblinkenlight

Yanıtlar:


310

Java'nın imzasız tamsayılar için veri türü yoktur .

Büyük değerleri depolamanız gerekiyorsa, longyerine bir tanımlayabilirsiniz int.

İşaretli bir tamsayıyı imzalanmamış gibi kullanabilirsiniz. İkinin tamamlayıcı gösteriminin yararı, çoğu işlemin (toplama, çıkarma, çarpma ve sola kaydırma gibi) imzalı ve imzasız tamsayılar için ikili düzeyde aynı olmasıdır. Bununla birlikte, birkaç işlem (bölme, sağa kaydırma, karşılaştırma ve döküm) farklıdır. Java SE 8'den itibaren, Integersınıftaki yeni yöntemler, imzalanmamış aritmetik yapmak için intveri türünü tam olarak kullanmanızı sağlar :

Java SE 8 ve sonraki sürümlerinde, minimum 0 ve maksimum 2 ^ 32-1 değerine sahip işaretsiz bir 32 bit tamsayıyı temsil etmek için int veri türünü kullanabilirsiniz. İnt veri türünü işaretsiz bir tam sayı olarak kullanmak için Integer sınıfını kullanın. Gibi Statik yöntemler compareUnsigned, divideUnsignedvb işaretsiz tamsayılar için aritmetik operasyonları desteklemek için tamsayı sınıfına eklendi.

Not olduğu intbildirilen, ancak imzasız aritmetik bu yöntemleri kullanarak artık mümkün olduğunda değişkenler hala imzalanır Integersınıfta.


11
Adil olmak gerekirse, birçok proje için teknik gereklilikler o kadar da katı değildir ve gerçekten böyle bir hafızayı "harcayabilirsiniz".
Simeon Visser

6
Biliyorum, Java'nın orijinal amacını da anlıyorum. Ancak, örneğin Akıllı Telefonlar fazladan bellek kullanmaz. Ve bildiğim kadarıyla genellikle Java kullanıyorlar. Ama Java programcıları ile diğerleri arasında bir savaş başlatmak istemiyorum.
Tomáš Zato - Monica'yı eski durumuna döndür

122
Bana göre bu sadece para israfı değil. Biraz seviyede çalıştığınızda, imzasız çalışmak daha kolaydır
Cruncher

24
Java 8'den itibaren, bu artık doğru değil . Java SE 8 ve sonraki sürümlerinde, intminimum değeri 0ve maksimum değeri olan işaretsiz bir 32 bit tamsayıyı temsil etmek için veri türünü kullanabilirsiniz 2^32-1. - bkz. docs.oracle.com/javase/tutorial/java/nutsandbolts/… ve docs.oracle.com/javase/8/docs/api/java/lang/Integer.html
8bitjunkie

2
@ 7ÖzelGems: Cevabı bu bilgiyi içerecek şekilde güncelledim. Bununla birlikte, imzasız tamsayıları bildirmek veya negatif değerleri dışlamak mümkün değildir, ancak bir intçeşitli yöntemler kullanılarak imzalanmamış gibi kullanmak mümkündür .
Simeon Visser

70

1
@stas imzasız veri türlerini kullanma becerisine sahip olmak konusunda kullanımı anlamakta zorlanıyorum. Çevrimiçi okuduğum çeşitli kaynaklardan, maksimum değeri genişletmek etrafında dönüyor gibi görünüyor ve doğanın örtük olması, bunun pozitif bir sayı olduğunu garanti ediyor. Anladığım doğru mu yoksa başka önemli nedenler var mı? Ayrıca, IntegerJava 8'deki sınıfın işaretsiz int kullanmasına izin verdiğine göre, sadece uzay ve hız arasındaki farktır (çünkü C / C ++ 'da ilkeldirler, Java'da iken, tüm nesne sarıcıdır)
Abdul

2
@Abdul - bit seviyesinde çalışırken (genellikle donanımla arabirim oluşturduğunuz için) belirli bir şekilde davranmak için değerlere ihtiyacınız vardır. yani - 11111111 ila 00000000 vb. sonra rulo. İmzasız imza yerine yerine CRC hesaplamaları vb kırmak olabilir. Bu bir gösteri tıpa değil, sadece boşa zaman.
Lorne K

3
@Lorne K: Java'da, imzalansalar intbile devrilme. İmzasız olarak devredildiği C / C ++, ancak imzalı taşma sırasında “Tanımsız Davranış” a neden olur. Eğer tek endişeniz “yuvarlanmak” ise, imzasız kalmanıza gerek yoktur. Sanırım, bu yüzden CRC rutinleri, vb. Ekstra çaba harcamadan Java'da çalışır. İşte bu yüzden yeni API yalnızca ayrıştırma, biçimlendirme, karşılaştırmalar, bölme ve kalanları ekler. Diğer tüm işlemler, yani tüm bit manipülasyonları, aynı zamanda toplama, çıkarma, çarpma, vb.
Holger

4
@Ciprian Tomoiaga: rollover ile eklemek için, girişin bit kalıpları ve sonuç, onu imzalı numara veya imzasız numara olarak yorumlamanıza bağlı değildir. Sabrınız varsa, tüm 2⁶⁵ kombinasyonlarıyla deneyebilirsiniz…
Holger

3
@Holger açıklama için teşekkürler! Aslında, bu yüzden aslında 2'nin tamamlayıcısını kullanıyoruz. Bazı 2 ^ 8 kombinasyonları ile denedim mi ^ ^
Ciprian Tomoiagă

66

İnt içindeki bir değerin imzalı veya imzasız olup olmadığı bitlerin nasıl yorumlandığına bağlıdır - Java bitleri imzalı bir değer olarak yorumlar (imzasız ilkelleri yoktur).

İmzasız bir değer olarak yorumlamak istediğiniz bir intiniz varsa (örneğin, imzalanmamış bir değer içerdiğini bildiğiniz bir DataInputStream öğesinden bir int okursanız), aşağıdaki hileyi yapabilirsiniz.

int fourBytesIJustRead = someObject.getInt();
long unsignedValue = fourBytesIJustRead & 0xffffffffl;

Onaltılık değişmez bilginin interal değil uzun bir değişmez değer olması ve dolayısıyla sonunda 'l' olması önemlidir.


3
Benim için bu en iyi cevap ... Verilerim 4 veya 8 baytlık bir NFC kart UID'sinden geliyor ... 4 bayt durumunda imzalanmamış bir int'e dökmem gerekiyordu ve yapamadım 64 bit veri olmadığı için ByteBuffer.getLong kullanın. Teşekkürler.
Loudenvier

Neden uzun olması gerekiyor. Sadece yapmak 0xFFFFFFve int tutmak değil mi ?
Displee

19

Biz modellemek için imzasız numaraları gerekli MySQL en imzasız TINYINT, SMALLINT, INT, BIGINTiçinde jOOQ biz yarattık nedeni budur, jOOU , Java işaretsiz tamsayı numaraları için türleri sarıcı minimalist kütüphane sunan. Misal:

import static org.joou.Unsigned.*;

// and then...
UByte    b = ubyte(1);
UShort   s = ushort(1);
UInteger i = uint(1);
ULong    l = ulong(1);

Bu tiplerin tümü genişler java.lang.Numberve daha yüksek mertebeli ilkel tiplere dönüştürülebilir ve BigInteger. Bu yardımcı olur umarım.

(Feragatname: Bu kütüphanelerin arkasındaki şirket için çalışıyorum)


Bu çok uygun geliyor! Bahsettiğiniz için teşekkürler. :)
Lucas Sousa



2

Belki de demek istediğin buydu?

long getUnsigned(int signed) {
    return signed >= 0 ? signed : 2 * (long) Integer.MAX_VALUE + 2 + signed;
}
  • getUnsigned(0) → 0
  • getUnsigned(1) → 1
  • getUnsigned(Integer.MAX_VALUE) → 2147483647
  • getUnsigned(Integer.MIN_VALUE) → 2147483648
  • getUnsigned(Integer.MIN_VALUE + 1) → 2147483649

İf ifadeleri yerine üçlü işleçlerle tembel yazma için saniyede bir performans süresinin milyonda birini feda ediyorsunuz. İyi değil. (şaka)
ytpillai

5
Gerçekten, 2 * (long) Integer.MAX_VALUE + 2anlamaktan daha kolay olduğunu 0x1_0000_0000Lmu düşünüyorsun ? Bu bakımdan, neden basit değil return signed & 0xFFFF_FFFFL;?
Holger

2

İmzalama problemini kullanmadan önce değerler üzerinde bir "mantıksal AND" yaparak çözebilirsiniz:

Örnek (Değer byte[] header[0]IS 0x86):

System.out.println("Integer "+(int)header[0]+" = "+((int)header[0]&0xff));

Sonuç:

Integer -122 = 134

2

Burada iyi cevaplar var, ama bitsel operasyonların herhangi bir gösterisini görmüyorum. Visser (şu anda kabul edilen cevap) dediği gibi, Java varsayılan olarak tamsayılar imzalar (Java 8 imzasız tamsayılara sahiptir, ancak bunları hiç kullanmadım). Daha fazla uzatmadan yapalım ...

RFC 868 Örneği

ES'ye işaretsiz bir tam sayı yazmanız gerekirse ne olur? Pratik örnek, zamanı RFC 868'e göre çıkarmak istediğiniz zamandır . Bu, 1 Ocak 1900'den bu yana saniye sayısını kodlayan 32 bit, big-endian, işaretsiz bir tam sayı gerektirir. Bunu nasıl kodlarsınız?

Kendi imzasız 32 bitlik tam sayınızı şu şekilde yapın:

4 bayt (32 bit) bayt dizisi bildirme

Byte my32BitUnsignedInteger[] = new Byte[4] // represents the time (s)

Bu diziyi başlatır, bkz. Bayt dizileri Java'da sıfırlandı mı? . Şimdi dizideki her baytı big-endian düzenindeki bilgilerle (veya tahribatı yıkmak istiyorsanız little-endian) doldurmanız gerekir. Uzun bir süreye sahip olduğunuzu varsayarsak (Java'da uzun tamsayılar 64 bit uzunluğundadır) denir secondsSince1900(Bu yalnızca ilk 32 biti kullanır ve Tarih'in 12:00 AM 1 Ocak 1970'e başvurduğunu), mantıksal AND'i kullanarak bitleri ayıklayabilir ve bu bitleri bir Byte'a girildiğinde göz ardı edilmeyecek konumlara (basamaklar) ve büyük endian düzenine kaydırabilirsiniz.

my32BitUnsignedInteger[0] = (byte) ((secondsSince1900 & 0x00000000FF000000L) >> 24); // first byte of array contains highest significant bits, then shift these extracted FF bits to first two positions in preparation for coersion to Byte (which only adopts the first 8 bits)
my32BitUnsignedInteger[1] = (byte) ((secondsSince1900 & 0x0000000000FF0000L) >> 16);
my32BitUnsignedInteger[2] = (byte) ((secondsSince1900 & 0x000000000000FF00L) >> 8);
my32BitUnsignedInteger[3] = (byte) ((secondsSince1900 & 0x00000000000000FFL); // no shift needed

Bizim my32BitUnsignedIntegerşimdi işaretsiz 32 bit, big-endian tamsayı denk olduğunu RCF 868 standardına yapışır. Evet, uzun veri tipi imzalandı, ancak bu gerçeği görmezden geldik, çünkü saniyelerSizin1900'ün yalnızca daha düşük 32 bit kullandığını varsaydık). Uzunluğu bir bayta zorladığından, 2 ^ 7'den (onaltılık ilk iki basamak) daha yüksek olan tüm bitler göz ardı edilir.

Referans verilen kaynak: Java Network Programming, 4th Edition.


1

Bu kod parçasını yeni oluşturduk, "this.altura" yı negatiften pozitif sayıya dönüştürür. Umarım bu ihtiyacı olan birine yardımcı olur

       if(this.altura < 0){    

                        String aux = Integer.toString(this.altura);
                        char aux2[] = aux.toCharArray();
                        aux = "";
                        for(int con = 1; con < aux2.length; con++){
                            aux += aux2[con];
                        }
                        this.altura = Integer.parseInt(aux);
                        System.out.println("New Value: " + this.altura);
                    }

-19

Math.abs (sayı) işlevini kullanabilirsiniz. Pozitif bir sayı döndürür.


12
nitpick: Eğer geçerseniz değilMIN_VALUE
Dennis Meng

2
@ kyo722 Bunun imzasız ilkeller aralığında olumlu bir değer getireceğini düşünemiyorum.
Florian R. Klein

1
nitpick # 2: Eğer 0
içeri girmezseniz
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.