JuliaLang / julia

The Julia Programming Language
https://julialang.org/
MIT License
45.74k stars 5.48k forks source link

Comparison with irrationals is not thread safe #52862

Open OlivierHnt opened 10 months ago

OlivierHnt commented 10 months ago

While investigating https://github.com/JuliaIntervals/IntervalArithmetic.jl/issues/612, we found out that < hinges on setrounding which is not thread safe.

MWE:

julia> precision(BigFloat)
256

julia> x = BigFloat(1)
1.0

julia> Threads.@threads for _ in 1:100000
           x < π
       end

julia> precision(BigFloat)
288

This example was run using Julia v1.10

julia> versioninfo()
Julia Version 1.10.0
Commit 3120989f39b (2023-12-25 18:01 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: macOS (arm64-apple-darwin22.4.0)
  CPU: 8 × Apple M1
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-15.0.7 (ORCJIT, apple-m1)
  Threads: 11 on 4 virtual cores

The problem seems to be here https://github.com/JuliaLang/julia/blob/c5d7b87a35b5beaef9d4d3aa53c0a2686f3445b9/base/irrationals.jl#L99-L101

cc @Kolaru and @dpsanders

Joel-Dahne commented 10 months ago

This problem is similar to #52859. At this place I think the fix is simple, just use specify the precision explicitly with BigFloat(x, precision = precision(y) + 32).

However, the construction of BigFloat from Irrational also uses setprecision and is hence not thread-safe. This is a harder problem to solve since when specifying irrationals one can give an arbitrary function for computing them. Here is the implementation https://github.com/JuliaLang/julia/blob/c5d7b87a35b5beaef9d4d3aa53c0a2686f3445b9/base/irrationals.jl#L212-L240

Joel-Dahne commented 10 months ago

In fact setprecision is used in a non-safe way in three more places in that file. For construction of Rational{T] as well as construction of Float32 and Float64 with rounding. In all of those places it would be fine to replace a constructor that explicitly specifies the precision though.