NaN 복싱의 목적은 무엇입니까?


44

21 세기 C를 읽으 면서 나는 6 장 "NaN을 사용하여 예외적 인 숫자 값 표시" 섹션에 도착했습니다 . 여기에서 가수의 비트를 사용하여 임의의 비트 패턴을 저장하고이를 마커 또는 포인터로 사용하는 방법에 대해 설명합니다 (도서 언급) WebKit은이 기술을 사용합니다).

나는이 기술의 유용성을 이해하지 못했다. 나는 해킹 (NaN의 가수 가치에 신경 쓰지 않는 하드웨어에 의존하지만)은 내가 익숙하지 않은 Java 배경에서 온 것으로 보인다. C의 거칠기

다음은 NaN에서 마커를 설정하고 읽는 코드 스 니펫입니다.

#include <stdio.h>
#include <math.h> //isnan

double ref;

double set_na(){
    if (!ref) {
        ref=0/0.;
        char *cr = (char *)(&ref);
        cr[2]='a';
    }
    return ref;
}

int is_na(double in){
    if (!ref) return 0;  //set_na was never called==>no NAs yet.

    char *cc = (char *)(&in);
    char *cr = (char *)(&ref);
    for (int i=0; i< sizeof(double); i++)
        if (cc[i] != cr[i]) return 0;
    return 1;
}

int main(){
    double x = set_na();
    double y = x;
    printf("Is x=set_na() NA? %i\n", is_na(x));
    printf("Is x=set_na() NAN? %i\n", isnan(x));
    printf("Is y=x NA? %i\n", is_na(y));
    printf("Is 0/0 NA? %i\n", is_na(0/0.));
    printf("Is 8 NA? %i\n", is_na(8));
}

다음을 인쇄합니다.

Is x=set_na() NA? 1
Is x=set_na() NAN? 1
Is y=x NA? 1
Is 0/0 NA? 0
Is 8 NA? 0

과에서 JSValue.h의 웹킷 인코딩을 설명하고 있지만 사용되는없는 이유.

이 기술의 목적은 무엇입니까? 공간 / 성능의 이점이 해킹 특성의 균형을 잡을만큼 충분히 높습니까?


간단한 예를 들어 줄 수 있습니까?
BЈовић

OP가 신호 NaN을 사용할 수 있는지 묻고 있음을 분명히하기 위해
ratchet freak

1
@ratchetfreak, 어떻게 생각하세요?
Winston Ewert

@ratchetfreak : 웹 키트 JSValue.h가 설명하는 것처럼 질문은 NaN 신호에 관한 것이 아니라 새로운 것을 발견하게 해 주셔서 감사합니다!
andijcr

1
@Hudson isnan () si는 메인의 두 번째 printf에 사용됩니다. is_an ()의 목적은 이중 입력의 비트 패턴이 ref 전역 변수에 저장된 것과 동일한 지 테스트하는 것입니다.
andijcr

답변:


63

동적으로 유형이 지정된 언어를 구현할 때는 모든 객체를 담을 수있는 단일 유형이 있어야합니다. 내가 알고있는 세 가지 다른 접근법이 있습니다.

먼저 포인터를 전달할 수 있습니다. 이것이 CPython 구현이하는 일입니다. 모든 객체는 PyObject포인터입니다. 이러한 포인터는 전달되고 PyObject 구조체의 세부 정보를보고 형식을 알아 냄으로써 작업이 수행됩니다.

단점은 숫자와 같은 작은 값은 상자 값으로 저장되므로 작은 5는 어딘가에 메모리 블록으로 저장된다는 것입니다. 그래서 이것은 우리를 Lua가 사용하는 유니온 접근법으로 연결합니다. 대신 PyObject*각 값은 하나의 필드가 유형을 지정하는 구조체이며 지원되는 모든 다른 유형의 합집합입니다. 그렇게하면 작은 값에 메모리를 할당하는 대신 유니언에 직접 저장하는 것을 피할 수 있습니다.

NaN접근 방식은 모든 것을 두 배로 저장하고 사용하지 않은 부분을 NaN추가 스토리지에 재사용합니다 . 통합 방법에 비해 장점은 유형 필드를 저장한다는 것입니다. 유효한 double이면 double입니다. 그렇지 않으면 가수는 실제 객체에 대한 포인터입니다.

이것은 모든 자바 스크립트 객체입니다. 모든 변수, 객체의 모든 값, 모든 표현식. 우리가 96 비트에서 64 비트로 모든 것을 줄일 수 있다면 꽤 인상적입니다.

해킹 가치가 있습니까? 효율적인 자바 스크립트에 대한 수요가 많다는 점을 상기하십시오. Javascript는 많은 웹 응용 프로그램의 병목 현상이므로 더 빠르게 만드는 것이 우선 순위가 높습니다. 성능상의 이유로 어느 정도의 해킹을 도입하는 것이 합리적입니다. 대부분의 경우 작은 이득을 얻기 위해 복잡성을 어느 정도 도입하기 때문에 나쁜 생각입니다. 그러나이 특정한 경우에는 메모리 및 속도 향상에 가치가 있습니다.


2
실제로 CPython은 작은 숫자를 캐시합니다. hg.python.org/cpython/file/e6cc582cafce/Objects/longobject.c
Phillip Cloud

1
@cpcloud, 사실이지만 그 세부 사항은 적절하지 않은 것으로 보입니다.
Winston Ewert

1
@WinstonEwert 당신이 맞아요. 내가 쓴 것을 읽은 후에도 같은 생각을했습니다.
Phillip Cloud

2
"박싱"을 피하기 위해 기본 유형의 비트를 사용하는 것은 모든 시간이 명예로운 기술입니다. 스몰 토크는 1970 년대에 이것을 사용하여 16 비트 정수에서 1 비트를 훔쳐서 객체 포인터 또는 15 비트 신호를 보냅니다 SmallInteger.
Jonathan Eunice

2
@JonathanEunice, 정말로? 16 비트의 범위가 너무 길지 않아서 기꺼이 포기하기 때문에 놀랍습니다.
Winston Ewert

7

"예외 값"에 NaN을 사용하는 것은 추가 부울 변수가 필요하지 않도록 잘 알려져 있고 때로는 유용한 기술 this_value_is_invalid입니다. 현명하게 사용하면 성능 저하없이 코드를보다 간결하고, 깨끗하고, 단순하고, 더 읽기 쉽게 만들 수 있습니다.

이 기술에는 물론 함정이 있지만 (여기 http://ppkwok.blogspot.co.uk/2012/11/java-cafe-1-never-write-nan-nan_24.html 참조 ) Java와 같은 언어 ( 또는 매우 유사한 C #) Float.isNaNNaN 처리를 단순화하는 것과 같은 표준 라이브러리 함수가 있습니다 . 물론, 자바 당신은 선택적으로 사용할 수있는 FloatDouble클래스와 C #에서 값 형식 Null 허용 float?하고 double?, 당신에게 사용할 수있는 가능성 제공 null유효하지 않은 부동 소수점 숫자 대신 NaN의의를, 그러나 그 기술은 성능과 메모리에 상당한 부정적인 영향을 미칠 수 프로그램 사용.

C에서 NaN의 사용은 100 % 이식 가능하지는 않지만, IEEE 754 부동 소수점 표준이 사용 가능한 모든 곳에서 사용할 수 있습니다. AFAIK 이것은 오늘날 거의 모든 주류 하드웨어입니다 (또는 적어도 대부분의 컴파일러의 런타임 환경이이를 지원합니다). 예를 들어, 이 SO 게시물 에는 C에서 NaN 사용에 대한 자세한 정보를 찾기위한 몇 가지 정보가 포함되어 있습니다.


자바의 자동 복싱은 지저분하고 피해야한다. 단지 null 값을 제공하기 위해 그것을 사용하는 것은 말도
ratchet freak

웹킷이 NaN-boxing을 사용하는 위치로 연결되도록 질문을 편집했습니다. 웹킷 신호 'NaN이'보다 다른 NaN이의 폭 넓은 사용이 보인다
andijcr

2
@ratchetfreak : 물론 내 요점을 지원합니다
Doc Brown
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.