diff --git a/NEWS.md b/NEWS.md index 0310608c30ffd..a4eca97480707 100644 --- a/NEWS.md +++ b/NEWS.md @@ -6,6 +6,7 @@ New language features * Support for Unicode 12.1.0 ([#32002]). * Methods can now be added to an abstract type ([#31916]). +* Added `sincosd(x)` to simultaneously compute the sine and cosine of `x`, where `x` is in degrees ([#30134]). Language changes ---------------- diff --git a/base/exports.jl b/base/exports.jl index 2d84157686774..4b24efcc24bd8 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -324,6 +324,7 @@ export sin, sinc, sincos, + sincosd, sind, sinh, sinpi, diff --git a/base/math.jl b/base/math.jl index d1a11fbdbad63..af021ac4ea41c 100644 --- a/base/math.jl +++ b/base/math.jl @@ -6,7 +6,7 @@ export sin, cos, sincos, tan, sinh, cosh, tanh, asin, acos, atan, asinh, acosh, atanh, sec, csc, cot, asec, acsc, acot, sech, csch, coth, asech, acsch, acoth, sinpi, cospi, sinc, cosc, - cosd, cotd, cscd, secd, sind, tand, + cosd, cotd, cscd, secd, sind, tand, sincosd, acosd, acotd, acscd, asecd, asind, atand, rad2deg, deg2rad, log, log2, log10, log1p, exponent, exp, exp2, exp10, expm1, diff --git a/base/special/trig.jl b/base/special/trig.jl index a9d158a101b82..c848ebfe492d1 100644 --- a/base/special/trig.jl +++ b/base/special/trig.jl @@ -1073,6 +1073,28 @@ end tand(x::Real) = sind(x) / cosd(x) +""" + sincosd(x) + +Simultaneously compute the sine and cosine of `x`, where `x` is in degrees. + +!!! compat "Julia 1.3" + This function requires at least Julia 1.3. +""" +function sincosd(x::Real) + if isinf(x) + return throw(DomainError(x, "sincosd(x) is only defined for finite `x`.")) + elseif isnan(x) + return (oftype(x,NaN), oftype(x,NaN)) + end + + # It turns out that calling those functions separately yielded better + # performance than considering each case and calling `sincos_kernel`. + return (sind(x), cosd(x)) +end + +sincosd(::Missing) = (missing, missing) + for (fd, f, fn) in ((:sind, :sin, "sine"), (:cosd, :cos, "cosine"), (:tand, :tan, "tangent")) name = string(fd) @eval begin diff --git a/test/math.jl b/test/math.jl index e4bf37e6b0f76..9aa1851091d9a 100644 --- a/test/math.jl +++ b/test/math.jl @@ -369,9 +369,14 @@ end @testset "degree-based trig functions" begin @testset "$T" for T = (Float32,Float64,Rational{Int}) fT = typeof(float(one(T))) + fTsc = typeof( (float(one(T)), float(one(T))) ) for x = -400:40:400 @test sind(convert(T,x))::fT ≈ convert(fT,sin(pi/180*x)) atol=eps(deg2rad(convert(fT,x))) @test cosd(convert(T,x))::fT ≈ convert(fT,cos(pi/180*x)) atol=eps(deg2rad(convert(fT,x))) + + s,c = sincosd(convert(T,x)) + @test s::fT ≈ convert(fT,sin(pi/180*x)) atol=eps(deg2rad(convert(fT,x))) + @test c::fT ≈ convert(fT,cos(pi/180*x)) atol=eps(deg2rad(convert(fT,x))) end @testset "sind" begin @test sind(convert(T,0.0))::fT === zero(fT) @@ -387,6 +392,16 @@ end @test cosd(convert(T,-90))::fT === zero(fT) @test cosd(convert(T,-270))::fT === zero(fT) end + @testset "sincosd" begin + @test sincosd(convert(T,-360))::fTsc === ( -zero(fT), one(fT) ) + @test sincosd(convert(T,-270))::fTsc === ( one(fT), zero(fT) ) + @test sincosd(convert(T,-180))::fTsc === ( -zero(fT), -one(fT) ) + @test sincosd(convert(T, -90))::fTsc === ( -one(fT), zero(fT) ) + @test sincosd(convert(T, 0))::fTsc === ( zero(fT), one(fT) ) + @test sincosd(convert(T, 90))::fTsc === ( one(fT), zero(fT) ) + @test sincosd(convert(T, 180))::fTsc === ( zero(fT), -one(fT) ) + @test sincosd(convert(T, 270))::fTsc === ( -one(fT), zero(fT) ) + end @testset "sinpi and cospi" begin for x = -3:0.3:3