@@ -18,12 +18,10 @@ import
18
18
setrounding, maxintfloat, widen, significand, frexp, tryparse, iszero,
19
19
isone, big, _string_n, decompose, minmax, _precision_with_base_2,
20
20
sinpi, cospi, sincospi, tanpi, sind, cosd, tand, asind, acosd, atand,
21
- uinttype, exponent_max, exponent_min, ieee754_representation, significand_mask,
22
- RawBigIntRoundingIncrementHelper, truncated, RawBigInt
23
-
21
+ uinttype, exponent_max, exponent_min, ieee754_representation, significand_mask
24
22
25
23
using . Base. Libc
26
- import .. Rounding:
24
+ import .. Rounding: Rounding,
27
25
rounding_raw, setrounding_raw, rounds_to_nearest, rounds_away_from_zero,
28
26
tie_breaker_is_to_even, correct_rounding_requires_increment
29
27
39
37
const libmpfr = " libmpfr.so.6"
40
38
end
41
39
42
-
43
40
version () = VersionNumber (unsafe_string (ccall ((:mpfr_get_version ,libmpfr), Ptr{Cchar}, ())))
44
41
patches () = split (unsafe_string (ccall ((:mpfr_get_patches ,libmpfr), Ptr{Cchar}, ())),' ' )
45
42
@@ -120,69 +117,129 @@ const mpfr_special_exponent_zero = typemin(Clong) + true
120
117
const mpfr_special_exponent_nan = mpfr_special_exponent_zero + true
121
118
const mpfr_special_exponent_inf = mpfr_special_exponent_nan + true
122
119
120
+ struct BigFloatLayout
121
+ prec:: Clong
122
+ sign:: Cint
123
+ exp:: Clong
124
+ d:: Ptr{Limb}
125
+ # possible padding
126
+ p:: Limb # Tuple{Vararg{Limb}}
127
+ end
128
+ const offset_prec = fieldoffset (BigFloatLayout, 1 ) % Int
129
+ const offset_sign = fieldoffset (BigFloatLayout, 2 ) % Int
130
+ const offset_exp = fieldoffset (BigFloatLayout, 3 ) % Int
131
+ const offset_d = fieldoffset (BigFloatLayout, 4 ) % Int
132
+ const offset_p_limbs = ((fieldoffset (BigFloatLayout, 5 ) % Int + sizeof (Limb) - 1 ) ÷ sizeof (Limb))
133
+ const offset_p = offset_p_limbs * sizeof (Limb)
134
+
123
135
"""
124
136
BigFloat <: AbstractFloat
125
137
126
138
Arbitrary precision floating point number type.
127
139
"""
128
- mutable struct BigFloat <: AbstractFloat
129
- prec:: Clong
130
- sign:: Cint
131
- exp:: Clong
132
- d:: Ptr{Limb}
133
- # _d::Buffer{Limb} # Julia gc handle for memory @ d
134
- _d:: String # Julia gc handle for memory @ d (optimized)
140
+ struct BigFloat <: AbstractFloat
141
+ d:: Memory{Limb}
135
142
136
143
# Not recommended for general use:
137
144
# used internally by, e.g. deepcopy
138
- global function _BigFloat (prec:: Clong , sign:: Cint , exp:: Clong , d:: String )
139
- # ccall-based version, inlined below
140
- # z = new(zero(Clong), zero(Cint), zero(Clong), C_NULL, d)
141
- # ccall((:mpfr_custom_init,libmpfr), Cvoid, (Ptr{Limb}, Clong), d, prec) # currently seems to be a no-op in mpfr
142
- # NAN_KIND = Cint(0)
143
- # ccall((:mpfr_custom_init_set,libmpfr), Cvoid, (Ref{BigFloat}, Cint, Clong, Ptr{Limb}), z, NAN_KIND, prec, d)
144
- # return z
145
- return new (prec, sign, exp, pointer (d), d)
146
- end
145
+ global _BigFloat (d:: Memory{Limb} ) = new (d)
147
146
148
147
function BigFloat (; precision:: Integer = _precision_with_base_2 (BigFloat))
149
148
precision < 1 && throw (DomainError (precision, " `precision` cannot be less than 1." ))
150
149
nb = ccall ((:mpfr_custom_get_size ,libmpfr), Csize_t, (Clong,), precision)
151
- nb = (nb + Core. sizeof (Limb) - 1 ) ÷ Core. sizeof (Limb) # align to number of Limb allocations required for this
152
- # d = Vector{Limb}(undef, nb)
153
- d = _string_n (nb * Core. sizeof (Limb))
154
- EXP_NAN = mpfr_special_exponent_nan
155
- return _BigFloat (Clong (precision), one (Cint), EXP_NAN, d) # +NAN
150
+ nl = (nb + offset_p + sizeof (Limb) - 1 ) ÷ Core. sizeof (Limb) # align to number of Limb allocations required for this
151
+ d = Memory {Limb} (undef, nl % Int)
152
+ # ccall-based version, inlined below
153
+ z = _BigFloat (d) # initialize to +NAN
154
+ # ccall((:mpfr_custom_init,libmpfr), Cvoid, (Ptr{Limb}, Clong), BigFloatData(d), prec) # currently seems to be a no-op in mpfr
155
+ # NAN_KIND = Cint(0)
156
+ # ccall((:mpfr_custom_init_set,libmpfr), Cvoid, (Ref{BigFloat}, Cint, Clong, Ptr{Limb}), z, NAN_KIND, prec, BigFloatData(d))
157
+ z. prec = Clong (precision)
158
+ z. sign = one (Cint)
159
+ z. exp = mpfr_special_exponent_nan
160
+ return z
156
161
end
157
162
end
158
163
159
- # The rounding mode here shouldn't matter.
160
- significand_limb_count (x:: BigFloat ) = div (sizeof (x. _d), sizeof (Limb), RoundToZero)
164
+ """
165
+ Segment of raw words of bits interpreted as a big integer. Less
166
+ significant words come first. Each word is in machine-native bit-order.
167
+ """
168
+ struct BigFloatData{Limb}
169
+ d:: Memory{Limb}
170
+ end
171
+
172
+ # BigFloat interface
173
+ @inline function Base. getproperty (x:: BigFloat , s:: Symbol )
174
+ d = getfield (x, :d )
175
+ p = Base. unsafe_convert (Ptr{Limb}, d)
176
+ if s === :prec
177
+ return GC. @preserve d unsafe_load (Ptr {Clong} (p) + offset_prec)
178
+ elseif s === :sign
179
+ return GC. @preserve d unsafe_load (Ptr {Cint} (p) + offset_sign)
180
+ elseif s === :exp
181
+ return GC. @preserve d unsafe_load (Ptr {Clong} (p) + offset_exp)
182
+ elseif s === :d
183
+ return BigFloatData (d)
184
+ else
185
+ return throw (FieldError (typeof (x), s))
186
+ end
187
+ end
188
+
189
+ @inline function Base. setproperty! (x:: BigFloat , s:: Symbol , v)
190
+ d = getfield (x, :d )
191
+ p = Base. unsafe_convert (Ptr{Limb}, d)
192
+ if s === :prec
193
+ return GC. @preserve d unsafe_store! (Ptr {Clong} (p) + offset_prec, v)
194
+ elseif s === :sign
195
+ return GC. @preserve d unsafe_store! (Ptr {Cint} (p) + offset_sign, v)
196
+ elseif s === :exp
197
+ return GC. @preserve d unsafe_store! (Ptr {Clong} (p) + offset_exp, v)
198
+ # elseif s === :d # not mutable
199
+ else
200
+ return throw (FieldError (x, s))
201
+ end
202
+ end
203
+
204
+ # Ref interface: make sure the conversion to C is done properly
205
+ Base. unsafe_convert (:: Type{Ref{BigFloat}} , x:: Ptr{BigFloat} ) = error (" not compatible with mpfr" )
206
+ Base. unsafe_convert (:: Type{Ref{BigFloat}} , x:: Ref{BigFloat} ) = error (" not compatible with mpfr" )
207
+ Base. cconvert (:: Type{Ref{BigFloat}} , x:: BigFloat ) = x. d # BigFloatData is the Ref type for BigFloat
208
+ function Base. unsafe_convert (:: Type{Ref{BigFloat}} , x:: BigFloatData )
209
+ d = getfield (x, :d )
210
+ p = Base. unsafe_convert (Ptr{Limb}, d)
211
+ GC. @preserve d unsafe_store! (Ptr {Ptr{Limb}} (p) + offset_d, p + offset_p, :monotonic ) # :monotonic ensure that TSAN knows that this isn't a data race
212
+ return Ptr {BigFloat} (p)
213
+ end
214
+ Base. unsafe_convert (:: Type{Ptr{Limb}} , fd:: BigFloatData ) = Base. unsafe_convert (Ptr{Limb}, getfield (fd, :d )) + offset_p
215
+ function Base. setindex! (fd:: BigFloatData , v, i)
216
+ d = getfield (fd, :d )
217
+ @boundscheck 1 <= i <= length (d) - offset_p_limbs || throw (BoundsError (fd, i))
218
+ @inbounds d[i + offset_p_limbs] = v
219
+ return fd
220
+ end
221
+ function Base. getindex (fd:: BigFloatData , i)
222
+ d = getfield (fd, :d )
223
+ @boundscheck 1 <= i <= length (d) - offset_p_limbs || throw (BoundsError (fd, i))
224
+ @inbounds d[i + offset_p_limbs]
225
+ end
226
+ Base. length (fd:: BigFloatData ) = length (getfield (fd, :d )) - offset_p_limbs
227
+ Base. copyto! (fd:: BigFloatData , limbs) = copyto! (getfield (fd, :d ), offset_p_limbs + 1 , limbs) # for Random
228
+
229
+ include (" rawbigfloats.jl" )
161
230
162
231
rounding_raw (:: Type{BigFloat} ) = something (Base. ScopedValues. get (CURRENT_ROUNDING_MODE), ROUNDING_MODE[])
163
232
setrounding_raw (:: Type{BigFloat} , r:: MPFRRoundingMode ) = ROUNDING_MODE[]= r
164
233
function setrounding_raw (f:: Function , :: Type{BigFloat} , r:: MPFRRoundingMode )
165
234
Base. ScopedValues. @with (CURRENT_ROUNDING_MODE => r, f ())
166
235
end
167
236
168
-
169
237
rounding (:: Type{BigFloat} ) = convert (RoundingMode, rounding_raw (BigFloat))
170
238
setrounding (:: Type{BigFloat} , r:: RoundingMode ) = setrounding_raw (BigFloat, convert (MPFRRoundingMode, r))
171
239
setrounding (f:: Function , :: Type{BigFloat} , r:: RoundingMode ) =
172
240
setrounding_raw (f, BigFloat, convert (MPFRRoundingMode, r))
173
241
174
242
175
- # overload the definition of unsafe_convert to ensure that `x.d` is assigned
176
- # it may have been dropped in the event that the BigFloat was serialized
177
- Base. unsafe_convert (:: Type{Ref{BigFloat}} , x:: Ptr{BigFloat} ) = x
178
- @inline function Base. unsafe_convert (:: Type{Ref{BigFloat}} , x:: Ref{BigFloat} )
179
- x = x[]
180
- if x. d == C_NULL
181
- x. d = pointer (x. _d)
182
- end
183
- return convert (Ptr{BigFloat}, Base. pointer_from_objref (x))
184
- end
185
-
186
243
"""
187
244
BigFloat(x::Union{Real, AbstractString} [, rounding::RoundingMode=rounding(BigFloat)]; [precision::Integer=precision(BigFloat)])
188
245
@@ -283,17 +340,18 @@ function BigFloat(x::Float64, r::MPFRRoundingMode=rounding_raw(BigFloat); precis
283
340
nlimbs = (precision + 8 * Core. sizeof (Limb) - 1 ) ÷ (8 * Core. sizeof (Limb))
284
341
285
342
# Limb is a CLong which is a UInt32 on windows (thank M$) which makes this more complicated and slower.
343
+ zd = z. d
286
344
if Limb === UInt64
287
345
for i in 1 : nlimbs- 1
288
- unsafe_store! (z . d , 0x0 , i)
346
+ @inbounds setindex! (zd , 0x0 , i)
289
347
end
290
- unsafe_store! (z . d , val, nlimbs)
348
+ @inbounds setindex! (zd , val, nlimbs)
291
349
else
292
350
for i in 1 : nlimbs- 2
293
- unsafe_store! (z . d , 0x0 , i)
351
+ @inbounds setindex! (zd , 0x0 , i)
294
352
end
295
- unsafe_store! (z . d , val % UInt32, nlimbs- 1 )
296
- unsafe_store! (z . d , (val >> 32 ) % UInt32, nlimbs)
353
+ @inbounds setindex! (zd , val % UInt32, nlimbs- 1 )
354
+ @inbounds setindex! (zd , (val >> 32 ) % UInt32, nlimbs)
297
355
end
298
356
z
299
357
end
@@ -440,12 +498,12 @@ function to_ieee754(::Type{T}, x::BigFloat, rm) where {T<:AbstractFloat}
440
498
ret_u = if is_regular & ! rounds_to_inf & ! rounds_to_zero
441
499
if ! exp_is_huge_p
442
500
# significand
443
- v = RawBigInt {Limb} (x . _d, significand_limb_count (x))
501
+ v = x . d :: BigFloatData
444
502
len = max (ieee_precision + min (exp_diff, 0 ), 0 ):: Int
445
503
signif = truncated (U, v, len) & significand_mask (T)
446
504
447
505
# round up if necessary
448
- rh = RawBigIntRoundingIncrementHelper (v, len)
506
+ rh = BigFloatDataRoundingIncrementHelper (v, len)
449
507
incr = correct_rounding_requires_increment (rh, rm, sb)
450
508
451
509
# exponent
@@ -1193,10 +1251,8 @@ set_emin!(x) = check_exponent_err(ccall((:mpfr_set_emin, libmpfr), Cint, (Clong,
1193
1251
1194
1252
function Base. deepcopy_internal (x:: BigFloat , stackdict:: IdDict )
1195
1253
get! (stackdict, x) do
1196
- # d = copy(x._d)
1197
- d = x. _d
1198
- d′ = GC. @preserve d unsafe_string (pointer (d), sizeof (d)) # creates a definitely-new String
1199
- y = _BigFloat (x. prec, x. sign, x. exp, d′)
1254
+ d′ = copy (getfield (x, :d ))
1255
+ y = _BigFloat (d′)
1200
1256
# ccall((:mpfr_custom_move,libmpfr), Cvoid, (Ref{BigFloat}, Ptr{Limb}), y, d) # unnecessary
1201
1257
return y
1202
1258
end :: BigFloat
@@ -1210,7 +1266,8 @@ function decompose(x::BigFloat)::Tuple{BigInt, Int, Int}
1210
1266
s. size = cld (x. prec, 8 * sizeof (Limb)) # limbs
1211
1267
b = s. size * sizeof (Limb) # bytes
1212
1268
ccall ((:__gmpz_realloc2 , libgmp), Cvoid, (Ref{BigInt}, Culong), s, 8 b) # bits
1213
- memcpy (s. d, x. d, b)
1269
+ xd = x. d
1270
+ GC. @preserve xd memcpy (s. d, Base. unsafe_convert (Ptr{Limb}, xd), b)
1214
1271
s, x. exp - 8 b, x. sign
1215
1272
end
1216
1273
0 commit comments