Skip to content

[stdlib] Add ** and **= for exponentiation #36053

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

Closed
wants to merge 6 commits into from

Conversation

benrimmington
Copy link
Contributor

@benrimmington benrimmington added the swift evolution pending discussion Flag → feature: A feature that has a Swift evolution proposal currently in review label Feb 19, 2021
@benrimmington
Copy link
Contributor Author

@swift-ci Please test

@benrimmington
Copy link
Contributor Author

@swift-ci Please test Windows platform

@benrimmington benrimmington requested a review from xwu February 19, 2021 15:59
@xwu
Copy link
Collaborator

xwu commented Feb 20, 2021

Neat. I think the question (for others to decide) is whether we'd want to add these shims to the standard library now (they'd have to stay forever). Personally, I think it's fine. Will have to think more about this whole precedence issue a little more on the forums.

@@ -118,17 +117,17 @@ FloatingPoint.test("BinaryFloatingPoint/genericIntegerConversion") {
FloatingPoint.test("BinaryFloatingPoint/genericFloatingPointConversion") {
func convert<
T: BinaryFloatingPoint, U: BinaryFloatingPoint
>(exactly value: T, to: U.Type) -> U { U(exactly: value) }
>(exactly value: T, to: U.Type) -> U? { U(exactly: value) }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused what happened here. Did it always not compile?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The entire test file was disabled 2 years ago (#23423), probably due to the isQuietNaN test failures.

The genericFloatingPointConversion test was updated 5 months ago (#33910), but it never compiled.

public static func **= (_ lhs: inout Self, _ rhs: Self) {
lhs = lhs ** rhs
}

Copy link
Collaborator

@xwu xwu Feb 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tricky thing about adding these for real (and @stephentyrone has said this in the forums) is that we then need to talk about whether the (Self, Self) -> Self overloads should vend IEEE pow (integral exponents get special treatment) or powr (derived by considering only exp(rhs * log(lhs))).

We would also need to consider if (Self, Int) -> Self overloads need to be added at the same time (vending IEEE pown), and if so whether they can appropriately be spelled with the same operator for two subtly different functions. The reason it'd have to be talked about now is, if we do decide to overload and choose powr for the above (Self, Self) -> Self overload, then for an integer literal exponent adding the overload later would silently change the behavior of existing code.

(My personal preference would be to use ** (Self, Self) -> Self to vend pow and ** (Self, Int) -> Self to vend pown, with a consideration for &** to be added if needed for powr. But I have to admit I haven't thought about it deeply.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swift Numerics uses __builtin_pow{,f,l} for all pairs of pow(_:_:) methods:

Clang also has:

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well I think that's settled then...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correction: Swift Numerics uses a guard statement, to implement pow(x, y) as exp(y * log(x)):

extension Double: Real {

  public static func pow(_ x: Double, _ y: Double) -> Double {
    guard x >= 0 else { return .nan }
    return libm_pow(x, y)
  }
}

So I think Clang/C99 is IEEE pow? Swift Numerics is IEEE powr and pown?

Module Test Result IEEE
Builtin __builtin_pow(-2.0, 4.0) 16.0 pow
Darwin pow(-2.0, 4.0) 16.0 pow
RealModule Double.pow(-2.0, 4.0) .nan powr
RealModule Double.pow(-2.0, 4__) 16.0 pown

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, conceptually, that would be how they're aligned then (there are some edge conditions where the IEEE-specified result of pow and powr differ (pow(1, .infinity) being one example)).

@benrimmington
Copy link
Contributor Author

I've opened #36072 to reinstate the floating-point tests.

@benrimmington benrimmington deleted the exponentiation branch February 21, 2021 14:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
swift evolution pending discussion Flag → feature: A feature that has a Swift evolution proposal currently in review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants