Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

Ruby에서 숫자가 작동하는 방식:정수, 부동 소수점 및 Bigdecimal 이해

Ruby 2.4 병합 Fixnum &Bignum 동일한 클래스로 (Integer ) 그래서 지금이 Ruby의 다양한 숫자 유형을 검토하기에 좋은 시간이라고 생각합니다!

이것이 우리가 이 게시물에서 이야기할 내용입니다 🙂

숫자 유형 개요

Ruby에서 모든 숫자 관련 클래스의 클래스 계층 구조를 살펴보는 것으로 시작하겠습니다.

숫자 정수 Fixnum Bignum Float Complex Rational BigDecimal(표준 라이브러리)

보시다시피 Numeric class는 모든 number 클래스의 부모입니다. ancestors를 사용할 수 있음을 기억하십시오. 모든 클래스의 상위 클래스를 검색하는 메서드입니다.

:

Fixnum.ancestors - Fixnum.included_modules[Fixnum, Integer, Numeric, Object, BasicObject]

이제 이러한 클래스를 테이블 형식으로 살펴보겠습니다.

클래스 설명
정수 Fixnum의 상위 클래스 &Bignum 1
수정 번호 OS 정수 유형(32 또는 64비트)에 맞는 정수 1
빅넘 더 큰 숫자에 사용 111111111111
플로트 정확하지 않은 십진수 5.0
복잡함 허수와 수학 문제에 사용 (1+0i)
합리적 분수를 나타내는 데 사용 (2/3)
BigDecimal 완벽한 정밀도 십진수 3.0

부동 정밀도

Float Ruby의 클래스는 공식 Ruby 문서에서 "정확하지 않음"으로 설명되어 있습니다.

그 이유는 무엇입니까?

예를 보여드리겠습니다 :

0.2 + 0.1 ==0.3# 거짓

이것이 왜 거짓입니까?

0.2 + 0.1의 결과를 봅시다. :

0.30000000000000004

정확히! 이것이 바로 우리가 부정확성을 의미하는 것입니다.

이것은 float가 저장되는 방식 때문에 발생합니다. 항상 정확한 십진수가 필요한 경우 BigDecimal을 사용할 수 있습니다. 수업.

Float 대 BigDecimal

BigDecimal은 임의의 정밀도 십진수를 제공하는 클래스입니다.

:

'bigdecimal'BigDecimal("0.2") + BigDecimal("0.1") ==0.3# true 필요

항상 BigDecimal을 사용하지 않는 이유 그 다음에? 훨씬 느리기 때문입니다!

다음은 벤치마크입니다. :

계산하기 ---------------------------------- bigdecimal 21.559k i/100ms float 79.336k i/ 100ms-------------------------------------------------- bigdecimal 311.721k(± 7.4%) i/s - 1.552M float 3.817M(±11.7%) i/s - 18.803M비교:float:3817207.2 i/s bigdecimal:311721.2 i/s -x 더 느림 

BigDecimal Float보다 12배 느립니다. , 그리고 이것이 기본값이 아닌 이유입니다 🙂

픽스넘 대 빅넘

이 섹션에서는 Fixnum 간의 차이점을 살펴보고자 합니다. 및 Bignum 루비 2.4 이전.

몇 가지 코드부터 시작하겠습니다. :

1.class# Fixnum100000000000.class# 빅넘

Ruby는 올바른 클래스를 생성하고 자동으로 Fixnum을 승격합니다. Bignum으로 필요할 때.

<블록 인용>

참고 :Bignum을 얻으려면 더 큰 숫자가 필요할 수 있습니다. 64비트 Ruby 인터프리터가 있는 경우 개체.

왜 다른 수업이 필요한가요? 대답은 더 큰 숫자로 작업하려면 다른 구현이 필요하고 큰 숫자로 작업하는 것이 더 느리기 때문에 Float와 비슷한 상황이 발생한다는 것입니다. 대 BigDecimal .

픽스넘의 특수 속성

Fixnum 클래스에도 몇 가지 특별한 속성이 있습니다. 예를 들어 개체 ID는 공식을 사용하여 계산됩니다.

1.object_id# 320.object_id# 41

공식은 다음과 같습니다. (number * 2) + 1 .

그러나 Fixnum을 사용할 때 이것에 더 많은 것이 있습니다. 생성되는 객체가 전혀 없습니다. Fixnum에 저장할 데이터가 없습니다. , 값이 개체 ID 자체에서 파생되기 때문입니다.

이것은 구현 세부 사항일 뿐이지만 알고 보면 재미있을 것 같아요 🙂

MRI(Matz의 Ruby Interpreter)는 다음 두 매크로를 사용하여 값과 객체 ID 사이를 변환합니다.

INT2FIX(i) ((VALUE)(((SIGNED_VALUE)(i))<<1 | FIXNUM_FLAG))FIX2LONG(x) ((long)RSHIFT((SIGNED_VALUE)(x),1))

여기서 일어나는 일은 모든 비트를 왼쪽이나 오른쪽으로 이동하는 "비트 시프팅"이라고 합니다.

한 위치를 왼쪽으로 이동하는 것은 2를 곱하는 것과 동일하므로 공식이 (number * 2) + 1입니다. . +1은 FIXNUM_FLAG에서 옵니다. .

대조적으로, Bignum 일반 클래스처럼 작동하고 일반 개체 ID를 사용합니다.

111111111111111.object_id# 23885808

이 모든 의미는 Fixnum 객체는 인터프리터 수준에서 작동하는 방식 면에서 기호에 더 가깝지만 Bignum 개체가 문자열에 더 가깝습니다.

2.4의 정수

Ruby 2.4부터 Fixnum 및 Bignum은 더 이상 사용되지 않지만 그 뒤에서는 여전히 동일한 방식으로 작동합니다.

Ruby는 자동으로 한 유형에서 다른 유형으로 전환합니다.

클래스 변경 없이 .

이는 작은 Integer 숫자는 여전히 Fixnum과 같은 방식으로 작동합니다. .

요약

이 게시물에서는 Ruby에 존재하는 다양한 숫자 관련 클래스에 대해 배웠습니다.

float가 부정확하고 BigDecimal을 사용할 수 있다는 것을 배웠습니다. 정확도가 성능보다 훨씬 더 중요하다면. 또한 Fixnum 객체는 인터프리터 수준에서 특별하지만 Bignum s는 그냥 일반 개체입니다.

이 게시물이 흥미롭다면 아래 양식에서 제 뉴스레터에 가입하는 것을 잊지 마세요 🙂