Astronomical computing - Ep 3 - Ruby의 각도

에서 우리는 천체 좌표 및 각도와 같은 여러 가지 새로운 개념을 발견했습니다.

Ruby 라이브러리를 향한 첫 번째 단계로 각도와 단위를 조작하는 것으로 시작할 것입니다.

Bundler 및 해당 명령$ bundle gem astronoby을 사용하여 만든 보석 생성 및 스켈레톤을 전달하겠습니다.

개체 유형



이 책은 우리에게 다음과 같이 알려줍니다.

To convert an angle from degrees to radians, multiply it by π/180.



Ruby에서는 다음과 같이 작성됩니다.

Math::PI / 180


Math::PI 은 표준 라이브러리에서 가져오고 Float를 반환합니다.

(Math::PI / 180).class
# => Float

Math::PI / 180
# => 0.017453292519943295


AFloat는 조작하기 쉽습니다. 또한 사용 가능한 정밀도가 0 다음의 18자리로 매우 흥미로운 것처럼 보입니다.

그러나 이것은 나에게 충분하지 않습니다. 각도는 이 전체 라이브러리에서 가장 중요하고 사용되는 데이터 중 하나가 될 것입니다. 그들은 크게 번성하고 나누어질 것입니다. 정의에 따라 aFloat는 π를 조작할 때 완전히 정확하지 않습니다.

약간의 정확성을 잃어도 괜찮은 순간이 있을 수 있지만 의도적으로가 아니라 선택에 의한 것이었으면 합니다.
또한 π를 신경 쓰지 않고 Float는 부정확성이 있으므로 정확도를 신경 쓸 때 사용해서는 안 됩니다.

0.1 + 0.2
# => 0.30000000000000004

1.1 * 0.1
# => 0.11000000000000001


따라서 BigDecimal 숫자 값, 특히 BigMath.PI 을 사용해야 합니다.

require "bigdecimal/math"

BigMath.PI(10).class
# => BigDecimal

BigMath.PI(10)
# 0.3141592653589793238462643388813853786957412e1

BigMath.PI(10) / 180
# 0.17453292519943295769236907715632521038652289e-1


퍼스트 클래스



우리는 3개의 수업으로 기본을 시작합니다:
  • Angle 모든 각도, 모든 단위
  • 의 상위 클래스가 됩니다.
  • Degree 도 단위로 초기화된 각도 조작용
  • Radian 라디안으로 초기화된 각도 조작용

  • 각도


    Angle는 몇 가지 기본 사항을 구현하지만 더 중요한 것은 각도를 다른 단위로 변환할 수 있다는 것입니다. 우리는 #to_degrees#to_radians를 다른 단위로 Angle의 새로운 인스턴스로 변환하기 위해 각도에서 사용할 수 있기를 원합니다.

    관련 사양을 작성해 보겠습니다.

    RSpec.describe Astronoby::Angle do
      describe "::as_degrees" do
        subject { described_class.as_degrees(180) }
    
        it "returns an Angle object" do
          expect(subject).to be_a(described_class)
        end
    
        it "returns an Angle in Degree" do
          expect(subject).to be_a(Astronoby::Degree)
        end
      end
    
      describe "::as_radians" do
        subject { described_class.as_radians(BigMath.PI(10)) }
    
        it "returns an Angle object" do
          expect(subject).to be_a(described_class)
        end
    
        it "returns an Angle in Radian" do
          expect(subject).to be_a(Astronoby::Radian)
        end
      end
    end
    

    Angle는 하위 클래스에서 처리할 단위 변환 계산을 관리하지 않습니다.

    실제 각도 값을 @value 속성에 저장하고 unit 매개변수를 사용하여 값의 단위를 지정합니다.

    상위Angle 클래스의 첫 번째 구현은 다음과 같습니다.

    module Astronoby
      class Angle
        UNITS = [
          DEGREES = :degrees,
          RADIANS = :radians
        ].freeze
    
        def self.as_degrees(angle)
          Astronoby::Degree.new(angle)
        end
    
        def self.as_radians(angle)
          Astronoby::Radian.new(angle)
        end
    
        def initialize(angle, unit:)
          @angle = BigDecimal(angle)
          @unit = unit
        end
    
        def value
          @angle
        end
    
        def to_degrees
          raise NotImplementedError, "#{self.class} must implement #to_degrees method."
        end
    
        def to_radians
          raise NotImplementedError, "#{self.class} must implement #to_radians method."
        end
      end
    end
    


    각도를 조작하거나 변환할 때 정밀도를 유지하기 위해 각도 값을 자동으로 BigDecimal 로 변환합니다.


    Degree 클래스는 도 단위의 각도에 대한 특정 논리를 처리하는 것을 목표로 합니다.

    지금 우리가 구현해야 하는 유일한 논리는 도에서 라디안으로 변환하는 것입니다. 여기에서 "곱하기 π/180"규칙을 작성합니다.

    먼저 이 새 클래스가 어떻게 작동해야 하는지 정의하는 테스트부터 시작하겠습니다. 우리는 #to_degrees가 각도를 그대로 유지하고 #to_radians가 적절한 클래스의 새 인스턴스를 반환하고 해당 값을 변환하는지 확인하려고 합니다.

    RSpec.describe Astronoby::Degree do
      let(:instance) { described_class.new(180) }
    
      describe "#value" do
        subject { instance.value }
    
        it "returns the angle's numeric value in the current unit" do
          expect(subject).to eq(180)
        end
      end
    
      describe "#to_degrees" do
        subject { instance.to_degrees }
    
        it "returns itself" do
          expect(subject).to eq(instance)
        end
      end
    
      describe "#to_radians" do
        subject { instance.to_radians }
    
        it "returns a new Radian instance" do
          expect(subject).to be_a(Astronoby::Radian)
        end
    
        it "converted the degrees value into radians" do
          expect(subject.value).to eq(BigMath.PI(10))
        end
      end
    end
    

    Degree 따라서 구현은 매우 간단합니다.

    module Astronoby
      class Degree < Angle
        def initialize(angle)
          super(angle, unit: DEGREES)
        end
    
        def to_degrees
          self
        end
    
        def to_radians
          self.class.as_radians(@angle / 180 * PI)
        end
      end
    end
    


    마지막으로 우리가 한동안 이야기해 온 전환입니다.

    라디안



    동일한 구조에서 Radian에는 라디안 단위의 각도를 도로 변환하는 논리가 포함됩니다.

    RSpec.describe Astronoby::Radian do
      let(:instance) { described_class.new(BigMath.PI(10)) }
    
      describe "#value" do
        subject { instance.value }
    
        it "returns the angle's numeric value in the current unit" do
          expect(subject).to eq(BigMath.PI(10))
        end
      end
    
      describe "#to_degrees" do
        subject { instance.to_degrees }
    
        it "returns a new Degree instance" do
          expect(subject).to be_a(Astronoby::Degree)
        end
    
        it "converted the degrees value into degrees" do
          expect(subject.value).to eq(180)
        end
      end
    
      describe "#to_radians" do
        subject { instance.to_radians }
    
        it "returns itself" do
          expect(subject).to eq(instance)
        end
      end
    end
    



    module Astronoby
      class Radian < Angle
        def initialize(angle)
          super(angle, unit: RADIANS)
        end
    
        def to_degrees
          self.class.as_degrees(@angle * 180 / PI)
        end
    
        def to_radians
          self
        end
      end
    end
    


    결론



    첫 번째 단계는 각도를 조작하고 각도를 라디안으로 변환할 수 있는 Astronoby라는 작동하는 보석입니다.

    다음은 gem 사용 예입니다.

    require "astronoby"
    
    Astronoby::Angle
      .as_degrees(180)
      .to_radians
      .value == BigMath.PI(10)
    
    # => true
    


    소스 코드는 현재 Github에서 사용할 수 있으며 gem은 RubyGems에서 다운로드할 수 있고 새로운 버전version이 출시되었습니다.

    다음 단계에서는 시간, 특히 캘린더와 표준 시간대에 대한 또 다른 기본 주제를 살펴보겠습니다.

    즐거운 해킹


    출처


  • Bundler gem
  • Astronoby gem on Github
  • Astronoby gem on RubyGems
  • 좋은 웹페이지 즐겨찾기