-
Notifications
You must be signed in to change notification settings - Fork 1
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
feature: Fractional Exponents #7
base: main
Are you sure you want to change the base?
feature: Fractional Exponents #7
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent work!! I love this approach.
Just wondering - have we validated that exponents in a fractional form are sufficient? Like that defining units in a decimal-based format is not required/desired? Also worth noting (although it's probably completely irrelevant), is that integer fractions cannot represent all decimal values: https://en.wikipedia.org/wiki/Irrational_number
Sources/Units/Unit/Fraction.swift
Outdated
|
||
var positive: Bool { | ||
switch (numerator, denominator) { | ||
// 0/0 is not positive in this logic |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just as an aside, here's a fun math Wikipedia article on this particular fraction: https://en.wikipedia.org/wiki/Indeterminate_form#Indeterminate_form_0/0
Sources/Units/Unit/Fraction.swift
Outdated
|
||
extension Fraction: Comparable { | ||
public static func < (lhs: Fraction, rhs: Fraction) -> Bool { | ||
return lhs.numerator < rhs.numerator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that this is correct - it should be:
return lhs.numerator < rhs.numerator | |
return lhs.asDouble < rhs.asDouble |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. I'll fix this. Instead of asDouble
I'l just do the int math to create a common denominator and compare them that way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated this logic.
} | ||
|
||
extension SignedInteger { | ||
func over<T: SignedInteger>(_ denominator: T) -> Fraction { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Were there type inference issues with using /
, like 5.measured(in: .meter.pow(1/2))
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. That was what I originally tried.
It was ambiguous to the compiler whether 1 / 2
meant Int / Int
or Fraction / Int
or Fraction / Fraction
etc because Fraction
conforms to ExpressibleAsIntegerLiteral.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On that note, how do you feel about |
as the operator? It wouldn't be ambiguous.
You could do 2|5
etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went ahead and did this - lmk if you like/dislike.
let gcd = Self.gcd(numerator, denominator) | ||
self.numerator = numerator / gcd | ||
self.denominator = denominator / gcd |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be public?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I guess the tests do a testable import so I didn't catch that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've made some more things public
@@ -0,0 +1,163 @@ | |||
|
|||
|
|||
public struct Fraction: Hashable, Equatable, Sendable { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we provide documentation about this type? Specific areas that would be helpful to document after reading through:
init
automatically reduces the input fraction- String representation uses
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Will do. I'll make a doc pass for everything I've added.
@@ -7,6 +7,8 @@ final class UnitTests: XCTestCase { | |||
XCTAssertNotEqual(Unit.meter, Unit.foot) | |||
XCTAssertEqual(Unit.meter * Unit.second / Unit.second, Unit.meter) | |||
XCTAssertNotEqual(Unit.newton, Unit.kilogram * Unit.meter / Unit.second.pow(2)) | |||
XCTAssertNotEqual(Unit.meter.pow(1.over(2)), Unit.kilogram * Unit.meter / Unit.second.pow(2)) | |||
XCTAssertEqual(Unit.meter.pow(1.over(6)), Unit.meter.pow(1.over(2)).pow(1.over(3)) ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These tests are great, but could we also add specific tests for the Fraction functions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. Just haven't yet cuz I didn't want to spend more time on it if it wasn't a productive direction to go. I'll make a more robust test suite for the Fraction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added tests.
Fractional form is not sufficient. It's just a step in the right direction. I haven't thought much about how we'll straddle the operation between |
bfa5aac
to
53a7872
Compare
Oof, do you think we should continue down this direction then or just try and go toward a 'double'-ized exponent? I'd hate to introduce a |
53a7872
to
03652e7
Compare
Sorry it won't be subsuming the functionality.
The reason we need fraction parts is to preserve precision for as long as possible so we don't run into a case like Can you think of any reason I wouldn't need to worry about that and could instead just convert all fractional exponents into Doubles and still get the right behavior during dimensional analysis? The main use case is for intermediate units that when combined reduce into units that make sense. |
No description provided.