diff mbox series

[bug#62819,core-updates,1/2] gnu: julia: Fix test suite regression.

Message ID 20230413202445.2098413-1-zimon.toutoune@gmail.com
State New
Headers show
Series [bug#62819,core-updates,1/2] gnu: julia: Fix test suite regression. | expand

Commit Message

Simon Tournier April 13, 2023, 8:24 p.m. UTC
The update of 'mpfr' to 4.2.0 by commit
d26814f8b936911d48bb004093713a525f2c6cf8 introduces a Julia test suite
regression.  The patch backports the Julia upstream fix.

* gnu/packages/julia.scm (julia)[source]: Add patch.
* gnu/packages/patches/julia-Use-MPFR-4.2.patch: New file.
* gnu/local.mk: Add it.
---
 gnu/local.mk                                  |   1 +
 gnu/packages/julia.scm                        |   3 +-
 gnu/packages/patches/julia-Use-MPFR-4.2.patch | 228 ++++++++++++++++++
 3 files changed, 231 insertions(+), 1 deletion(-)
 create mode 100644 gnu/packages/patches/julia-Use-MPFR-4.2.patch


base-commit: a957171bc41e98e29674f99cf3dd2940ff45a0d3

Comments

Andreas Enge April 14, 2023, 12:04 p.m. UTC | #1
Hello Simon,

the proposed patch is not enough. Now julia fails with the following message
(on x86_64):

Error in testset LinearAlgebra/addmul:
Error During Test at none:1
  Got exception outside of a @test
  ProcessExitedException(2)
  Stacktrace:
    [1] try_yieldto(undo::typeof(Base.ensure_rescheduled))
      @ Base ./task.jl:871
    [2] wait()
      @ Base ./task.jl:931
    [3] wait(c::Base.GenericCondition{ReentrantLock})
      @ Base ./condition.jl:124
    [4] take_buffered(c::Channel{Any})
      @ Base ./channels.jl:416
    [5] take!(c::Channel{Any})
      @ Base ./channels.jl:410
    [6] take!(::Distributed.RemoteValue)
      @ Distributed ~/guix-build-julia-1.8.3.drv-0/julia-1.8.3/usr/share/julia/stdlib/v1.8/Distributed/src/remotecall.jl:726
    [7] remotecall_fetch(::Function, ::Distributed.Worker, ::String, ::Vararg{String}; kwargs::Base.Pairs{Symbol, UInt128, Tuple{Symbol}, NamedTuple{(:seed,), Tuple{UInt128}}})
      @ Distributed ~/guix-build-julia-1.8.3.drv-0/julia-1.8.3/usr/share/julia/stdlib/v1.8/Distributed/src/remotecall.jl:461
    [8] remotecall_fetch(::Function, ::Int64, ::String, ::Vararg{String}; kwargs::Base.Pairs{Symbol, UInt128, Tuple{Symbol}, NamedTuple{(:seed,), Tuple{UInt128}}})
      @ Distributed ~/guix-build-julia-1.8.3.drv-0/julia-1.8.3/usr/share/julia/stdlib/v1.8/Distributed/src/remotecall.jl:492
    [9] macro expansion
      @ ~/guix-build-julia-1.8.3.drv-0/julia-1.8.3/test/runtests.jl:260 [inlined]
   [10] (::var"#43#55"{Vector{Task}, var"#print_testworker_errored#51"{ReentrantLock, Int64, Int64}, var"#print_testworker_stats#49"{ReentrantLock, Int64, Int64, Int64, Int64, Int64, Int64}, Vector{Any}, Dict{String, DateTime}})()
      @ Main ./task.jl:484
ERROR: LoadError: Test run finished with errors
in expression starting at /tmp/guix-build-julia-1.8.3.drv-0/julia-1.8.3/test/runtests.jl:93
make[1]: *** [Makefile:25: default] Error 1
make[1]: Leaving directory '/tmp/guix-build-julia-1.8.3.drv-0/julia-1.8.3/test'
make: *** [Makefile:552: test] Error 2

Test suite failed, dumping logs.
error: in phase 'check': uncaught exception:
%exception #<&invoke-error program: "make" arguments: ("test" "-j" "4" "VERBOSE=1" "prefix=/gnu/store/3xxjvc8nswaklinr9s6lispdinc3x44v-julia-1.8.3" "JULIA_CPU_TARGET=generic;generic,-cx16,clone_all;sandybridge,-xsaveopt,clone_all;haswell,-rdrnd,base(1)" "CONFIG_SHELL=bash -x" "USE_BINARYBUILDER=0" "USE_SYSTEM_CSL=1" "USE_SYSTEM_LLVM=1" "USE_SYSTEM_LIBUNWIND=1" "USE_SYSTEM_PCRE=1" "USE_SYSTEM_OPENLIBM=1" "USE_SYSTEM_DSFMT=1" "USE_SYSTEM_LIBBLASTRAMPOLINE=1" "USE_SYSTEM_BLAS=1" "USE_SYSTEM_LAPACK=1" "USE_SYSTEM_GMP=1" "USE_SYSTEM_MPFR=1" "USE_SYSTEM_LIBSUITESPARSE=1" "USE_SYSTEM_LIBUV=1" "USE_SYSTEM_UTF8PROC=1" "USE_SYSTEM_MBEDTLS=1" "USE_SYSTEM_LIBSSH2=1" "USE_SYSTEM_NGHTTP2=1" "USE_SYSTEM_CURL=1" "USE_SYSTEM_LIBGIT2=1" "USE_SYSTEM_PATCHELF=1" "USE_SYSTEM_LIBWHICH=1" "USE_SYSTEM_ZLIB=1" "USE_SYSTEM_P7ZIP=1" "USE_LLVM_SHLIB=1" "NO_GIT=1" "USE_GPL_LIBS=1" "LIBBLAS=-lopenblas" "LIBBLASNAME=libopenblas" "UTF8PROC_INC=/gnu/store/dwsnxdqa3hvsrvrvlqbw1qyrqxf4khkp-utf8proc-2.7.0/include" "LIBUV=/gnu/store/fh2cksjy4bd8wj3iij7s2xd3g3ny7gkn-libuv-julia-2.0.0-4.e6f0e49/lib/libuv.a" "LIBUV_INC=/gnu/store/fh2cksjy4bd8wj3iij7s2xd3g3ny7gkn-libuv-julia-2.0.0-4.e6f0e49/include") exit-status: 2 term-signal: #f stop-signal: #f>
phase `check' failed after 4965.9 seconds
command "make" "test" "-j" "4" "VERBOSE=1" "prefix=/gnu/store/3xxjvc8nswaklinr9s6lispdinc3x44v-julia-1.8.3" "JULIA_CPU_TARGET=generic;generic,-cx16,clone_all;sandybridge,-xsaveopt,clone_all;haswell,-rdrnd,base(1)" "CONFIG_SHELL=bash -x" "USE_BINARYBUILDER=0" "USE_SYSTEM_CSL=1" "USE_SYSTEM_LLVM=1" "USE_SYSTEM_LIBUNWIND=1" "USE_SYSTEM_PCRE=1" "USE_SYSTEM_OPENLIBM=1" "USE_SYSTEM_DSFMT=1" "USE_SYSTEM_LIBBLASTRAMPOLINE=1" "USE_SYSTEM_BLAS=1" "USE_SYSTEM_LAPACK=1" "USE_SYSTEM_GMP=1" "USE_SYSTEM_MPFR=1" "USE_SYSTEM_LIBSUITESPARSE=1" "USE_SYSTEM_LIBUV=1" "USE_SYSTEM_UTF8PROC=1" "USE_SYSTEM_MBEDTLS=1" "USE_SYSTEM_LIBSSH2=1" "USE_SYSTEM_NGHTTP2=1" "USE_SYSTEM_CURL=1" "USE_SYSTEM_LIBGIT2=1" "USE_SYSTEM_PATCHELF=1" "USE_SYSTEM_LIBWHICH=1" "USE_SYSTEM_ZLIB=1" "USE_SYSTEM_P7ZIP=1" "USE_LLVM_SHLIB=1" "NO_GIT=1" "USE_GPL_LIBS=1" "LIBBLAS=-lopenblas" "LIBBLASNAME=libopenblas" "UTF8PROC_INC=/gnu/store/dwsnxdqa3hvsrvrvlqbw1qyrqxf4khkp-utf8proc-2.7.0/include" "LIBUV=/gnu/store/fh2cksjy4bd8wj3iij7s2xd3g3ny7gkn-libuv-julia-2.0.0-4.e6f0e49/lib/libuv.a" "LIBUV_INC=/gnu/store/fh2cksjy4bd8wj3iij7s2xd3g3ny7gkn-libuv-julia-2.0.0-4.e6f0e49/include" failed with status 2
builder for `/gnu/store/6g75j5i0jjfzlskma0hgj85w9r9p1dv6-julia-1.8.3.drv' failed with exit code 1
build of /gnu/store/6g75j5i0jjfzlskma0hgj85w9r9p1dv6-julia-1.8.3.drv failed
View build log at '/var/log/guix/drvs/6g/75j5i0jjfzlskma0hgj85w9r9p1dv6-julia-1.8.3.drv.gz'.
guix build: error: build of `/gnu/store/6g75j5i0jjfzlskma0hgj85w9r9p1dv6-julia-1.8.3.drv' failed

Andreas
Andreas Enge April 14, 2023, 12:23 p.m. UTC | #2
Am Fri, Apr 14, 2023 at 02:04:51PM +0200 schrieb Andreas Enge:
> the proposed patch is not enough. Now julia fails with the following message
> (on x86_64):

Actually I have tried julia@1.8.3 together with the patch.
Did you try with an update to 1.8.5 plus the patch?

Andreas
Simon Tournier April 14, 2023, 2:12 p.m. UTC | #3
On Fri, 14 Apr 2023 at 14:23, Andreas Enge <andreas@enge.fr> wrote:
>
> Am Fri, Apr 14, 2023 at 02:04:51PM +0200 schrieb Andreas Enge:
> > the proposed patch is not enough. Now julia fails with the following message
> > (on x86_64):

I do not have the failure you are reporting. The build is totally fine
on my machine. Even, Julia builds fine on two different machines.

Do you have enough Memory?


> Actually I have tried julia@1.8.3 together with the patch.
> Did you try with an update to 1.8.5 plus the patch?

The update is too much work.


Cheers,
simon
Andreas Enge April 14, 2023, 2:17 p.m. UTC | #4
Am Fri, Apr 14, 2023 at 04:12:10PM +0200 schrieb Simon Tournier:
> I do not have the failure you are reporting. The build is totally fine
> on my machine. Even, Julia builds fine on two different machines.
> Do you have enough Memory?

16GB. But indeed at some point the desktop came to a crawl.
I will try again on berlin.

Andreas
Andreas Enge April 14, 2023, 3:20 p.m. UTC | #5
Am Fri, Apr 14, 2023 at 04:17:57PM +0200 schrieb Andreas Enge:
> 16GB. But indeed at some point the desktop came to a crawl.
> I will try again on berlin.

It passed on berlin, and I pushed the patch, thanks! This is frightening
and quite unreasonable. If julia  needs more than 16GB of main memory to
build, it will pass on our aarch64 machines with 32GB of memory, but not
on most boards limited to 4GB.

Andreas
Simon Tournier April 14, 2023, 4:33 p.m. UTC | #6
Hi Andreas,

On ven., 14 avril 2023 at 17:20, Andreas Enge <andreas@enge.fr> wrote:

> It passed on berlin, and I pushed the patch, thanks! This is frightening
> and quite unreasonable. If julia  needs more than 16GB of main memory to
> build, it will pass on our aarch64 machines with 32GB of memory, but not
> on most boards limited to 4GB.

Julia requires more than 4GB – currently the 8GB of my laptop are full
and extended by 6GB of swap; still building and maybe will fail — and
supports these platform:

                    x86-64         (64-bit)  
                    i686           (32-bit)          
                    ARMv8          (64-bit)          
                    ARMv7          (32-bit)          
                    PowerPC        (64-bit)  
    CUDA 10.1       Nvidia CUDA    (64-bit)
    ROCM            AMD ROCM       (64-bit)  
    oneAPI          Intel oneAPI   (64-bit)

    https://julialang.org/downloads/#supported_platforms

Upstream provides binaries for these.  AFAIK, for most of them, Julia is
cross-compiled and not natively compiled.  Well, I am still missing the
point to natively compile on limited boards.

Having substitutes running on non-x86_64 architectures is one thing,
directly build on these non-x86_64 architectures is another.

(I am not saying that direct builds on these non-x86_64 architectures is
not interesting by itself but that I miss the aim of such for some heavy
packages as Julia or GHC or else.)


Cheers,
simon
Andreas Enge April 16, 2023, 12:06 p.m. UTC | #7
Julia bug fixed in commit 1e28aed2eb7049c8a40092071ac1ca1142869b6d.
The GHC problem is unrelated and not fixed by the proposed patch,
as far as I can see.

Andreas
diff mbox series

Patch

diff --git a/gnu/local.mk b/gnu/local.mk
index b07811f1cb..ed064937d7 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1380,6 +1380,7 @@  dist_patch_DATA =						\
   %D%/packages/patches/json-c-0.13-CVE-2020-12762.patch		\
   %D%/packages/patches/json-c-0.12-CVE-2020-12762.patch		\
   %D%/packages/patches/julia-SOURCE_DATE_EPOCH-mtime.patch	\
+  %D%/packages/patches/julia-Use-MPFR-4.2.patch	                \
   %D%/packages/patches/libgeotiff-fix-tests-with-proj-9.1.1.patch	\
   %D%/packages/patches/libobjc2-unbundle-robin-map.patch	\
   %D%/packages/patches/librime-fix-build-with-gcc10.patch	\
diff --git a/gnu/packages/julia.scm b/gnu/packages/julia.scm
index 906cb4b94c..ba54175822 100644
--- a/gnu/packages/julia.scm
+++ b/gnu/packages/julia.scm
@@ -150,7 +150,8 @@  (define-public julia
               (sha256
                (base32
                 "0jf8dr5j7y8cjnr65kn38xps5h9m2qvi8g1yd8qgiip5r87ld3ad"))
-              (patches (search-patches "julia-SOURCE_DATE_EPOCH-mtime.patch"))))
+              (patches (search-patches "julia-SOURCE_DATE_EPOCH-mtime.patch"
+                                       "julia-Use-MPFR-4.2.patch"))))
     (build-system gnu-build-system)
     (arguments
      `(#:test-target "test"
diff --git a/gnu/packages/patches/julia-Use-MPFR-4.2.patch b/gnu/packages/patches/julia-Use-MPFR-4.2.patch
new file mode 100644
index 0000000000..73a395c89e
--- /dev/null
+++ b/gnu/packages/patches/julia-Use-MPFR-4.2.patch
@@ -0,0 +1,228 @@ 
+This patch backports part of Julia upstream commit:
+
+    1e5fdb29f8858f3244f6aff116ee12e4c8247f3a
+    Author:     Simon Byrne <simon.byrne@gmail.com>
+    AuthorDate: Tue Jan 10 14:52:36 2023 -0800
+    Commit:     GitHub <noreply@github.com>
+    CommitDate: Tue Jan 10 17:52:36 2023 -0500
+
+    update MPFR to 4.2.0 (#48165)
+
+    Co-authored-by: Mosè Giordano <giordano@users.noreply.github.com>
+
+    6 files changed, 112 insertions(+), 79 deletions(-)
+    base/mpfr.jl                     | 34 ++++++++++++++--
+    deps/checksums/mpfr              | 68 ++++++++++++++++----------------
+    deps/mpfr.version                |  2 +-
+    stdlib/MPFR_jll/Project.toml     |  2 +-
+    stdlib/MPFR_jll/test/runtests.jl |  2 +-
+    test/math.jl                     | 83 +++++++++++++++++++++-------------------
+
+
+diff -ur julia-1.8.3-orig/base/mpfr.jl julia-1.8.3-patch/base/mpfr.jl
+--- julia-1.8.3-orig/base/mpfr.jl	2023-04-13 17:50:58.394891391 +0200
++++ julia-1.8.3-patch/base/mpfr.jl	2023-04-13 20:42:52.551833467 +0200
+@@ -16,7 +16,8 @@
+         cosh, sinh, tanh, sech, csch, coth, acosh, asinh, atanh, lerpi,
+         cbrt, typemax, typemin, unsafe_trunc, floatmin, floatmax, rounding,
+         setrounding, maxintfloat, widen, significand, frexp, tryparse, iszero,
+-        isone, big, _string_n, decompose
++        isone, big, _string_n, decompose, minmax,
++        sinpi, cospi, sincospi, sind, cosd, tand, asind, acosd, atand
+ 
+ import ..Rounding: rounding_raw, setrounding_raw
+ 
+@@ -745,7 +746,7 @@
+ end
+ 
+ # Functions for which NaN results are converted to DomainError, following Base
+-for f in (:sin, :cos, :tan, :sec, :csc, :acos, :asin, :atan, :acosh, :asinh, :atanh)
++for f in (:sin, :cos, :tan, :sec, :csc, :acos, :asin, :atan, :acosh, :asinh, :atanh, :sinpi, :cospi)
+     @eval begin
+         function ($f)(x::BigFloat)
+             isnan(x) && return x
+@@ -756,6 +757,7 @@
+         end
+     end
+ end
++sincospi(x::BigFloat) = (sinpi(x), cospi(x))
+ 
+ function atan(y::BigFloat, x::BigFloat)
+     z = BigFloat()
+@@ -763,6 +765,32 @@
+     return z
+ end
+ 
++# degree functions
++for f in (:sin, :cos, :tan)
++    @eval begin
++        function ($(Symbol(f,:d)))(x::BigFloat)
++            isnan(x) && return x
++            z = BigFloat()
++            ccall(($(string(:mpfr_,f,:u)), :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, x, 360, ROUNDING_MODE[])
++            isnan(z) && throw(DomainError(x, "NaN result for non-NaN input."))
++            return z
++        end
++        function ($(Symbol(:a,f,:d)))(x::BigFloat)
++            isnan(x) && return x
++            z = BigFloat()
++            ccall(($(string(:mpfr_a,f,:u)), :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, x, 360, ROUNDING_MODE[])
++            isnan(z) && throw(DomainError(x, "NaN result for non-NaN input."))
++            return z
++        end
++    end
++end
++function atand(y::BigFloat, x::BigFloat)
++    z = BigFloat()
++    ccall((:mpfr_atan2u, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, y, x, 360, ROUNDING_MODE[])
++    return z
++end
++
++
+ # Utility functions
+ ==(x::BigFloat, y::BigFloat) = ccall((:mpfr_equal_p, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}), x, y) != 0
+ <=(x::BigFloat, y::BigFloat) = ccall((:mpfr_lessequal_p, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}), x, y) != 0
+@@ -1018,7 +1046,7 @@
+     isfinite(x) || return string(Float64(x))
+     _prettify_bigfloat(string_mpfr(x, fmt))
+ end
+-_string(x::BigFloat) = _string(x, "%.Re")
++_string(x::BigFloat) = _string(x, "%Re")
+ _string(x::BigFloat, k::Integer) = _string(x, "%.$(k)Re")
+ 
+ string(b::BigFloat) = _string(b)
+diff -ur julia-1.8.3-orig/test/math.jl julia-1.8.3-patch/test/math.jl
+--- julia-1.8.3-orig/test/math.jl	2023-04-13 17:50:58.382891276 +0200
++++ julia-1.8.3-patch/test/math.jl	2023-04-13 21:13:55.377279761 +0200
+@@ -411,47 +411,51 @@
+     @test rad2deg(pi + (pi/3)*im) ≈ 180 + 60im
+ end
+ 
++# ensure zeros are signed the same
++⩲(x,y) = typeof(x) == typeof(y) && x == y && signbit(x) == signbit(y)
++⩲(x::Tuple, y::Tuple) = length(x) == length(y) && all(map(⩲,x,y))
++
+ @testset "degree-based trig functions" begin
+-    @testset "$T" for T = (Float32,Float64,Rational{Int})
++    @testset "$T" for T = (Float32,Float64,Rational{Int},BigFloat)
+         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)))
++            @test sind(convert(T,x))::fT ≈ sin(pi*convert(fT,x)/180) atol=eps(deg2rad(convert(fT,x)))
++            @test cosd(convert(T,x))::fT ≈ cos(pi*convert(fT,x)/180) 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)))
++            @test s::fT ≈ sin(pi*convert(fT,x)/180) atol=eps(deg2rad(convert(fT,x)))
++            @test c::fT ≈ cos(pi*convert(fT,x)/180) atol=eps(deg2rad(convert(fT,x)))
+         end
+         @testset "sind" begin
+-            @test sind(convert(T,0.0))::fT === zero(fT)
+-            @test sind(convert(T,180.0))::fT === zero(fT)
+-            @test sind(convert(T,360.0))::fT === zero(fT)
+-            T != Rational{Int} && @test sind(convert(T,-0.0))::fT === -zero(fT)
+-            @test sind(convert(T,-180.0))::fT === -zero(fT)
+-            @test sind(convert(T,-360.0))::fT === -zero(fT)
++            @test sind(convert(T,0.0))::fT ⩲ zero(fT)
++            @test sind(convert(T,180.0))::fT ⩲ zero(fT)
++            @test sind(convert(T,360.0))::fT ⩲ zero(fT)
++            T != Rational{Int} && @test sind(convert(T,-0.0))::fT ⩲ -zero(fT)
++            @test sind(convert(T,-180.0))::fT ⩲ -zero(fT)
++            @test sind(convert(T,-360.0))::fT ⩲ -zero(fT)
+             if T <: AbstractFloat
+                 @test isnan(sind(T(NaN)))
+             end
+         end
+         @testset "cosd" begin
+-            @test cosd(convert(T,90))::fT === zero(fT)
+-            @test cosd(convert(T,270))::fT === zero(fT)
+-            @test cosd(convert(T,-90))::fT === zero(fT)
+-            @test cosd(convert(T,-270))::fT === zero(fT)
++            @test cosd(convert(T,90))::fT ⩲ zero(fT)
++            @test cosd(convert(T,270))::fT ⩲ zero(fT)
++            @test cosd(convert(T,-90))::fT ⩲ zero(fT)
++            @test cosd(convert(T,-270))::fT ⩲ zero(fT)
+             if T <: AbstractFloat
+                 @test isnan(cosd(T(NaN)))
+             end
+         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) )
++            @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) )
+             if T <: AbstractFloat
+                 @test_throws DomainError sincosd(T(Inf))
+                 @test all(isnan.(sincosd(T(NaN))))
+@@ -463,22 +467,22 @@
+             "sincospi" => (x->sincospi(x)[1], x->sincospi(x)[2])
+         )
+             @testset "pi * $x" for x = -3:0.3:3
+-                @test sinpi(convert(T,x))::fT ≈ convert(fT,sin(pi*x)) atol=eps(pi*convert(fT,x))
+-                @test cospi(convert(T,x))::fT ≈ convert(fT,cos(pi*x)) atol=eps(pi*convert(fT,x))
++                @test sinpi(convert(T,x))::fT ≈ sin(pi*convert(fT,x)) atol=eps(pi*convert(fT,x))
++                @test cospi(convert(T,x))::fT ≈ cos(pi*convert(fT,x)) atol=eps(pi*convert(fT,x))
+             end
+ 
+-            @test sinpi(convert(T,0.0))::fT === zero(fT)
+-            @test sinpi(convert(T,1.0))::fT === zero(fT)
+-            @test sinpi(convert(T,2.0))::fT === zero(fT)
+-            T != Rational{Int} && @test sinpi(convert(T,-0.0))::fT === -zero(fT)
+-            @test sinpi(convert(T,-1.0))::fT === -zero(fT)
+-            @test sinpi(convert(T,-2.0))::fT === -zero(fT)
++            @test sinpi(convert(T,0.0))::fT ⩲ zero(fT)
++            @test sinpi(convert(T,1.0))::fT ⩲ zero(fT)
++            @test sinpi(convert(T,2.0))::fT ⩲ zero(fT)
++            T != Rational{Int} && @test sinpi(convert(T,-0.0))::fT ⩲ -zero(fT)
++            @test sinpi(convert(T,-1.0))::fT ⩲ -zero(fT)
++            @test sinpi(convert(T,-2.0))::fT ⩲ -zero(fT)
+             @test_throws DomainError sinpi(convert(T,Inf))
+ 
+-            @test cospi(convert(T,0.5))::fT === zero(fT)
+-            @test cospi(convert(T,1.5))::fT === zero(fT)
+-            @test cospi(convert(T,-0.5))::fT === zero(fT)
+-            @test cospi(convert(T,-1.5))::fT === zero(fT)
++            @test cospi(convert(T,0.5))::fT ⩲ zero(fT)
++            @test cospi(convert(T,1.5))::fT ⩲ zero(fT)
++            @test cospi(convert(T,-0.5))::fT ⩲ zero(fT)
++            @test cospi(convert(T,-1.5))::fT ⩲ zero(fT)
+             @test_throws DomainError cospi(convert(T,Inf))
+         end
+         @testset "Check exact values" begin
+@@ -489,8 +493,8 @@
+             @test sincospi(one(T)/convert(T,6))[1] == 0.5
+             @test_throws DomainError sind(convert(T,Inf))
+             @test_throws DomainError cosd(convert(T,Inf))
+-            T != Float32 && @test cospi(one(T)/convert(T,3)) == 0.5
+-            T != Float32 && @test sincospi(one(T)/convert(T,3))[2] == 0.5
++            fT == Float64 && @test isapprox(cospi(one(T)/convert(T,3)), 0.5)
++            fT == Float64 && @test isapprox(sincospi(one(T)/convert(T,3))[2], 0.5)
+             T == Rational{Int} && @test sinpi(5//6) == 0.5
+             T == Rational{Int} && @test sincospi(5//6)[1] == 0.5
+         end
+@@ -538,8 +542,8 @@
+             end
+         end
+     end
+-    @test @inferred(sinc(0//1)) === 1.0
+-    @test @inferred(cosc(0//1)) === -0.0
++    @test @inferred(sinc(0//1)) ⩲ 1.0
++    @test @inferred(cosc(0//1)) ⩲ -0.0
+ 
+     # test right before/after thresholds of Taylor series
+     @test sinc(0.001) ≈ 0.999998355066745 rtol=1e-15