Skip to content

Commit 1b99c54

Browse files
Merge pull request #69 from stephentyrone/cbrt
Defer to libm cbrt for root(x,3).
2 parents 913a62e + 5d783ce commit 1b99c54

File tree

4 files changed

+43
-9
lines changed

4 files changed

+43
-9
lines changed

Sources/NumericsShims/include/NumericsShims.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ HEADER_SHIM float libm_powf(float x, float y) {
8181
return __builtin_powf(x, y);
8282
}
8383

84+
HEADER_SHIM float libm_cbrtf(float x) {
85+
return __builtin_cbrtf(x);
86+
}
87+
8488
HEADER_SHIM float libm_atan2f(float y, float x) {
8589
return __builtin_atan2f(y, x);
8690
}
@@ -204,6 +208,10 @@ HEADER_SHIM double libm_pow(double x, double y) {
204208
return __builtin_pow(x, y);
205209
}
206210

211+
HEADER_SHIM double libm_cbrt(double x) {
212+
return __builtin_cbrt(x);
213+
}
214+
207215
HEADER_SHIM double libm_atan2(double y, double x) {
208216
return __builtin_atan2(y, x);
209217
}
@@ -322,6 +330,10 @@ HEADER_SHIM long double libm_powl(long double x, long double y) {
322330
return __builtin_powl(x, y);
323331
}
324332

333+
HEADER_SHIM long double libm_cbrtl(long double x) {
334+
return __builtin_cbrtl(x);
335+
}
336+
325337
HEADER_SHIM long double libm_atan2l(long double y, long double x) {
326338
return __builtin_atan2l(y, x);
327339
}

Sources/Real/Real.swift

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,6 @@ extension Real {
3939
return pow(10, x)
4040
}
4141

42-
@_transparent
43-
public static func root(_ x: Self, _ n: Int) -> Self {
44-
guard x >= 0 || n % 2 != 0 else { return .nan }
45-
// TODO: this implementation is not quite correct, because n may be
46-
// rounded in conversion to Self. This only affects very extreme cases,
47-
// so we'll leave it alone for now.
48-
return Self(signOf: x, magnitudeOf: pow(x.magnitude, 1/Self(n)))
49-
}
50-
5142
#if !os(Windows)
5243
public static func signGamma(_ x: Self) -> FloatingPointSign {
5344
// Gamma is strictly positive for x >= 0.

Sources/Real/ScalarConformances.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ extension Float: Real {
5757
return libm_powf(x, Float(n))
5858
}
5959

60+
@_transparent public static func root(_ x: Float, _ n: Int) -> Float {
61+
guard x >= 0 || n % 2 != 0 else { return .nan }
62+
// Workaround the issue mentioned below for the specific case of n = 3
63+
// where we can fallback on cbrt.
64+
if n == 3 { return libm_cbrtf(x) }
65+
// TODO: this implementation is not quite correct, because either n or
66+
// 1/n may be not be representable as Float.
67+
return Float(signOf: x, magnitudeOf: libm_powf(x.magnitude, 1/Float(n)))
68+
}
69+
6070
@_transparent public static func atan2(y: Float, x: Float) -> Float {
6171
return libm_atan2f(y, x)
6272
}
@@ -126,6 +136,16 @@ extension Double: Real {
126136
return libm_pow(x, Double(n))
127137
}
128138

139+
@_transparent public static func root(_ x: Double, _ n: Int) -> Double {
140+
guard x >= 0 || n % 2 != 0 else { return .nan }
141+
// Workaround the issue mentioned below for the specific case of n = 3
142+
// where we can fallback on cbrt.
143+
if n == 3 { return libm_cbrt(x) }
144+
// TODO: this implementation is not quite correct, because either n or
145+
// 1/n may be not be representable as Double.
146+
return Double(signOf: x, magnitudeOf: libm_pow(x.magnitude, 1/Double(n)))
147+
}
148+
129149
@_transparent public static func atan2(y: Double, x: Double) -> Double {
130150
return libm_atan2(y, x)
131151
}
@@ -178,6 +198,16 @@ extension Float80: Real {
178198
return libm_powl(x, Float80(n))
179199
}
180200

201+
@_transparent public static func root(_ x: Float80, _ n: Int) -> Float80 {
202+
guard x >= 0 || n % 2 != 0 else { return .nan }
203+
// Workaround the issue mentioned below for the specific case of n = 3
204+
// where we can fallback on cbrt.
205+
if n == 3 { return libm_cbrtl(x) }
206+
// TODO: this implementation is not quite correct, because either n or
207+
// 1/n may be not be representable as Float80.
208+
return Float80(signOf: x, magnitudeOf: libm_powl(x.magnitude, 1/Float80(n)))
209+
}
210+
181211
@_transparent public static func atan2(y: Float80, x: Float80) -> Float80 {
182212
return libm_atan2l(y, x)
183213
}

Tests/RealTests/RealTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ internal extension ElementaryFunctions where Self: BinaryFloatingPoint {
6161
sanityCheck(-0.980829253011726236856451127452003999, Self.log(0.375))
6262
sanityCheck(0.3184537311185346158102472135905995955, Self.log(onePlus: 0.375))
6363
sanityCheck(-0.7211247851537041911608191553900547941, Self.root(-0.375, 3))
64+
XCTAssertEqual(-10, Self.root(-1000, 3))
6465
sanityCheck(0.6123724356957945245493210186764728479, Self.sqrt(0.375))
6566
sanityCheck(0.54171335479545025876069682133938570, Self.pow(0.375, 0.625))
6667
sanityCheck(-0.052734375, Self.pow(-0.375, 3))

0 commit comments

Comments
 (0)