Java가 서명되지 않은 정수를 지원하지 않는 이유는 무엇입니까?
Java가 부호없는 정수에 대한 지원을 포함하지 않는 이유는 무엇입니까?
예기치 않은 큰 입력에서 오버플로가 발생할 가능성이 적은 코드를 작성할 수 있다는 점을 감안할 때 이상한 생략 인 것 같습니다.
또한 부호없는 정수를 사용하는 것은 자체 문서화의 한 형태 일 수 있습니다. 부호없는 정수가 보유하려고 한 값이 절대 음수로 표시되지 않기 때문입니다.
마지막으로 부호없는 정수는 나누기와 같은 특정 작업에 더 효율적일 수 있습니다.
이것들을 포함하면 어떤 단점이 있습니까?
이것은 단순성에 대한 Gosling 및 다른 사람들과 의 인터뷰 에서 얻은 것입니다 .
Gosling : 저를 요즘으로 생각하지 않는 언어 디자이너로서 저에게 "간단한"이라는 말은 J. Random Developer가 그의 머리 속에 스펙을 갖도록 기대할 수있었습니다. 예를 들어, Java는 그렇지 않다는 사실이 있습니다. 실제로 이러한 언어는 실제로 이해하지 못하는 많은 경우로 끝납니다. 서명되지 않은 C 개발자에 대한 퀴즈를 풀면 곧 C 개발자가 서명되지 않은 연산, 서명되지 않은 산술이 무엇인지 이해하는 사람이 거의 없다는 것을 알게 될 것입니다. 그런 것들이 C를 복잡하게 만들었습니다. Java의 언어 부분은 매우 간단하다고 생각합니다. 찾아야 할 라이브러리.
선 사이를 읽으면 논리가 다음과 같다고 생각합니다.
- 일반적으로 Java 디자이너는 사용 가능한 데이터 유형의 레퍼토리를 단순화하려고했습니다.
- 일상적인 목적으로 서명 된 데이터 유형이 가장 일반적으로 필요하다고 느꼈습니다.
- 특정 알고리즘을 구현하기 위해 부호없는 산술이 필요한 경우도 있지만 이러한 알고리즘을 구현하는 프로그래머의 종류는 부호있는 데이터 유형으로 부호없는 산술을 수행하는 데 대한 지식이 있어야합니다.
대부분, 나는 그것이 합리적인 결정이라고 말했습니다. 아마도, 나는 :
- 바이트를 부호없는 것으로 만들거나 적어도 하나의 데이터 유형에 대해 다른 이름을 가진 부호있는 / 부호없는 대안을 제공했습니다 (서명을 만드는 것이 일관성에 좋지만 언제 부호있는 바이트가 필요합니까?)
- '짧은'으로 없애 버렸습니다 (16 비트 부호있는 산술을 언제 마지막으로 사용 했습니까?)
그럼에도 불구하고 약간의 클루 징을 통해 최대 32 비트의 부호없는 값에 대한 작업은 그리 나쁘지 않으며 대부분의 사람들은 부호없는 64 비트 나누기 또는 비교가 필요하지 않습니다.
이것은 오래된 질문이며 pat은 간단히 char을 언급했지만,이 길을 내려다 보는 다른 사람들을 위해 이것을 확장해야한다고 생각했습니다. Java 프리미티브 유형을 자세히 살펴 보겠습니다.
byte
-8 비트 부호있는 정수
short
-16 비트 부호있는 정수
int
-32 비트 부호있는 정수
long
-64 비트 부호있는 정수
char
-16 비트 문자 (부호없는 정수)
하지만 char
지원하지 않는 unsigned
연산, 그것은 본질적으로 처리 할 수 있습니다 unsigned
정수입니다. 산술 연산을 명시 적으로 다시로 캐스팅해야 char
하지만 unsigned
숫자 를 지정하는 방법을 제공합니다 .
char a = 0;
char b = 6;
a += 1;
a = (char) (a * b);
a = (char) (a + b);
a = (char) (a - 16);
b = (char) (b % 3);
b = (char) (b / a);
//a = -1; // Generates complier error, must be cast to char
System.out.println(a); // Prints ?
System.out.println((int) a); // Prints 65532
System.out.println((short) a); // Prints -4
short c = -4;
System.out.println((int) c); // Prints -4, notice the difference with char
a *= 2;
a -= 6;
a /= 3;
a %= 7;
a++;
a--;
예, 부호없는 정수에 대한 직접적인 지원은 없습니다 (직접 지원이 있다면 대부분의 작업을 char로 다시 캐스팅 할 필요는 없습니다). 그러나 서명되지 않은 기본 데이터 유형이 반드시 존재합니다. 나는 부호없는 바이트도보고 싶었지만 메모리 비용을 두 배로 늘리고 대신 char을 사용하는 것이 가능한 옵션이라고 생각합니다.
편집하다
JDK8 거기위한 새로운 API는 다음 Long
과 Integer
헬퍼 메소드 제공하는 처리 long
및 int
부호 값으로 값.
compareUnsigned
divideUnsigned
parseUnsignedInt
parseUnsignedLong
remainderUnsigned
toUnsignedLong
toUnsignedString
또한 구아바 는 정수 유형에서 비슷한 작업을 수행하는 여러 가지 도우미 메서드를 제공하여 정수에 대한 기본 지원 부족으로 인해 발생하는 격차를 좁 unsigned
힙니다.
Java에는 서명되지 않은 유형이 있거나 적어도 하나가 있습니다. char는 부호가없는 축약 형입니다. 고슬링이 변명하는 것이 무엇이든지간에 서명되지 않은 다른 유형이없는 이유는 실제로 그의 무지입니다.
또한 짧은 유형 : 반바지는 멀티미디어에 항상 사용됩니다. 그 이유는 단일 32 비트 부호없는 길이로 2 개의 샘플을 맞추고 많은 연산을 벡터화 할 수 있기 때문입니다. 8 비트 데이터와 부호없는 바이트도 마찬가지입니다. 벡터화를 위해 레지스터에 4 개 또는 8 개의 샘플을 맞출 수 있습니다.
부호있는 정수와 부호없는 정수가 표현에 섞여 나면 일 이 지저분 해지고 정보 가 손실 될 수 있습니다. 서명 된 정수로 Java를 제한하면 실제로 문제가 해결됩니다. 서명 된 / 서명되지 않은 전체 비즈니스에 대해 걱정할 필요가 없어서 기쁘지만 때로는 바이트에서 8 비트를 놓치게됩니다.
http://skeletoncoder.blogspot.com/2006/09/java-tutorials-why-no-unsigned.html
이 표준은 C 표준이 부호없는 및 부호있는 정수를 포함하는 연산을 부호없는 것으로 취급하기 때문에이를 정의하기 때문이라고 말합니다. 음의 부호있는 정수가 부호없는 큰 int로 롤오버되어 버그가 발생할 수 있습니다.
Java는 그대로 괜찮다고 생각하고 unsigned를 추가하면 많은 이득없이 복잡하게 만들 수 있습니다. 단순화 된 정수 모델을 사용하더라도 대부분의 Java 프로그래머는 기본 숫자 유형의 작동 방식을 알지 못합니다. Java Puzzlers 라는 책을 읽고 어떤 오해가 생길 수 있는지 확인하십시오.
실용적인 조언에 관해서는 :
값이 임의의 크기이며에 맞지 않으면를
int
사용하십시오long
.long
사용에 적합하지 않은 경우BigInteger
.공간을 절약해야 할 때 배열에만 더 작은 유형을 사용하십시오.
정확히 64/32/16/8 비트가 필요한 경우
long
/int
/short
/를 사용byte
하고 나누기, 비교, 오른쪽 이동 및 캐스팅을 제외하고 부호 비트에 대해 걱정하지 마십시오 .
"난수 생성기를 C에서 Java로 이식"에 대한 이 답변 도 참조하십시오 .
로 JDK8 그것은 그들을 위해 어떤 지원을 가지고있다.
Gosling의 우려에도 불구하고 Java에서 서명되지 않은 유형을 완벽하게 지원할 수 있습니다.
이 게시물이 너무 오래되었다는 것을 알고 있습니다. 그러나 Java 8 이상에서는 int
데이터 유형을 사용하여 최소값 0과 최대 값 2 32 -1 의 부호없는 32 비트 정수를 나타낼 수 있습니다 . 사용 Integer
용도에 클래스 int
부호없는 정수와 같은 정적 방법으로 데이터 타입 compareUnsigned()
, divideUnsigned()
등등에 부가 된 Integer
부호없는 정수에 대한 산술 연산을 지원하는 클래스.
나는 그것들이 orignal Java 릴리스에 가깝게 포함되어야한다는 이야기를 들었습니다. Oak는 Java의 선구자였으며 일부 사양 문서에는 사용 된 값에 대한 언급이있었습니다. 불행히도 이것들은 결코 Java 언어로 만들지 않았습니다. 누구나 알아낼 수있는 한 시간 제약으로 인해 구현되지 않았습니다.
나는 한 번 C ++ 표준위원회의 누군가와 함께 C ++ 과정을 밟았는데, 이는 서명되지 않은 정수를 사용하는 대부분의 프로그램이 부호있는 정수와 마찬가지로 할 수 있기 때문에 Java가 부호없는 정수를 피하기 위해 올바른 결정을 내렸다는 것을 암시했습니다. (2) 부호없는 정수를 사용하면 정수 산술 오버플로 및 부호있는 유형과 부호없는 유형 사이를 변환 할 때 중요한 비트를 잃는 것과 같은 문제를 쉽게 만들 수는 있지만 디버그하기가 어렵습니다. 부호있는 정수를 사용하여 실수로 1에서 0을 빼면 2 ^ 32-1을 감쌀 때보 다 프로그램이 더 빨리 중단되고 버그를 쉽게 찾을 수 있으며 컴파일러 및 정적 분석 도구 및 런타임 검사는 부호없는 산술을 사용하기로 선택한 이후에 수행중인 작업을 알고 있다고 가정합니다. 또한,
오래 전에 메모리가 제한되고 프로세서가 한 번에 64 비트에서 자동으로 작동하지 않았을 때 모든 비트가 더 많이 계산되었으므로 부호없는 바이트 또는 반바지와 부호를 갖는 것이 실제로 훨씬 더 중요한 문제였으며 분명히 올바른 설계 결정이었습니다. 오늘날 부호가있는 int를 사용하는 것은 거의 모든 정규 프로그래밍 사례에서 충분하며, 프로그램이 실제로 2 ^ 31-1보다 큰 값을 사용해야하는 경우에는 종종 길어야합니다. long을 사용하는 영역에 들어가면 2 ^ 63-1 양의 정수로 실제로 얻을 수없는 이유를 생각해내는 것이 더 어렵습니다. 128 비트 프로세서로 갈 때마다 별 문제가되지 않습니다.
귀하의 질문은 "자바가 부호없는 정수를 지원하지 않는 이유는 무엇입니까?"
그리고 귀하의 질문에 대한 나의 대답은 Java가 모든 기본 유형 인 byte , char , short , int 및 long 이 어셈블리에서와 마찬가지로 byte , word , dword 및 qword로 각각 처리되어야하며 Java 연산자가 서명 되기를 원한다는 것입니다. char를 제외한 모든 기본 유형에 대한 연산 이지만 char 에서만 16 비트 부호가 없습니다.
따라서 정적 메소드는 것으로 가정 서명 동작을 도 32 및 64 비트에 대해.
서명되지 않은 작업에 대해 정적 메서드를 호출 할 수있는 최종 클래스가 필요 합니다.
이 최종 클래스를 생성하고 원하는 이름으로 호출하고 정적 메소드를 구현할 수 있습니다.
정적 메소드를 구현하는 방법에 대해 모른다면 이 링크 가 도움 이 될 수 있습니다.
내 의견으로는, 자바는 하지 ++ C와 유사한 전혀 이 경우, 어느 쪽도 서명되지 않은 유형 지원하지 않으며 연산자 오버로딩을 나는 자바는 모두 C에서 ++와 C는 전혀 다른 언어로 취급해야한다고 생각하므로,
그런데 언어의 이름도 완전히 다릅니다.
따라서 Java에서 C와 유사한 코드를 입력하는 것은 권장하지 않으며 C ++과 유사한 코드를 입력하지 않는 것이 좋습니다 .Java에서는 C ++에서 다음에 수행하려는 작업을 수행 할 수 없기 때문에, 즉, 코드는 전혀 C ++이 아니며 계속 나에게 스타일을 변경하는 것은 좋지 않습니다.
서명 된 연산에도 정적 메소드를 작성하고 사용하는 것이 좋습니다. 따라서 코드에 서명 된 연산 만 필요하지 않은 한 부호있는 연산과 서명되지 않은 연산 모두에 대한 연산자와 정적 메소드의 코드 혼합을 볼 수 없으며 괜찮습니다. 연산자 만 사용하십시오.
또한 short , int 및 long 기본 유형을 사용 하지 말고 word , dword 및 qword를 각각 대신 사용하는 것이 좋습니다. 연산자 대신 서명되지 않은 작업 및 / 또는 서명 된 작업에 대한 정적 메서드를 호출하는 것입니다.
서명 된 연산 만 수행하고 코드에서만 연산자를 사용하려는 경우 이러한 기본 유형을 short , int 및 long 사용하는 것이 좋습니다 .
실제로 word , dword 및 qword 는 언어에 존재 하지 않지만 각각에 대해 새 클래스를 만들 수 있으며 각각의 구현은 매우 쉽습니다.
클래스 워드 는 기본 유형을 짧게 유지하고 클래스 dword 는 기본 유형을 int 만 보유하고 qword 클래스 는 기본 유형을 길게 보유합니다 . 이제 모든 부호없는 메소드와 부호있는 메소드가 정적이거나 선택하지 않은 것처럼 각 클래스에서 구현 할 수 있습니다. 즉, 부호없는 단어 와 부호있는 클래스의 의미 이름을 지정하여 부호없는 문자 와 부호있는 모든 16 비트 연산을 서명 할 수 있습니다. dword 클래스 에 의미 이름을 제공하여 부호가 있고 qword 클래스 에 의미 이름을 제공하여 부호가없고 부호있는 모든 64 비트 연산이 있습니다 .
각 방법에 대해 너무 많은 다른 이름을주고 마음에 들지 않으면, 당신은 항상 자바 않았다 읽고, 자바에 과부하를 잘 사용할 수 없는 것을 너무 제거!
8 비트 부호있는 조작에 대한 연산자가 아닌 메소드와 전혀 연산자가없는 8 비트 부호없는 조작에 대한 메소드가 필요한 경우 Byte 클래스를 작성할 수 있습니다 (첫 번째 문자 'B'는 대문자 임). primitive type byte ) 및이 클래스의 메소드를 구현하십시오.
값으로 전달 및 참조로 전달 정보 :
C #에서와 같이 내가 틀리지 않으면 기본 객체는 자연스럽게 값으로 전달되지만 클래스 객체는 자연스럽게 참조로 전달되므로 Byte , word , dword 및 qword 유형의 객체는 값이 아닌 참조로 전달됩니다 기본적으로. Java에 C #에서와 같이 구조체 객체 가 있기를 바랍니다 . 따라서 모든 Byte , word , dword 및 qword 를 클래스 대신 구조체 로 구현할 수 있습니다.따라서 기본 유형과 같이 C #의 모든 struct 객체는 기본적으로 참조가 아닌 값으로 전달되지만 Java는 C #보다 나쁘기 때문에 기본적으로 참조가 아닌 값으로 전달되었습니다. 이를 처리하기 위해 기본적으로 값이 아닌 참조로 전달되는 클래스와 인터페이스 만 있습니다. 따라서 Java 및 C #의 다른 클래스 객체와 같이 Byte , word , dword 및 qword 객체를 참조가 아닌 값 으로 전달 하려면 복사 생성자를 사용하면됩니다.
그것이 내가 생각할 수있는 유일한 솔루션입니다. 난 그냥 할 것을 나는 수 만 지원하는 것을 C #을 달리 전혀 단어, DWORD와 QWORD하지만, 자바도 지원 형식 정의도 사용에 대한 기본 유형, 형식 정의 사용 은 C의 형식 정의에 해당합니다.
출력 정보 :
동일한 비트 시퀀스 에 대해 여러 가지 방법 으로 비트 를 인쇄 할 수 있습니다. 2 진 (C printf의 % u와 같은 의미), 8 진 (C printf의 % o와 같은 의미), 16 진 (같은) C printf에서 % x의 의미) 및 정수 (C printf에서 % d의 의미)
C printf는 함수에 매개 변수로 전달되는 변수의 유형을 알지 못하므로 printf는 함수의 첫 번째 매개 변수에 전달 된 char * 객체에서만 각 변수의 유형을 알고 있습니다.
따라서 Byte , word , dword 및 qword 각 클래스에서 print 메소드를 구현하고 printf의 기능을 얻을 수 있습니다. 클래스의 기본 유형이 서명 된 경우에도 관련 알고리즘을 따라 서명되지 않은 상태로 인쇄 할 수 있습니다 논리 및 시프트 연산을 사용하여 숫자를 출력으로 인쇄합니다.
불행히도 내가 준 링크는 이러한 인쇄 방법을 구현하는 방법을 보여주지 않지만 이러한 인쇄 방법을 구현하는 데 필요한 알고리즘을 Google에서 찾을 수 있다고 확신합니다.
그게 내가 당신의 질문에 대답하고 당신에게 제안 할 수있는 전부입니다.
unsigned
유형은 순수한 악 이기 때문입니다.
C에서 unsigned - int
생산 한다는 사실 unsigned
은 훨씬 더 악하다.
다음은 한 번 이상 나를 태운 문제의 스냅 샷입니다.
// We have odd positive number of rays,
// consecutive ones at angle delta from each other.
assert( rays.size() > 0 && rays.size() % 2 == 1 );
// Get a set of ray at delta angle between them.
for( size_t n = 0; n < rays.size(); ++n )
{
// Compute the angle between nth ray and the middle one.
// The index of the middle one is (rays.size() - 1) / 2,
// the rays are evenly spaced at angle delta, therefore
// the magnitude of the angle between nth ray and the
// middle one is:
double angle = delta * fabs( n - (rays.size() - 1) / 2 );
// Do something else ...
}
아직 버그를 보셨습니까? 디버거를 시작한 후에 만 보았습니다.
n
부호없는 유형 이므로 size_t
전체 표현식이로 n - (rays.size() - 1) / 2
평가됩니다 unsigned
. 그 표현은 중간 광선으로부터의 광선 의 부호있는 위치 가되도록 의도된다 n
: 좌측의 중간 광선으로부터의 제 1 광선은 위치 -1을 가질 것이고, 오른쪽의 제 1 광선은 위치 +1을 가질 것이다. abs 값을 취하고 delta
각도를 곱하면 n
광선과 중간 광선 사이의 각도를 얻을 수 있습니다.
불행히도 위의 표현에는 악의 부호가없고 -1로 평가하는 대신 2 ^ 32-1로 평가되었습니다. 후속 변환으로 double
버그 가 봉인되었습니다.
unsigned
산술의 오용으로 인한 버그 하나 또는 두 개가 발생 하면 여분의 비트가 얻는 것이 추가 문제가 있는지 궁금해하기 시작해야합니다. unsigned
이진 마스크와 같은 비 산술 연산에 여전히 유형을 사용하지만 산술에서 유형의 사용을 피하기 위해 가능한 한 많이 노력 하고 있습니다.
'C'스펙에는 자바가 실용적으로 떨어졌지만 개발자 요구 (클로저 등)로 서서히 되돌아 오는 몇 가지 보석이 있습니다.
이 토론과 관련이 있기 때문에 첫 번째를 언급합니다. 부호없는 정수 산술에 대한 포인터 값의 준수 그리고이 스레드 주제와 관련하여 서명 된 Java 세계에서 서명되지 않은 의미론을 유지하기가 어렵습니다.
고든 링의 디자인 팀에게 데니스 리치에게 자아를 고양시켜야한다면 Signed에게 "무한도의 제로"를 줄 것을 제안했을 것입니다. 그래서 모든 주소 오프셋 요청은 먼저 음의 값을 없애기 위해 대수적 링 크기를 추가합니다.
이렇게하면 배열에서 발생하는 오프셋은 절대 SEGFAULT를 생성 할 수 없습니다. 예를 들어, "자체 순환 루프"컨텍스트에서 서명되지 않은 동작을 필요로하는 Double의 RingArray를 호출하는 캡슐화 된 클래스에서 :
// ...
// Housekeeping state variable
long entrycount; // A sequence number
int cycle; // Number of loops cycled
int size; // Active size of the array because size<modulus during cycle 0
int modulus; // Maximal size of the array
// Ring state variables
private int head; // The 'head' of the Ring
private int tail; // The ring iterator 'cursor'
// tail may get the current cursor position
// and head gets the old tail value
// there are other semantic variations possible
// The Array state variable
double [] darray; // The array of doubles
// somewhere in constructor
public RingArray(int modulus) {
super();
this.modulus = modulus;
tail = head = cycle = 0;
darray = new double[modulus];
// ...
}
// ...
double getElementAt(int offset){
return darray[(tail+modulus+offset%modulus)%modulus];
}
// remember, the above is treating steady-state where size==modulus
// ...
위의 RingArray는 악의적 인 요청자가 시도한 경우에도 절대 인덱스에서 절대 'get'하지 않습니다. 이전 (음수) 색인 값을 요청하는 합법적 인 요청도 많이 있습니다.
NB : 외부 % 모듈러스는 합법적 인 요청을 참조 해제하지만 내부 % 모듈러스는-모듈러스보다 더 음인 네거티브로부터 뻔뻔한 악의를 가려냅니다. 이것이 Java + .. + 9 || 8 + .. + 사양이라면 문제는 '실제로'자체 회전 '할 수없는 프로그래머'가 될 것입니다.
소위 Java unsigned int 'deficiency'는 위의 한 줄짜리로 보완 될 수 있다고 확신합니다.
추신 : 위의 RingArray 하우스 키핑에 컨텍스트를 제공하기 위해 위의 'get'요소 작업과 일치하는 후보 'set'작업이 있습니다.
void addElement(long entrycount,double value){ // to be called only by the keeper of entrycount
this.entrycount= entrycount;
cycle = (int)entrycount/modulus;
if(cycle==0){ // start-up is when the ring is being populated the first time around
size = (int)entrycount; // during start-up, size is less than modulus so use modulo size arithmetic
tail = (int)entrycount%size; // during start-up
}
else {
size = modulus;
head = tail;
tail = (int)entrycount%modulus; // after start-up
}
darray[head] = value; // always overwrite old tail
}
불행한 부작용 하나를 생각할 수 있습니다. Java 임베디드 데이터베이스에서 32 비트 ID 필드로 가질 수있는 ID 수는 2 ^ 32가 아닌 2 ^ 31입니다 (~ 40 억이 아닌 ~ 20 억).
IMHO의 이유는 그들이 실수를 이행 / 수정하기에는 너무 게으 르기 때문입니다. C / C ++ 프로그래머가 부호없는, 구조, 공용체, 비트 플래그를 이해하지 못한다고 제안하는 것은 단지 터무니없는 일입니다.
Ether 당신은이 언어를 전혀 알지 못하고 la C 프로그래밍을 시작하기 직전에 기본 / bash / java 프로그래머와 대화 중이거나 자신의 마음에서 이야기하고 있습니다. ;)
파일이나 하드웨어에서 매일 형식을 다룰 때 어떤 생각을하고 있는지 궁금해지기 시작합니다.
여기서 좋은 예는 부호없는 바이트를 자체 회전 루프로 사용하는 것입니다. 마지막 문장을 이해하지 못하는 사람들을 위해 지구상에서 어떻게 자신을 프로그래머라고 부릅니다.
DC
참고 URL : https://stackoverflow.com/questions/430346/why-doesnt-java-support-unsigned-ints
'Programing' 카테고리의 다른 글
목록 사이의 간격 (0) | 2020.02.28 |
---|---|
가장 논란이 많은 프로그래밍 의견은 무엇입니까? (0) | 2020.02.28 |
Java에서 동기화되지 않습니까? (0) | 2020.02.28 |
유효성 검증 실패를 위해 REST API 서비스에서 리턴 할 적절한 HTTP 상태 코드는 무엇입니까? (0) | 2020.02.28 |
월별 만 표시하는 jQuery UI DatePicker (0) | 2020.02.28 |