Google 프로토콜 버퍼에서 SINT32 대신 Int32를 사용하기에 좋은 시간이 있습니까?

StackOverflow https://stackoverflow.com/questions/765916

  •  12-09-2019
  •  | 
  •  

문제

나는 읽고 있었다 Google 프로토콜 버퍼 최근에는 다양한 스칼라 값 유형을 메시지에 사용할 수 있습니다.

에 따르면 그들의 문서, 가변 길이 정수 프리미티브에는 세 가지 유형이 있습니다. int32, uint32, 그리고 sint32. 그들의 문서에서 그들은 그것을 주목합니다 int32 "음수 인코딩에 비효율적입니다 - 필드가 음수 값을 가질 가능성이있는 경우 사용하십시오. sint32 대신. "그러나 네 마이너스가없는 필드가 있다면 UINT32가 사용하기에 더 나은 유형이라고 가정합니다. int32 어쨌든 (음수 처리에 대한 추가 비트 및 CPU 비용이 감소하기 때문에).

그래서 언제 int32 사용하기에 좋은 스칼라입니까? 문서가 마이너스 숫자를 거의 얻지 못할 때만 가장 효율적이라는 것을 암시 하는가? 아니면 항상 사용하는 것이 바람직합니까? sint32 그리고 uint32, 필드의 내용에 따라?

(이 스칼라의 64 비트 버전에도 동일한 질문이 적용됩니다. int64, uint64, 그리고 sint64; 그러나 나는 가독성을 위해 문제 설명에서 그들을 남겼습니다.)

도움이 되었습니까?

해결책

Google 프로토콜 버퍼에 익숙하지는 않지만 문서에 대한 저의 해석은 다음과 같습니다.

  • 사용 uint32 값이 음수가 될 수없는 경우
  • 사용 sint32 값이 그렇지 않은 것처럼 부정적 일 가능성이 거의 없다면 ( "가능성이있는"퍼지 정의의 경우)
  • 사용 int32 값이 음수 일 수 있지만 값이 긍정적 인 것보다 훨씬 적습니다 (예 : 응용 프로그램이 -1을 사용하여 오류 또는 '알 수없는'값을 나타내는 경우 비교적 드문 상황입니다).

다음은 인코딩에 대해 문서가 말하는 내용입니다 (http://code.google.com/apis/protocolbuffers/docs/encoding.html#types):

서명 된 INT 유형 사이에는 중요한 차이가 있습니다 (sint32 그리고 sint64) 및 "표준"int 유형 (int32 그리고 int64) 음수를 인코딩 할 때. 사용하는 경우 int32 또는 int64 음수의 유형으로 결과 varint 항상 10 바이트 길이입니다. 효과적으로 매우 큰 서명되지 않은 정수처럼 취급됩니다. 서명 된 유형 중 하나를 사용하는 경우 결과 varint 지그재그 인코딩을 사용하여 훨씬 더 효율적입니다.

지그재그 인코딩 맵에 서명 된 정수에 서명되지 않은 정수에 서명하여 작은 절대 값을 가진 숫자 (예 : -1) varint 인코딩 된 값도. 이것은 양수와 음의 정수를 통해 "zig -zags"를 앞뒤로 앞뒤로하는 방식으로, -1은 1로 인코딩되도록, 1, 1은 2로 인코딩되고 -2는 3으로 인코딩되며 ...

따라서 음수를 사용하는 경우에는 드물게 보입니다. 프로토콜에 전달하는 숫자의 크기가 더 작은쪽에있는 한, 당신은 사용하는 것이 더 나을 수 있습니다. sint32. 확실하지 않은 경우 프로파일 링이 순서대로 진행됩니다.

다른 팁

sint* 대신 int*를 사용해야 할 좋은 이유는 거의 없습니다. 이러한 추가 유형의 존재는 역사적, 역 호환성 이유에 가장 가능성이 높으며, 프로토콜 버퍼는 자체 프로토콜 버전에서도 유지하려고합니다.

가장 좋은 추측은 가장 초기 버전에서 2의 보완 표현에서 음수 정수를 인코딩했으며, 이는 9 바이트의 최대 크기의 Varint 인코딩 (추가 유형 바이트를 계산하지 않음)이 필요합니다. 그런 다음 그들은 이미 사용한 오래된 코드와 직렬화를 깨지 않도록 인코딩에 붙어있었습니다. 따라서 기존 코드를 깨지 않고 음수에 대한 다양한 크기의 인코딩을 얻기 위해 새 인코딩 유형 인 SINT*를 추가해야했습니다. 디자이너들이 어떻게이 문제를 깨닫지 못한 방법은 완전히 저를 넘어서고 있습니다.

Varint 인코딩 (유형 사양없이 1 바이트가 필요)은 다음 바이트 수에서 서명되지 않은 정수 값을 인코딩 할 수 있습니다.

0, 2^7) : 1 바이트

2^7, 2^14) : 2 바이트

2^14, 2^21) : 3 바이트

2^21, 2^28) : 4 바이트

2^28, 2^35) : 5 바이트

2^35, 2^42) : 6 바이트

2^42, 2^49) : 7 바이트

2^49, 2^56) : 8 바이트

2^56, 2^64) : 9 바이트

작은 크기의 음수 정수를 소형으로 인코딩하려면 부호를 나타내려면 약간의 "사용"해야합니다. 명시 적 부호 비트 (일부 예약 된 위치) 및 크기 표현을 통해이를 수행 할 수 있습니다. 또는 Zig Zag 인코딩을 수행 할 수 있습니다. 왼쪽 크기를 1 비트로 이동하고 음수에 대해 1을 빼면 효과적으로 동일한 작업을 수행 할 수 있습니다 (따라서 가장 중요한 비트는 부호를 나타냅니다. Evens는 음성이 없음).

어느 쪽이든, 포인트를 차단합니다 긍정적인 정수는 이제 더 많은 공간이 필요합니다.

0, 2^6) : 1 바이트

2^6, 2^13) : 2 바이트

2^13, 2^20) : 3 바이트

2^20, 2^27) : 4 바이트

2^27, 2^34) : 5 바이트

2^34, 2^41) : 6 바이트

2^41, 2^48) : 7 바이트

2^48, 2^55) : 8 바이트

2^55, 2^63) : 9 바이트

sint*를 통해 int*를 사용하려면 음수 숫자가 극히 드물지만 가능해야합니다. int* (예 : 2^6 vs. 2^7이 2X 인코딩 크기로 이어지는)와 달리 sint*의 더 큰 인코딩에.

기본적으로 일부는 음수 일 수있는 숫자를 가질 것이라면 기본적으로 int* 대신 sint*를 사용합니다. int*는 거의 우월하지 않으며 일반적으로 가치가 있는지 여부를 판단하는 데 전념해야 할 여분의 생각조차 할 가치가 없습니다.

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