Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arithmetic methods support for Angle #16

Merged
merged 6 commits into from
Feb 23, 2024

Conversation

rhannequin
Copy link
Owner

@rhannequin rhannequin commented Feb 20, 2024

This introduces several arithmetic functions in Angle to increase readability and developer experience.

Instance methods

  • Angle#+: adds two angles' values and returns an angle
  • Angle#-: subtracts two angles' values and returns an angle
  • Angle#sin: returns the numeric value (ratio) of the sine of the angle
  • Angle#cos: returns the numeric value (ratio) of the cosine of the angle
  • Angle#tan: returns the numeric value (ratio) of the tangent of the angle

###Class methods

  • Angle::asin: returns a new angle from the radians of a inverse sine ratio
  • Angle::acos: returns a new angle from the radians of a inverse cosine ratio
  • Angle::atan: returns a new angle from the radians of a inverse tangent ratio

Examples

angle_1 = Astronoby::Angle.as_radians(described_class::PI)
angle_2 = Astronoby::Angle.as_degrees(45)
new_angle = angle_1 + angle_2
new_angle.degrees
# => 225

Astronoby::Angle.as_radians(Math::PI / 6).sin
# => ~ 0.5

angle = Astronoby::Angle.atan(1)
angle.radians
# => ~ π÷4

@rhannequin rhannequin self-assigned this Feb 20, 2024
lib/astronoby/angle.rb Outdated Show resolved Hide resolved
lib/astronoby/angle.rb Outdated Show resolved Hide resolved
@rhannequin
Copy link
Owner Author

@JoelQ

def +(other)
  self.class.as_radians(radians + other.radians)
end

This implementation doesn't allow for arithmetic operations with regular numbers:

Astronoby::Angle.as_degrees(180) + 60
# `+': undefined method `radians' for 60:Integer (NoMethodError)

I need to do the following:

angle = Astronoby::Angle.as_degrees(180)
Astronoby::Angle.as_degrees(angle.degrees + 60)

Do you think it would be worth it to allow somehow this?

angle = Astronoby::Angle.as_degrees(180)
new_angle = angle + 60
new_angle.degrees # => 240

This would be very convenient to write, but also very error prone. I don't even know how to do it because angles are stored in radians and the #+ method would have no clue what the numeric value's unit would be.

This reminds me of your suggestion to implement #cos, but this means I have to be cautious because #cos would return a number (implicitly in radians) instead of an Angle.

Do you have an opinion?

@rhannequin rhannequin force-pushed the add-arithmetic-methods-to-angle branch from 1e136b5 to 4cd6f65 Compare February 20, 2024 22:15
@rhannequin rhannequin changed the title Add Angle#+ Arithmetic methods support for Angle Feb 20, 2024
@JoelQ
Copy link

JoelQ commented Feb 21, 2024

This implementation doesn't allow for arithmetic operations with regular numbers
[...]
This would be very convenient to write, but also very error prone. I don't even know how to do it because angles are stored in radians and the #+ method would have no clue what the numeric value's unit would be.

Agreed! IMO you shouldn't do arithmetic operations with raw numbers. Raw numbers are ambiguous and lead to bugs. Consider:

angle = Angle.as_degrees(180)
angle + 60

What does 60 represent? Is it an angle in degrees? An angle in radians? Some other quantity altogether such as distance in meters? A dimensionless number?

It's safer and easier to read if you do write this as:

angle = Angle.as_degrees(180)
other_angle = Angle.as_degrees(60)

new_angle = angle + other_angle

In general

  • it only makes sense to add or subtract two values of the same quantity (e.g. two angles). You get back a new unit of that quantity. You can't add an angle and a distance.
  • you can multiply or divide across quantities, but this returns a new quantity type. For example dividing a Distance by a Duration returns a Velocity.
  • You can multiply and divide a quantity by a unit-less number (this is scaling the quantity up or down)
  • you can divide two quantities of the same type and get a unit-less number back (one of the few times I'm OK with a raw number!)

This reminds me of your suggestion to implement #cos, but this means I have to be cautious because #cos would return a number (implicitly in radians) instead of an Angle.

Interestingly, the value returned by trigonometric functions is not a number of radians. It is not even an angle. Instead it is a unit-less number (a ratio of two distances so the units cancel out)

The idea that you can do math between and across unit types, that this can result in new units, and that some operations are forbidden leads to the technique of dimensional analysis, where a calculation can be spot-checked for correctness by making sure that the units that come out of it are those expected

Some languages like F# can track unit math automatically for you, which is pretty cool!

@rhannequin rhannequin marked this pull request as ready for review February 21, 2024 21:20
@rhannequin rhannequin force-pushed the add-arithmetic-methods-to-angle branch from 6aa22d9 to e463ade Compare February 21, 2024 21:29
@rhannequin rhannequin merged commit ecd3d2d into main Feb 23, 2024
5 checks passed
@rhannequin rhannequin deleted the add-arithmetic-methods-to-angle branch February 23, 2024 10:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants