• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37919

29 Sep 2024 09:41AM UTC coverage: 86.232% (-0.3%) from 86.484%
#37919

push

local

web-flow
fix rawbigints OOB issues (#55917)

Fixes issues introduced in #50691 and found in #55906:
* use `@inbounds` and `@boundscheck` macros in rawbigints, for catching
OOB with `--check-bounds=yes`
* fix OOB in `truncate`

12 of 13 new or added lines in 1 file covered. (92.31%)

1287 existing lines in 41 files now uncovered.

77245 of 89578 relevant lines covered (86.23%)

15686161.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.01
/base/floatfuncs.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
## floating-point functions ##
4

5
copysign(x::Float64, y::Float64) = copysign_float(x, y)
3,638,464✔
6
copysign(x::Float32, y::Float32) = copysign_float(x, y)
1,555,146✔
7
copysign(x::Float32, y::Real) = copysign(x, Float32(y))
51✔
8
copysign(x::Float64, y::Real) = copysign(x, Float64(y))
173,674✔
9

10
flipsign(x::Float64, y::Float64) = bitcast(Float64, xor_int(bitcast(UInt64, x), and_int(bitcast(UInt64, y), 0x8000000000000000)))
212,267✔
11
flipsign(x::Float32, y::Float32) = bitcast(Float32, xor_int(bitcast(UInt32, x), and_int(bitcast(UInt32, y), 0x80000000)))
123✔
12
flipsign(x::Float32, y::Real) = flipsign(x, Float32(y))
63✔
13
flipsign(x::Float64, y::Real) = flipsign(x, Float64(y))
96,565✔
14

15
signbit(x::Float64) = signbit(bitcast(Int64, x))
49,608,296✔
16
signbit(x::Float32) = signbit(bitcast(Int32, x))
18,740,484✔
17
signbit(x::Float16) = signbit(bitcast(Int16, x))
739,125✔
18

19
"""
20
    maxintfloat(T=Float64)
21

22
The largest consecutive integer-valued floating-point number that is exactly represented in
23
the given floating-point type `T` (which defaults to `Float64`).
24

25
That is, `maxintfloat` returns the smallest positive integer-valued floating-point number
26
`n` such that `n+1` is *not* exactly representable in the type `T`.
27

28
When an `Integer`-type value is needed, use `Integer(maxintfloat(T))`.
29
"""
30
maxintfloat(::Type{Float64}) = 9007199254740992.
×
31
maxintfloat(::Type{Float32}) = Float32(16777216.)
3,126,106✔
32
maxintfloat(::Type{Float16}) = Float16(2048f0)
2,284,559✔
33
maxintfloat(x::T) where {T<:AbstractFloat} = maxintfloat(T)
63✔
34

35
"""
36
    maxintfloat(T, S)
37

38
The largest consecutive integer representable in the given floating-point type `T` that
39
also does not exceed the maximum integer representable by the integer type `S`.  Equivalently,
40
it is the minimum of `maxintfloat(T)` and [`typemax(S)`](@ref).
41
"""
42
maxintfloat(::Type{S}, ::Type{T}) where {S<:AbstractFloat, T<:Integer} = min(maxintfloat(S), S(typemax(T)))
6,262,859✔
43
maxintfloat() = maxintfloat(Float64)
1✔
44

45
isinteger(x::AbstractFloat) = iszero(x - trunc(x)) # note: x == trunc(x) would be incorrect for x=Inf
36,541,459✔
46

47
# See rounding.jl for docstring.
48

49
# NOTE: this relies on the current keyword dispatch behaviour (#9498).
50
function round(x::Real, r::RoundingMode=RoundNearest;
2,026,798✔
51
               digits::Union{Nothing,Integer}=nothing, sigdigits::Union{Nothing,Integer}=nothing, base::Union{Nothing,Integer}=nothing)
52
    if digits === nothing
280✔
53
        if sigdigits === nothing
47✔
54
            if base === nothing
1✔
55
                # avoid recursive calls
56
                throw(MethodError(round, (x,r)))
×
57
            else
58
                round(x,r)
1✔
59
                # or throw(ArgumentError("`round` cannot use `base` argument without `digits` or `sigdigits` arguments."))
60
            end
61
        else
62
            isfinite(x) || return float(x)
48✔
63
            _round_sigdigits(x, r, sigdigits, base === nothing ? 10 : base)
42✔
64
        end
65
    else
66
        if sigdigits === nothing
233✔
67
            isfinite(x) || return float(x)
43,739✔
68
            _round_digits(x, r, digits, base === nothing ? 10 : base)
43,731✔
69
        else
70
            throw(ArgumentError("`round` cannot use both `digits` and `sigdigits` arguments."))
×
71
        end
72
    end
73
end
74

75
# round x to multiples of 1/invstep
76
function _round_invstep(x, invstep, r::RoundingMode)
6✔
77
    y = round(x * invstep, r) / invstep
43,659✔
78
    if !isfinite(y)
43,659✔
79
        return x
×
80
    end
81
    return y
43,659✔
82
end
83

84
# round x to multiples of 1/(invstepsqrt^2)
85
# Using square root of step prevents overflowing
UNCOV
86
function _round_invstepsqrt(x, invstepsqrt, r::RoundingMode)
×
87
    y = round((x * invstepsqrt) * invstepsqrt, r) / invstepsqrt / invstepsqrt
26✔
88
    if !isfinite(y)
26✔
89
        return x
16✔
90
    end
91
    return y
10✔
92
end
93

94
# round x to multiples of step
UNCOV
95
function _round_step(x, step, r::RoundingMode)
×
96
    # TODO: use div with rounding mode
97
    y = round(x / step, r) * step
15✔
98
    if !isfinite(y)
15✔
99
        if x > 0
12✔
100
            return (r == RoundUp ? oftype(x, Inf) : zero(x))
4✔
101
        elseif x < 0
8✔
102
            return (r == RoundDown ? -oftype(x, Inf) : -zero(x))
4✔
103
        else
104
            return x
4✔
105
        end
106
    end
107
    return y
3✔
108
end
109

110
function _round_digits(x, r::RoundingMode, digits::Integer, base)
43,694✔
111
    fx = float(x)
157✔
112
    if digits >= 0
43,700✔
113
        invstep = oftype(fx, base)^digits
87,349✔
114
        if isfinite(invstep)
43,685✔
115
            return _round_invstep(fx, invstep, r)
43,659✔
116
        else
117
            invstepsqrt = oftype(fx, base)^oftype(fx, digits/2)
26✔
118
            return _round_invstepsqrt(fx, invstepsqrt, r)
26✔
119
        end
120
    else
121
        step = oftype(fx, base)^-digits
24✔
122
        return _round_step(fx, step, r)
15✔
123
    end
124
end
125

126
hidigit(x::Integer, base) = ndigits0z(x, base)
×
127
function hidigit(x::AbstractFloat, base)
40✔
128
    iszero(x) && return 0
42✔
129
    if base == 10
40✔
130
        return 1 + floor(Int, log10(abs(x)))
36✔
131
    elseif base == 2
4✔
132
        return 1 + exponent(x)
3✔
133
    else
134
        return 1 + floor(Int, log(base, abs(x)))
1✔
135
    end
136
end
137
hidigit(x::Real, base) = hidigit(float(x), base)
3✔
138

139
function _round_sigdigits(x, r::RoundingMode, sigdigits::Integer, base)
140
    h = hidigit(x, base)
42✔
141
    _round_digits(x, r, sigdigits-h, base)
42✔
142
end
143

144
# C-style round
145
function round(x::AbstractFloat, ::RoundingMode{:NearestTiesAway})
49,520✔
146
    y = trunc(x)
50,594✔
147
    ifelse(x==y,y,trunc(2*x-y))
50,594✔
148
end
149
# Java-style round
150
function round(x::T, ::RoundingMode{:NearestTiesUp}) where {T <: AbstractFloat}
49,520✔
151
    copysign(floor((x + (T(0.25) - eps(T(0.5)))) + (T(0.25) + eps(T(0.5)))), x)
50,594✔
152
end
153

154
function Base.round(x::AbstractFloat, ::typeof(RoundFromZero))
49,520✔
155
    signbit(x) ? round(x, RoundDown) : round(x, RoundUp)
51,076✔
156
end
157

158
# isapprox: approximate equality of numbers
159
"""
160
    isapprox(x, y; atol::Real=0, rtol::Real=atol>0 ? 0 : √eps, nans::Bool=false[, norm::Function])
161

162
Inexact equality comparison. Two numbers compare equal if their relative distance *or* their
163
absolute distance is within tolerance bounds: `isapprox` returns `true` if
164
`norm(x-y) <= max(atol, rtol*max(norm(x), norm(y)))`. The default `atol` (absolute tolerance) is zero and the
165
default `rtol` (relative tolerance) depends on the types of `x` and `y`. The keyword argument `nans` determines
166
whether or not NaN values are considered equal (defaults to false).
167

168
For real or complex floating-point values, if an `atol > 0` is not specified, `rtol` defaults to
169
the square root of [`eps`](@ref) of the type of `x` or `y`, whichever is bigger (least precise).
170
This corresponds to requiring equality of about half of the significant digits. Otherwise,
171
e.g. for integer arguments or if an `atol > 0` is supplied, `rtol` defaults to zero.
172

173
The `norm` keyword defaults to `abs` for numeric `(x,y)` and to `LinearAlgebra.norm` for
174
arrays (where an alternative `norm` choice is sometimes useful).
175
When `x` and `y` are arrays, if `norm(x-y)` is not finite (i.e. `±Inf`
176
or `NaN`), the comparison falls back to checking whether all elements of `x` and `y` are
177
approximately equal component-wise.
178

179
The binary operator `≈` is equivalent to `isapprox` with the default arguments, and `x ≉ y`
180
is equivalent to `!isapprox(x,y)`.
181

182
Note that `x ≈ 0` (i.e., comparing to zero with the default tolerances) is
183
equivalent to `x == 0` since the default `atol` is `0`.  In such cases, you should either
184
supply an appropriate `atol` (or use `norm(x) ≤ atol`) or rearrange your code (e.g.
185
use `x ≈ y` rather than `x - y ≈ 0`).   It is not possible to pick a nonzero `atol`
186
automatically because it depends on the overall scaling (the "units") of your problem:
187
for example, in `x - y ≈ 0`, `atol=1e-9` is an absurdly small tolerance if `x` is the
188
[radius of the Earth](https://en.wikipedia.org/wiki/Earth_radius) in meters,
189
but an absurdly large tolerance if `x` is the
190
[radius of a Hydrogen atom](https://en.wikipedia.org/wiki/Bohr_radius) in meters.
191

192
!!! compat "Julia 1.6"
193
    Passing the `norm` keyword argument when comparing numeric (non-array) arguments
194
    requires Julia 1.6 or later.
195

196
# Examples
197
```jldoctest
198
julia> isapprox(0.1, 0.15; atol=0.05)
199
true
200

201
julia> isapprox(0.1, 0.15; rtol=0.34)
202
true
203

204
julia> isapprox(0.1, 0.15; rtol=0.33)
205
false
206

207
julia> 0.1 + 1e-10 ≈ 0.1
208
true
209

210
julia> 1e-10 ≈ 0
211
false
212

213
julia> isapprox(1e-10, 0, atol=1e-8)
214
true
215

216
julia> isapprox([10.0^9, 1.0], [10.0^9, 2.0]) # using `norm`
217
true
218
```
219
"""
220
function isapprox(x::Number, y::Number;
385,907✔
221
                  atol::Real=0, rtol::Real=rtoldefault(x,y,atol),
222
                  nans::Bool=false, norm::Function=abs)
223
    x′, y′ = promote(x, y) # to avoid integer overflow
368,678✔
224
    x == y ||
385,999✔
225
        (isfinite(x) && isfinite(y) && norm(x-y) <= max(atol, rtol*max(norm(x′), norm(y′)))) ||
226
         (nans && isnan(x) && isnan(y))
227
end
228

229
function isapprox(x::Integer, y::Integer;
794✔
230
                  atol::Real=0, rtol::Real=rtoldefault(x,y,atol),
231
                  nans::Bool=false, norm::Function=abs)
232
    if norm === abs && atol < 1 && rtol == 0
577✔
233
        return x == y
462✔
234
    else
235
        # We need to take the difference `max` - `min` when comparing unsigned integers.
236
        _x, _y = x < y ? (x, y) : (y, x)
127✔
237
        return norm(_y - _x) <= max(atol, rtol*max(norm(_x), norm(_y)))
115✔
238
    end
239
end
240

241
"""
242
    isapprox(x; kwargs...) / ≈(x; kwargs...)
243

244
Create a function that compares its argument to `x` using `≈`, i.e. a function equivalent to `y -> y ≈ x`.
245

246
The keyword arguments supported here are the same as those in the 2-argument `isapprox`.
247

248
!!! compat "Julia 1.5"
249
    This method requires Julia 1.5 or later.
250
"""
251
isapprox(y; kwargs...) = x -> isapprox(x, y; kwargs...)
197✔
252

253
const ≈ = isapprox
254
"""
255
    x ≉ y
256

257
This is equivalent to `!isapprox(x,y)` (see [`isapprox`](@ref)).
258
"""
259
≉(args...; kws...) = !≈(args...; kws...)
56✔
260

261
# default tolerance arguments
262
rtoldefault(::Type{T}) where {T<:AbstractFloat} = sqrt(eps(T))
429,622✔
263
rtoldefault(::Type{<:Real}) = 0
×
264
function rtoldefault(x::Union{T,Type{T}}, y::Union{S,Type{S}}, atol::Real) where {T<:Number,S<:Number}
19,189✔
265
    rtol = max(rtoldefault(real(T)),rtoldefault(real(S)))
427,568✔
266
    return atol > 0 ? zero(rtol) : rtol
412,198✔
267
end
268

269
# fused multiply-add
270

271
"""
272
    fma(x, y, z)
273

274
Computes `x*y+z` without rounding the intermediate result `x*y`. On some systems this is
275
significantly more expensive than `x*y+z`. `fma` is used to improve accuracy in certain
276
algorithms. See [`muladd`](@ref).
277
"""
278
function fma end
279
function fma_emulated(a::Float32, b::Float32, c::Float32)::Float32
262,155✔
280
    ab = Float64(a) * b
262,155✔
281
    res = ab+c
262,155✔
282
    reinterpret(UInt64, res)&0x1fff_ffff!=0x1000_0000 && return res
262,155✔
283
    # yes error compensation is necessary. It sucks
284
    reslo = abs(c)>abs(ab) ? ab-(res - c) : c-(res - ab)
4✔
285
    res = iszero(reslo) ? res : (signbit(reslo) ? prevfloat(res) : nextfloat(res))
3✔
286
    return res
2✔
287
end
288

289
""" Splits a Float64 into a hi bit and a low bit where the high bit has 27 trailing 0s and the low bit has 26 trailing 0s"""
290
@inline function splitbits(x::Float64)
291
    hi = reinterpret(Float64, reinterpret(UInt64, x) & 0xffff_ffff_f800_0000)
923,223✔
292
    return hi, x-hi
923,223✔
293
end
294

295
function twomul(a::Float64, b::Float64)
296
    ahi, alo = splitbits(a)
307,741✔
297
    bhi, blo = splitbits(b)
307,741✔
298
    abhi = a*b
307,741✔
299
    blohi, blolo = splitbits(blo)
307,741✔
300
    ablo = alo*blohi - (((abhi - ahi*bhi) - alo*bhi) - ahi*blo) + blolo*alo
307,741✔
301
    return abhi, ablo
×
302
end
303

304
function fma_emulated(a::Float64, b::Float64,c::Float64)
262,452✔
305
    abhi, ablo = @inline twomul(a,b)
262,452✔
306
    if !isfinite(abhi+c) || isless(abs(abhi), nextfloat(0x1p-969)) || issubnormal(a) || issubnormal(b)
491,894✔
307
        aandbfinite = isfinite(a) && isfinite(b)
69,641✔
308
        if !(isfinite(c) && aandbfinite)
69,641✔
309
            return aandbfinite ? c : abhi+c
443✔
310
        end
311
        (iszero(a) || iszero(b)) && return abhi+c
69,198✔
312
        # The checks above satisfy exponent's nothrow precondition
313
        bias = Math._exponent_finite_nonzero(a) + Math._exponent_finite_nonzero(b)
69,197✔
314
        c_denorm = ldexp(c, -bias)
138,394✔
315
        if isfinite(c_denorm)
69,197✔
316
            # rescale a and b to [1,2), equivalent to ldexp(a, -exponent(a))
317
            issubnormal(a) && (a *= 0x1p52)
45,289✔
318
            issubnormal(b) && (b *= 0x1p52)
45,289✔
319
            a = reinterpret(Float64, (reinterpret(UInt64, a) & ~Base.exponent_mask(Float64)) | Base.exponent_one(Float64))
45,289✔
320
            b = reinterpret(Float64, (reinterpret(UInt64, b) & ~Base.exponent_mask(Float64)) | Base.exponent_one(Float64))
45,289✔
321
            c = c_denorm
×
322
            abhi, ablo = twomul(a,b)
45,289✔
323
            # abhi <= 4 -> isfinite(r)      (α)
324
            r = abhi+c
45,289✔
325
            # s ≈ 0                         (β)
326
            s = (abs(abhi) > abs(c)) ? (abhi-r+c+ablo) : (c-r+abhi+ablo)
57,926✔
327
            # α ⩓ β -> isfinite(sumhi)      (γ)
328
            sumhi = r+s
45,289✔
329
            # If result is subnormal, ldexp will cause double rounding because subnormals have fewer mantisa bits.
330
            # As such, we need to check whether round to even would lead to double rounding and manually round sumhi to avoid it.
331
            if issubnormal(ldexp(sumhi, bias))
90,578✔
332
                sumlo = r-sumhi+s
16✔
333
                # finite: See γ
334
                # non-zero: If sumhi == ±0., then ldexp(sumhi, bias) == ±0,
335
                # so we don't take this branch.
336
                bits_lost = -bias-Math._exponent_finite_nonzero(sumhi)-1022
16✔
337
                sumhiInt = reinterpret(UInt64, sumhi)
16✔
338
                if (bits_lost != 1) ⊻ (sumhiInt&1 == 1)
16✔
339
                    sumhi = nextfloat(sumhi, cmp(sumlo,0))
12✔
340
                end
341
            end
342
            return ldexp(sumhi, bias)
45,289✔
343
        end
344
        isinf(abhi) && signbit(c) == signbit(a*b) && return abhi
23,908✔
345
        # fall through
346
    end
347
    r = abhi+c
216,719✔
348
    s = (abs(abhi) > abs(c)) ? (abhi-r+c+ablo) : (c-r+abhi+ablo)
335,354✔
349
    return r+s
216,719✔
350
end
351
fma_llvm(x::Float32, y::Float32, z::Float32) = fma_float(x, y, z)
2,448,598✔
352
fma_llvm(x::Float64, y::Float64, z::Float64) = fma_float(x, y, z)
408,530,108✔
353

354
# Disable LLVM's fma if it is incorrect, e.g. because LLVM falls back
355
# onto a broken system libm; if so, use a software emulated fma
356
@assume_effects :consistent fma(x::Float32, y::Float32, z::Float32) = Core.Intrinsics.have_fma(Float32) ? fma_llvm(x,y,z) : fma_emulated(x,y,z)
2,448,598✔
357
@assume_effects :consistent fma(x::Float64, y::Float64, z::Float64) = Core.Intrinsics.have_fma(Float64) ? fma_llvm(x,y,z) : fma_emulated(x,y,z)
408,530,108✔
358

359
function fma(a::Float16, b::Float16, c::Float16)
1✔
360
    Float16(muladd(Float32(a), Float32(b), Float32(c))) #don't use fma if the hardware doesn't have it.
499,784✔
361
end
362

363
# This is necessary at least on 32-bit Intel Linux, since fma_llvm may
364
# have called glibc, and some broken glibc fma implementations don't
365
# properly restore the rounding mode
366
Rounding.setrounding_raw(Float32, Rounding.JL_FE_TONEAREST)
367
Rounding.setrounding_raw(Float64, Rounding.JL_FE_TONEAREST)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc