Skip to content

Commit

Permalink
Drop BigDecimal (#46)
Browse files Browse the repository at this point in the history
`BigDecimal` was introduced early in the project from my belief that high accuracy was needed.

It turns out that the number of digits in floats are enough to keep a precision up to 0.0001 arcseconds in most calculations.

Using `BigDecimal` has a cost over the overall performance of the library. If it is not absolutely necessary for the calculations, it's better not to use it. Calculations are performed 11 times faster using only floats, for the same precision (see benchmark below).

### Benchmark

The benchmark simply executes usual calculations enabled by the library at the moment, many times.

```rb
Benchmark.bmbm do |x|
  x.report do
    10_000.times do
      time = Time.utc(2023, 2, 17, 11, 0, 0)
      epoch = Astronoby::Epoch.from_time(time)

      observer = Astronoby::Observer.new(
        latitude: Astronoby::Angle.from_degrees(38),
        longitude: Astronoby::Angle.from_degrees(-78)
      )

      sun = Astronoby::Sun.new(epoch: epoch)

      sun
        .apparent_ecliptic_coordinates
        .to_apparent_equatorial(epoch: epoch)
        .to_horizontal(
          time: time,
          latitude: observer.latitude,
          longitude: observer.longitude
        )

      sun.rising_time(observer: observer)
      sun.rising_azimuth(observer: observer).str(:dms)
      sun.setting_time(observer: observer)
      sun.setting_azimuth(observer: observer).str(:dms)

      year = 2024
      Astronoby::EquinoxSolstice.march_equinox(year)
      Astronoby::EquinoxSolstice.june_solstice(year)
    end
  end
end
```

```
                         user    system      total         real
with BigDecimal     61.342663  0.351669  61.694332  (61.892873)
without BigDecimal   5.286487  0.004743   5.291230   (5.308093)
```
  • Loading branch information
rhannequin authored Apr 4, 2024
1 parent fdb16bc commit e3d862f
Show file tree
Hide file tree
Showing 15 changed files with 89 additions and 115 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ major one is released.

```rb
angle1 = Astronoby::Angle.from_degrees(90)
angle2 = Astronoby::Angle.from_radians(Astronoby::Angle::PI / 2)
angle2 = Astronoby::Angle.from_radians(Math::PI / 2)
angle3 = Astronoby::Angle.from_hours(12)

angle1 == angle2
Expand Down Expand Up @@ -83,8 +83,8 @@ horizontal_coordinates = sun.horizontal_coordinates(
longitude: longitude
)

horizontal_coordinates.altitude.degrees.to_f
# => 27.50008242057459
horizontal_coordinates.altitude.degrees
# => 27.500082420575094

horizontal_coordinates.altitude.str(:dms)
# => "+27° 30′ 0.2967″"
Expand Down
31 changes: 12 additions & 19 deletions lib/astronoby/angle.rb
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
# frozen_string_literal: true

require "bigdecimal/math"

module Astronoby
class Angle
include Comparable

PRECISION = 14
PI = BigMath.PI(PRECISION)
PI_IN_DEGREES = BigDecimal("180")
MIN_PRECISION = 10
PI_IN_DEGREES = 180.0

FULL_CIRCLE_IN_RADIANS = (2 * PI)
FULL_CIRCLE_IN_RADIANS = (2 * Math::PI)

RADIAN_PER_HOUR = PI / BigDecimal("12")
MINUTES_PER_DEGREE = BigDecimal("60")
MINUTES_PER_HOUR = BigDecimal("60")
SECONDS_PER_MINUTE = BigDecimal("60")
RADIAN_PER_HOUR = Math::PI / 12.0
MINUTES_PER_DEGREE = 60.0
MINUTES_PER_HOUR = 60.0
SECONDS_PER_MINUTE = 60.0
SECONDS_PER_HOUR = MINUTES_PER_HOUR * SECONDS_PER_MINUTE

FORMATS = %i[dms hms].freeze
Expand All @@ -31,7 +28,7 @@ def from_radians(radians)
end

def from_degrees(degrees)
radians = degrees / PI_IN_DEGREES * PI
radians = degrees / PI_IN_DEGREES * Math::PI
from_radians(radians)
end

Expand Down Expand Up @@ -70,16 +67,12 @@ def atan(ratio)
attr_reader :radians

def initialize(radians)
@radians = if radians.is_a?(Integer) || radians.is_a?(BigDecimal)
BigDecimal(radians)
else
BigDecimal(radians, PRECISION)
end
@radians = radians
freeze
end

def degrees
@radians * PI_IN_DEGREES / PI
@radians * PI_IN_DEGREES / Math::PI
end

def hours
Expand Down Expand Up @@ -153,7 +146,7 @@ def to_dms(deg)
absolute_decimal_minutes - absolute_decimal_minutes.floor
)

Dms.new(sign, degrees, minutes, seconds.to_f.floor(4))
Dms.new(sign, degrees, minutes, seconds.floor(4))
end

def to_hms(hrs)
Expand All @@ -168,7 +161,7 @@ def to_hms(hrs)
absolute_decimal_minutes - absolute_decimal_minutes.floor
)

Hms.new(hours, minutes, seconds.to_f.floor(4))
Hms.new(hours, minutes, seconds.floor(4))
end
end
end
2 changes: 1 addition & 1 deletion lib/astronoby/bodies/sun.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Astronoby
class Sun
SEMI_MAJOR_AXIS_IN_METERS = 149_598_500_000
ANGULAR_DIAMETER = Angle.from_degrees(0.533128)
INTERPOLATION_FACTOR = BigDecimal("24.07")
INTERPOLATION_FACTOR = 24.07

# Source:
# Title: Practical Astronomy with your Calculator or Spreadsheet
Expand Down
2 changes: 1 addition & 1 deletion lib/astronoby/coordinates/equatorial.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def to_horizontal(time:, latitude:, longitude:)
azimuth = Angle.acos(t2)

if ha.sin.positive?
azimuth = Angle.from_degrees(BigDecimal("360") - azimuth.degrees)
azimuth = Angle.from_degrees(360 - azimuth.degrees)
end

Horizontal.new(
Expand Down
2 changes: 1 addition & 1 deletion lib/astronoby/coordinates/horizontal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def to_equatorial(time:)

if @azimuth.sin.positive?
hour_angle_degrees = Angle
.from_degrees(BigDecimal("360") - hour_angle_degrees)
.from_degrees(360 - hour_angle_degrees)
.degrees
end

Expand Down
4 changes: 2 additions & 2 deletions lib/astronoby/geocentric_parallax.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ class GeocentricParallax
# Chapter: 39 - Calculating correction for parallax

ASTRONOMICAL_UNIT_IN_METERS = 149_597_870_700
EARTH_FLATTENING_CORRECTION = BigDecimal("0.996647")
EARTH_EQUATORIAL_RADIUS = BigDecimal("6378140")
EARTH_FLATTENING_CORRECTION = 0.996647
EARTH_EQUATORIAL_RADIUS = 6378140.0

# Equatorial horizontal parallax
# @param distance [Numeric] Distance of the body from the center of the
Expand Down
14 changes: 7 additions & 7 deletions lib/astronoby/observer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
module Astronoby
class Observer
DEFAULT_ELEVATION = 0
DEFAULT_TEMPERATURE = BigDecimal("283.15")
PRESSURE_AT_SEA_LEVEL = BigDecimal("1013.25")
PASCAL_PER_MILLIBAR = BigDecimal("0.01")
EARTH_GRAVITATIONAL_ACCELERATION = BigDecimal("9.80665")
MOLAR_MASS_OF_AIR = BigDecimal("0.0289644")
UNIVERSAL_GAS_CONSTANT = BigDecimal("8.31432")
DEFAULT_TEMPERATURE = 283.15
PRESSURE_AT_SEA_LEVEL = 1013.25
PASCAL_PER_MILLIBAR = 0.01
EARTH_GRAVITATIONAL_ACCELERATION = 9.80665
MOLAR_MASS_OF_AIR = 0.0289644
UNIVERSAL_GAS_CONSTANT = 8.31432

attr_reader :latitude, :longitude, :elevation, :temperature

Expand Down Expand Up @@ -37,7 +37,7 @@ def initialize(
# Compute an estimation of the atmospheric pressure based on the elevation
# and temperature
#
# @return [BigDecimal] the atmospheric pressure in millibars.
# @return [Float] the atmospheric pressure in millibars.
def pressure
@pressure ||= PRESSURE_AT_SEA_LEVEL * pressure_ratio
end
Expand Down
10 changes: 5 additions & 5 deletions lib/astronoby/time/greenwich_sidereal_time.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
module Astronoby
class GreenwichSiderealTime
JULIAN_CENTURIES_EXPONENTS = [
BigDecimal("6.697374558"),
BigDecimal("2400.051336"),
BigDecimal("0.000025862")
6.697374558,
2400.051336,
0.000025862
].freeze

attr_reader :date, :time
Expand All @@ -29,7 +29,7 @@ def self.from_utc(utc)
utc.min / 60.0 +
(utc.sec + utc.subsec) / 3600.0

gmst = BigDecimal("1.002737909") * ut_in_hours + t0
gmst = 1.002737909 * ut_in_hours + t0
gmst += 24 if gmst.negative?
gmst -= 24 if gmst > 24

Expand Down Expand Up @@ -61,7 +61,7 @@ def to_utc
a += 24 if a.negative?
a -= 24 if a > 24

utc = BigDecimal("0.9972695663") * a
utc = 0.9972695663 * a

decimal_hour_to_time(date, utc)
end
Expand Down
2 changes: 0 additions & 2 deletions lib/astronoby/util/trigonometry.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# frozen_string_literal: true

require "bigdecimal/math"

module Astronoby
module Util
module Trigonometry
Expand Down
Loading

0 comments on commit e3d862f

Please sign in to comment.