문제

Java에 부호 없는 정수에 대한 지원이 포함되지 않는 이유는 무엇입니까?

예기치 않게 큰 입력에 대해 오버플로가 발생할 가능성이 적은 코드를 작성할 수 있다는 점을 고려하면 이는 이상한 누락인 것 같습니다.

게다가 부호 없는 정수를 사용하는 것은 자체 문서화의 한 형태가 될 수 있습니다. 왜냐하면 부호 없는 정수가 보유하려고 했던 값이 결코 음수가 되어서는 안 된다는 것을 나타내기 때문입니다.

마지막으로 어떤 경우에는 부호 없는 정수가 나누기와 같은 특정 작업에 더 효율적일 수 있습니다.

이것을 포함하면 어떤 단점이 있나요?

도움이 되었습니까?

해결책

이것은 an입니다 Gosling 및 다른 사람들과의 인터뷰, 단순성에 대해 :

GOSLING : 언어 디자이너로서 저는 요즘 실제로 자신을 계산하지 않습니다. 실제로 "간단한"이라는 의미는 J. Random Developer가 그의 사양을 머리에 붙잡을 것으로 기대할 수있었습니다. 이 정의는 예를 들어 Java가 그렇지 않다고 말합니다. 실제로 이러한 많은 언어는 많은 코너 케이스로 끝나고 아무도 실제로 이해하지 못하는 것들로 끝납니다. 서명되지 않은 것에 대한 C 개발자 퀴즈를 퀴즈하고 곧 C. 부인되지 않은 산술이 무엇인지 실제로 거의 C 개발자가 이해하지 못한다는 것을 알게됩니다. 그런 것들이 C 복잡해졌습니다. Java의 언어 부분은 매우 간단하다고 생각합니다. 당신이 찾아야하는 라이브러리.

다른 팁

라인 사이를 읽고 논리가 다음과 같은 것 같아요.

  • 일반적으로 Java 디자이너는 사용 가능한 데이터 유형의 레퍼토리를 단순화하려고했습니다.
  • 일상적인 목적 상, 가장 일반적인 요구는 서명 된 데이터 유형에 대한 것이라고 생각했습니다.
  • 특정 알고리즘을 구현하기 위해서는 서명되지 않은 산술이 때때로 필요하지만, 이러한 알고리즘을 구현할 프로그래머는 서명 된 데이터 유형으로 서명되지 않은 산술을 수행하는 "작업 라운드"에 대한 지식을 가질 수 있습니다.

대부분, 나는 그것이 합리적인 결정이라고 말하고 싶습니다. 아마도 나는 다음과 같습니다.

  • 이 데이터 유형에 대해 서명되지 않았거나 적어도 서명/부호없는 대안을 다른 이름으로 제공했을 것입니다.
  • '짧은'(16 비트 서명 된 산술을 언제 마지막으로 사용 했습니까?)

그럼에도 불구하고 약간의 kludging으로, 최대 32 비트의 서명되지 않은 값에 대한 작업은 너무 나쁘지 않으며 대부분의 사람들은 서명되지 않은 64 비트 부서 또는 비교가 필요하지 않습니다.

이것은 오래된 질문이며 Pat은 Char를 간단히 언급했습니다. 나는 이것을 길 아래를 바라 볼 다른 사람들을 위해 이것을 확장해야한다고 생각했습니다. Java Primitive 유형을 자세히 살펴 보겠습니다.

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 비트 서명이 길고 많은 작업을 벡터화 할 수 있기 때문입니다. 8 비트 데이터와 서명되지 않은 바이트와 동일합니다. 벡터 화를위한 레지스터에 4 ~ 8 개의 샘플을 장착 할 수 있습니다.

서명하고 서명되지 않은 int가 표현에 혼합 되 자마자 사물이 지저분 해지기 시작하면 아마 ~ 할 것이다 정보를 잃습니다. Java가 서명 된 Ints로 제한하면 실제로 상황이 정리됩니다. 나는 서명 된 사업 전체에 대해 걱정할 필요가 없어서 기쁘지만 때로는 바이트에서 8 번째 비트를 놓치지 만 때때로.

http://skeletoncoder.blogspot.com/2006/09/java-tutorials-why-no-unsigned.html

이 사람은 C 표준이 서명되지 않은 부인 및 서명 된 INT와 관련된 작업을 정의하지 않기 때문에 서명되지 않은 것으로 간주하기 때문입니다. 이로 인해 부정적인 서명 된 정수가 서명되지 않은 큰 INT로 굴러 가면 버그가 발생할 수 있습니다.

나는 Java가 그대로 괜찮다고 생각합니다. 서명되지 않은 것을 추가하면 많은 이득없이 복잡하게됩니다. 단순화 된 정수 모델을 사용하더라도 대부분의 Java 프로그래머는 기본 숫자 유형이 어떻게 행동하는지 모릅니다. 자바 퍼즐 러 어떤 오해를 보유하고 있는지 확인하기 위해.

실용적인 조언에 관해서는 :

  • 값이 다소 임의의 크기이고 맞지 않는 경우 int, 사용 long. 그들이 맞지 않는다면 long 사용 BigInteger.

  • 공간을 절약해야 할 때 배열에만 작은 유형을 사용하십시오.

  • 정확히 64/32/16/8 비트가 필요한 경우 사용하십시오 long/int/short/byte 그리고 분할, 비교, 올바른 교대 및 캐스팅을 제외한 사인 비트에 대한 걱정을 중단하십시오.

또한보십시오 이것 "C에서 Java 로의 임의의 숫자 생성기 포팅"에 대한 답변.

와 함께 JDK8 그것은 그들에 대한 지원이 있습니다.

우리는 아직 Gosling의 우려에도 불구하고 Java에서 서명되지 않은 유형을 완전히 지원할 수 있습니다.

나는이 게시물이 너무 늙었다는 것을 알고 있습니다. 그러나 당신의 관심을 위해, Java 8 이상에서, 당신은 int 서명되지 않은 32 비트 정수를 나타내는 데이터 유형, 최소값은 0이고 최대 값은 2입니다.32-1. 사용 Integer 사용할 수업 int 서명되지 않은 정수 및 정적 메소드와 같은 데이터 유형 compareUnsigned(), divideUnsigned() 등에 추가되었습니다 Integer 서명되지 않은 정수의 산술 작업을 지원하는 클래스.

나는 그들이 Orignal Java 릴리스에 가깝게 포함되어야한다는 이야기를 들었습니다. 오크는 Java의 선구자였으며 일부 사양 문서에서는 사용 지정된 값에 대한 언급이있었습니다. 불행히도 이것들은 그것을 자바 언어로 만들지 않았습니다. 누군가가 시간 제약으로 인해 구현되지 않았다는 것을 알 수있는 한.

나는 C ++ 표준위원회의 누군가와 C ++ 과정을 밟았으며, Java는 서명되지 않은 정수를 피하기 위해 올바른 결정을 내렸다는 것을 암시했다. 사람들이 생각하는 방법 및 (2) 서명되지 않은 정수를 사용하면 생성하기 쉽지만 정수 산술 오버플로와 서명되지 않은 유형을 변환 할 때 상당한 비트를 잃는 것과 같은 문제를 디버깅하기가 어렵습니다. 서명 된 정수를 사용하여 0에서 1에서 1에서 1을 빼면 프로그램이 더 빨리 충돌하고 버그가 2^32-1로 감싸는 것보다 버그를 더 쉽게 찾을 수 있으며 컴파일러 및 정적 분석 도구 및 런타임 점검이 필요합니다. 서명되지 않은 산술을 사용하기로 선택한 이후로 무엇을하고 있는지 알고 있다고 가정하십시오. 또한 -1과 같은 음수 숫자는 종종 무시되는 필드/기본값/UnSet과 같은 유용한 것을 나타낼 수 있으며 서명되지 않은 경우 2^32-1과 같은 특별한 값을 예약해야합니다.

오래 전에, 메모리가 제한되어 있고 프로세서가 한 번에 64 비트로 자동으로 작동하지 않았을 때, 모든 비트가 훨씬 더 많이 계산되었으므로, 서명되지 않은 바이트 또는 반바지에 서명 한 후에는 실제로 훨씬 더 자주 중요했으며 분명히 올바른 설계 결정이었습니다. 오늘날 서명 된 INT를 사용하는 것은 거의 모든 정규 프로그래밍 사례에서 충분한 일이며, 프로그램이 실제로 2^31-1보다 큰 값을 사용해야한다면, 종종 오랫동안 오래 원합니다. 당신이 Longs를 사용하는 영토에 들어가면, 당신이 2^63-1의 양수 정수로 실제로 얻을 수없는 이유를 생각해 내기가 더 어렵습니다. 128 비트 프로세서로 갈 때마다 문제가되지 않습니다.

귀하의 질문은 "Java가 서명되지 않은 INT를 지원하지 않는 이유"입니다.

그리고 당신의 질문에 대한 나의 대답은 Java는 모든 것이 원시적 인 유형을 원한다는 것입니다. 바이트, , 짧은, int 그리고 처리해야합니다 바이트, 단어, dword 그리고 Qword 각각 어셈블리에서와 마찬가지로 Java 운영자는 서명 모든 것을 제외한 모든 원시 유형에 대한 작업 , 그러나 만 그들은 서명되지 않은 16 비트입니다.

따라서 정적 방법은 서명되지 않았습니다 운영 또한 32와 64 비트 모두.

정적 메소드를 호출 할 수있는 최종 클래스가 필요합니다. 서명되지 않았습니다 운영.

이 최종 클래스를 만들고 원하는 이름을 부르고 정적 메소드를 구현할 수 있습니다.

정적 메소드를 구현하는 방법에 대해 전혀 모르면 링크 당신을 도울 수 있습니다.

제 생각에는 Java는입니다 ~ 아니다 C ++와 유사합니다 조금도, 그 경우 어느 것도 아니다 서명되지 않은 유형을 지원합니다 ...도 아니다 운영자 과부하이므로 Java는 C ++와 C에서 완전히 다른 언어로 취급되어야한다고 생각합니다.

그건 그렇고 언어 이름에서도 완전히 다릅니다.

따라서 Java에서 C와 유사한 코드를 입력하는 것이 좋습니다. C ++와 유사한 코드를 전혀 입력하는 것이 좋습니다. Java에서는 C ++에서 다음에하고 싶은 일을 할 수 없기 때문입니다. 즉, 코드는 계속 C ++처럼 계속되지 않을 것이며, 이것은 나에게 코드가 중간의 스타일을 변경하는 것이 좋지 않습니다.

서명 된 작업을 위해 정적 메소드를 작성하고 사용하는 것이 좋습니다. 따라서 코드에서 서명 된 작업 만 필요하지 않은 한 서명 된 작업 및 서명되지 않은 작업에 대한 코드 혼합 및 정적 메소드에는 표시되지 않습니다. 연산자 만 사용하십시오.

또한 사용하지 않는 것이 좋습니다 짧은, int 그리고 원시 유형 및 사용 단어, dword 그리고 Qword 대신 각각, 당신은 운영자를 사용하는 대신 서명되지 않은 운영 및/또는 서명 된 작업에 대한 정적 메소드를 호출하는 것에 관한 것입니다.

서명 된 작업 만 수행하고 코드에서만 연산자를 사용하려는 경우 이러한 원시 유형을 사용해도 괜찮습니다. 짧은, int 그리고 .

실제로 단어, dword 그리고 Qword 하다그렇습니다 언어로 존재하지만 각각에 대한 새로운 클래스를 만들 수 있으며 각각의 구현은 매우 쉬워야합니다.

클래스 단어 원시 유형을 보유합니다 짧은 만, 수업 dword 원시 유형을 보유합니다 int 만과 수업 Qword 원시 유형을 보유합니다 뿐. 이제 서명되지 않은 모든 및 서명 된 메소드는 정적이거나 정적이지 않은 경우 각 클래스에서 구현할 수 있습니다. 즉, 16 개의 비트 작업은 모두 서명하지 않고 서명하여 단어 클래스, 모든 32 비트 작업은 서명되지 않고 서명 된 모든 dword 클래스 및 64 비트 작업은 모두에 대한 의미 이름을 제공하여 서명하지 않고 서명했습니다. Qword 수업.

각 방법에 대해 너무 많은 이름을 부여하는 것을 좋아하지 않는다면 언제든지 Java에서 과부하를 사용할 수 있습니다. Java를 읽는 것이 좋습니다.그렇습니다 그것도 제거하십시오!

8 비트 서명 작업 및 운영자가없는 8 비트 서명되지 않은 작업에 대한 방법을 사용하는 방법을 원한다면 바이트 클래스 (첫 번째 문자 'B'는 자본이므로 원시 유형이 아닙니다. 바이트) 그리고이 클래스에서 방법을 구현하십시오.

가치를 통과하고 참조로 통과하는 것에 대해 :

C#에서와 같이 잘못되지 않은 경우 원시 객체는 자연스럽게 값으로 전달되지만 클래스 객체는 자연스럽게 참조별로 전달되므로 유형의 객체가 나타납니다. 바이트, 단어, dword 그리고 Qword 기본적으로 값이 아닌 참조별로 전달됩니다. 나는 Java가 있었으면 좋겠다 구조 C#과 같은 개체는 모두 있습니다 바이트, 단어, dword 그리고 Qword 구현 될 수 있습니다 구조 대신에 수업, 기본적으로 기본 유형과 같은 C#의 구조체 객체와 같이 기본적으로 참조적으로 값으로 전달되었습니다. 기본적으로 기본적으로 참조가 아니라 값으로 전달됩니다. 이를 다루기 위해서는 기본적으로 값이 아닌 참조별로 전달되는 클래스와 인터페이스 만 있습니다. 그러니 당신이 통과하고 싶다면 바이트, 단어, dword 그리고 Qword Java 및 C#의 다른 클래스 객체와 마찬가지로 참조가 아닌 값별로 객체를 참조하십시오. 단순히 사본 생성자를 사용해야합니다.

그것이 제가 생각할 수있는 유일한 해결책입니다. 원시 유형을 Word, Dword 및 Qword에 타이핑 할 수 있기를 바랍니다. 그러나 Java는 지원하는 C#과 달리 Typedef를 지원하거나 전혀 사용하지 않습니다. 사용, C의 typedef와 동일합니다.

출력 정보 :

똑같이 비트 시퀀스, 여러 가지 방법으로 다음과 같이 인쇄 할 수 있습니다 : 이진, 소수점으로 (C printf에서 %u의 의미와 같은), 8 대 (c printf에서 %o의 의미와 같은), 16 진수 ( %x의 의미 : %x의 의미 : C printf) 및 정수 (c printf의 %d의 의미와 같은).

C printf는 함수의 매개 변수로 전달되는 변수의 유형을 알지 못하므로 printf는 함수의 첫 번째 매개 변수로 전달 된 char* 객체에서만 각 변수의 유형을 알고 있습니다.

따라서 각 수업에서 : 바이트, 단어, dword 그리고 Qword, 당신은 인쇄 방법을 구현하고 printf의 기능을 얻을 수 있습니다. 클래스의 원시 유형이 서명 되더라도 논리적 및 변속 작업과 관련된 일부 알고리즘을 따르면 숫자를 출력으로 인쇄 할 수 있도록 서명되지 않은 상태로 인쇄 할 수 있습니다.

불행히도 제가 제공 한 링크는 이러한 인쇄 방법을 구현하는 방법을 보여주지 않지만 이러한 인쇄 방법을 구현하는 데 필요한 알고리즘에 대해 Google을 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입니다.절대값을 취하고 곱한 후 delta 각도 나는 사이의 각도를 얻을 것입니다 n레이와 중간 것.

불행하게도 위의 표현식에는 unsigned라는 표현이 포함되어 있으며 -1로 평가하는 대신 2^32-1로 평가되었습니다.후속 변환은 double 버그를 봉인했습니다.

오용으로 인해 버그가 발생한 후 unsigned 산술적인 사람은 자신이 얻는 추가 비트가 추가 문제를 겪을 만한 가치가 있는지 궁금해하기 시작해야 합니다.가능한 한 어떤 사용도 하지 않으려고 노력하고 있습니다. unsigned 산술 유형이지만 이진 마스크와 같은 비산술 연산에는 여전히 사용됩니다.

'C'사양에는 Java가 실용적인 이유로 떨어졌지만 개발자 수요 (폐쇄 등)로 천천히 다시 등장하는 보석이 몇 개 있습니다.

나는이 토론과 관련이 있기 때문에 첫 번째를 언급합니다. 서명되지 않은 정수 산술에 대한 포인터 값의 준수. 그리고이 스레드 주제와 관련하여 서명 된 Java 세계에서 서명되지 않은 의미를 유지하기가 어렵습니다.

Dennis Ritchie Alter Ego가 Gosling의 디자인 팀을 조언하기 위해 Dennis Ritchie Alter Ego를 얻는다면 Signed가 "Zero At Infinity"라고 제안했을 것입니다. 따라서 모든 주소 오프셋 요청이 먼저 대수 링 크기를 추가하여 음수 값을 제거 할 것입니다.

그렇게하면 배열에 던져진 오프셋은 결코 segfault를 생성 할 수 없습니다. 예를 들어 서명되지 않은 동작이 필요한 복식의 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는 악의적 인 요청자가 시도하더라도 부정적인 색인에서 결코 얻지 못할 것입니다. 사전 (부정적인) 색인 값을 요구하는 합법적 인 요청도 많이 있습니다.

NB : 외부 %모듈러스는 합법적 인 요청을받는 반면, 내부 %모듈러스는 -모다 루스보다 부정적인 악의를 가려냅니다. 이것이 자바에 나타나면 +.. +9 || 8+ ..+ 사양이면 문제는 진정으로 '자기 회전 할 수없는'프로그래머가 될 것입니다.

나는 소위 Java Unsigned int '결핍'을 위의 1 라이너와 함께 만들 수 있다고 확신합니다.

추신 : 위의 RingArray 하우스 키핑에 대한 컨텍스트를 제공하려면 위의 'Get'요소 작업과 일치하는 후보 '세트'작업이 있습니다.

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 (~ 2billion, ~ 4billion)가 아닌 2^31입니다.

IMHO가 그 실수를 구현/수정하기에는 너무 게으르기 때문입니다. C/C ++ 프로그래머는 서명되지 않은, 구조, 노조, 비트 플래그를 이해하지 못한다고 제안하는 것이 터무니없는 일입니다.

에테르 당신은 LA C를 프로그래밍하기 직전에 기본/bash/Java 프로그래머와 이야기하고있었습니다. ;)

파일이나 하드웨어에서 매일 형식을 다룰 때 질문하기 시작합니다.

여기서 좋은 예는 서명되지 않은 바이트를 자체 회전 루프로 사용하려고하는 것입니다. 마지막 문장을 이해하지 못하는 사람들에게는 지구상에서 어떻게 자신을 프로그래머라고 부릅니다.

DC

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top