-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
/
fastmath.jl
177 lines (154 loc) · 6.55 KB
/
fastmath.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# This file is a part of Julia. License is MIT: http://julialang.org/license
# fast math
# basic arithmetic
const one32 = one(Float32)
const eps32 = eps(Float32)
const eps32_2 = eps32/2
# Note: Cannot use local functions since these are not yet optimized
fm_ieee_32(x) = x + eps32_2 + eps32_2
fm_fast_32(x) = @fastmath x + eps32_2 + eps32_2
@test fm_ieee_32(one32) == one32
@test (fm_fast_32(one32) == one32 ||
fm_fast_32(one32) == one32 + eps32 > one32)
const one64 = one(Float64)
const eps64 = eps(Float64)
const eps64_2 = eps64/2
# Note: Cannot use local functions since these are not yet optimized
fm_ieee_64(x) = x + eps64_2 + eps64_2
fm_fast_64(x) = @fastmath x + eps64_2 + eps64_2
@test fm_ieee_64(one64) == one64
@test (fm_fast_64(one64) == one64 ||
fm_fast_64(one64) == one64 + eps64 > one64)
# check updating operators
fm_ieee_64_upd(x) = (r=x; r+=eps64_2; r+=eps64_2)
fm_fast_64_upd(x) = @fastmath (r=x; r+=eps64_2; r+=eps64_2)
@test fm_ieee_64_upd(one64) == one64
@test (fm_fast_64_upd(one64) == one64 ||
fm_fast_64_upd(one64) == one64 + eps64 > one64)
let epsf = 1.0f0/2^15, one_epsf = 1+epsf
@test isapprox((@fastmath one_epsf * one_epsf - 1),
Float32(65537/1073741824))
end
let eps = 1.0/2^30, one_eps = 1+eps
@test isapprox((@fastmath one_eps * one_eps - 1),
2147483649/1152921504606846976)
end
for T in (Float32, Float64, BigFloat)
zero = convert(T, 0)
one = convert(T, 1) + eps(T)
two = convert(T, 2) + 1//10
three = convert(T, 3) + 1//100
@test isapprox((@fastmath +two), +two)
@test isapprox((@fastmath -two), -two)
@test isapprox((@fastmath zero+one+two), zero+one+two)
@test isapprox((@fastmath zero-one-two), zero-one-two)
@test isapprox((@fastmath one*two*three), one*two*three)
@test isapprox((@fastmath one/two/three), one/two/three)
@test isapprox((@fastmath rem(two, three)), rem(two, three))
@test isapprox((@fastmath mod(two, three)), mod(two, three))
@test (@fastmath cmp(two, two)) == cmp(two, two)
@test (@fastmath cmp(two, three)) == cmp(two, three)
@test (@fastmath cmp(three, two)) == cmp(three, two)
@test (@fastmath one/zero) == convert(T, Inf)
@test (@fastmath -one/zero) == -convert(T, Inf)
@test isnan(@fastmath zero/zero) # must not throw
for x in (zero, two, convert(T, Inf), convert(T, NaN))
@test (@fastmath isfinite(x))
@test !(@fastmath isinf(x))
@test !(@fastmath isnan(x))
@test !(@fastmath issubnormal(x))
end
end
for T in (Complex64, Complex128, Complex{BigFloat})
zero = convert(T, 0)
one = convert(T, 1) + im*eps(real(convert(T,1)))
two = convert(T, 2) + im//10
three = convert(T, 3) + im//100
@test isapprox((@fastmath +two), +two)
@test isapprox((@fastmath -two), -two)
@test isapprox((@fastmath zero+one+two), zero+one+two)
@test isapprox((@fastmath zero-one-two), zero-one-two)
@test isapprox((@fastmath one*two*three), one*two*three)
@test isapprox((@fastmath one/two/three), one/two/three)
@test (@fastmath three == two) == (three == two)
@test (@fastmath three != two) == (three != two)
@test isnan(@fastmath one/zero) # must not throw
@test isnan(@fastmath -one/zero) # must not throw
@test isnan(@fastmath zero/zero) # must not throw
for x in (zero, two, convert(T, Inf), convert(T, NaN))
@test (@fastmath isfinite(x))
@test !(@fastmath isinf(x))
@test !(@fastmath isnan(x))
@test !(@fastmath issubnormal(x))
end
end
# math functions
for T in (Float32, Float64, BigFloat)
half = 1/convert(T, 2)
third = 1/convert(T, 3)
for f in (:+, :-, :abs, :abs2, :conj, :inv, :sign,
:acos, :asin, :asinh, :atan, :atanh, :cbrt, :cos, :cosh,
:exp10, :exp2, :exp, :expm1, :lgamma, :log10, :log1p,
:log2, :log, :sin, :sinh, :sqrt, :tan, :tanh)
@test isapprox((@eval @fastmath $f($half)), (@eval $f($half)))
@test isapprox((@eval @fastmath $f($third)), (@eval $f($third)))
end
for f in (:acosh,)
@test isapprox((@eval @fastmath $f(1+$half)), (@eval $f(1+$half)))
@test isapprox((@eval @fastmath $f(1+$third)), (@eval $f(1+$third)))
end
for f in (:+, :-, :*, :/, :%, :(==), :!=, :<, :<=, :>, :>=, :^,
:atan2, :hypot, :max, :min)
@test isapprox((@eval @fastmath $f($half, $third)),
(@eval $f($half, $third)))
@test isapprox((@eval @fastmath $f($third, $half)),
(@eval $f($third, $half)))
end
for f in (:minmax,)
@test isapprox((@eval @fastmath $f($half, $third))[1],
(@eval $f($half, $third))[1])
@test isapprox((@eval @fastmath $f($half, $third))[2],
(@eval $f($half, $third))[2])
@test isapprox((@eval @fastmath $f($third, $half))[1],
(@eval $f($third, $half))[1])
@test isapprox((@eval @fastmath $f($third, $half))[2],
(@eval $f($third, $half))[2])
end
end
for T in (Float32, Float64, BigFloat)
CT = Complex{T}
half = (1+1im)/convert(T, 2) # complex
third = 1/convert(T, 3) # real
@test isapprox((@fastmath third^3), third^3)
@test isapprox((@fastmath half/third), half/third)
@test isapprox((@fastmath half^3), half^3)
@test isapprox((@fastmath cis(third)), cis(third))
end
for T in (Complex64, Complex128, Complex{BigFloat})
half = (1+1im)/convert(T, 2)
third = (1-1im)/convert(T, 3)
for f in (:+, :-, :abs, :abs2, :conj, :inv, :sign,
:acos, :acosh, :asin, :asinh, :atan, :atanh, :cos,
:cosh, :exp10, :exp2, :exp, :expm1, :log10, :log1p,
:log2, :log, :sin, :sinh, :sqrt, :tan, :tanh)
@test isapprox((@eval @fastmath $f($half)), (@eval $f($half)))
@test isapprox((@eval @fastmath $f($third)), (@eval $f($third)))
end
for f in (:+, :-, :*, :/, :(==), :!=, :^)
@test isapprox((@eval @fastmath $f($half, $third)),
(@eval $f($half, $third)))
@test isapprox((@eval @fastmath $f($third, $half)),
(@eval $f($third, $half)))
end
end
# issue #10544
let a = ones(2,2), b = ones(2,2)
@test isapprox((@fastmath a[1] += 2.0), b[1] += 2.0)
@test isapprox((@fastmath a[2] -= 2.0), b[2] -= 2.0)
@test isapprox((@fastmath a[1,1] *= 2.0), b[1,1] *= 2.0)
@test isapprox((@fastmath a[2,2] /= 2.0), b[2,2] /= 2.0)
@test isapprox((@fastmath a[1,2] ^= 2.0), b[1,2] ^= 2.0)
# test fallthrough for unsupported ops
local c = 0
@test Bool((@fastmath c |= 1))
end