@@ -18,12 +18,10 @@ import
1818 setrounding, maxintfloat, widen, significand, frexp, tryparse, iszero,
1919 isone, big, _string_n, decompose, minmax, _precision_with_base_2,
2020 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
2422
2523using . Base. Libc
26- import .. Rounding:
24+ import .. Rounding: Rounding,
2725 rounding_raw, setrounding_raw, rounds_to_nearest, rounds_away_from_zero,
2826 tie_breaker_is_to_even, correct_rounding_requires_increment
2927
3937 const libmpfr = " libmpfr.so.6"
4038end
4139
42-
4340version () = VersionNumber (unsafe_string (ccall ((:mpfr_get_version ,libmpfr), Ptr{Cchar}, ())))
4441patches () = split (unsafe_string (ccall ((:mpfr_get_patches ,libmpfr), Ptr{Cchar}, ())),' ' )
4542
@@ -120,69 +117,129 @@ const mpfr_special_exponent_zero = typemin(Clong) + true
120117const mpfr_special_exponent_nan = mpfr_special_exponent_zero + true
121118const mpfr_special_exponent_inf = mpfr_special_exponent_nan + true
122119
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+
123135"""
124136 BigFloat <: AbstractFloat
125137
126138Arbitrary precision floating point number type.
127139"""
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}
135142
136143 # Not recommended for general use:
137144 # 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)
147146
148147 function BigFloat (; precision:: Integer = _precision_with_base_2 (BigFloat))
149148 precision < 1 && throw (DomainError (precision, " `precision` cannot be less than 1." ))
150149 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
156161 end
157162end
158163
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" )
161230
162231rounding_raw (:: Type{BigFloat} ) = something (Base. ScopedValues. get (CURRENT_ROUNDING_MODE), ROUNDING_MODE[])
163232setrounding_raw (:: Type{BigFloat} , r:: MPFRRoundingMode ) = ROUNDING_MODE[]= r
164233function setrounding_raw (f:: Function , :: Type{BigFloat} , r:: MPFRRoundingMode )
165234 Base. ScopedValues. @with (CURRENT_ROUNDING_MODE => r, f ())
166235end
167236
168-
169237rounding (:: Type{BigFloat} ) = convert (RoundingMode, rounding_raw (BigFloat))
170238setrounding (:: Type{BigFloat} , r:: RoundingMode ) = setrounding_raw (BigFloat, convert (MPFRRoundingMode, r))
171239setrounding (f:: Function , :: Type{BigFloat} , r:: RoundingMode ) =
172240 setrounding_raw (f, BigFloat, convert (MPFRRoundingMode, r))
173241
174242
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-
186243"""
187244 BigFloat(x::Union{Real, AbstractString} [, rounding::RoundingMode=rounding(BigFloat)]; [precision::Integer=precision(BigFloat)])
188245
@@ -283,17 +340,18 @@ function BigFloat(x::Float64, r::MPFRRoundingMode=rounding_raw(BigFloat); precis
283340 nlimbs = (precision + 8 * Core. sizeof (Limb) - 1 ) ÷ (8 * Core. sizeof (Limb))
284341
285342 # Limb is a CLong which is a UInt32 on windows (thank M$) which makes this more complicated and slower.
343+ zd = z. d
286344 if Limb === UInt64
287345 for i in 1 : nlimbs- 1
288- unsafe_store! (z . d , 0x0 , i)
346+ @inbounds setindex! (zd , 0x0 , i)
289347 end
290- unsafe_store! (z . d , val, nlimbs)
348+ @inbounds setindex! (zd , val, nlimbs)
291349 else
292350 for i in 1 : nlimbs- 2
293- unsafe_store! (z . d , 0x0 , i)
351+ @inbounds setindex! (zd , 0x0 , i)
294352 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)
297355 end
298356 z
299357end
@@ -440,12 +498,12 @@ function to_ieee754(::Type{T}, x::BigFloat, rm) where {T<:AbstractFloat}
440498 ret_u = if is_regular & ! rounds_to_inf & ! rounds_to_zero
441499 if ! exp_is_huge_p
442500 # significand
443- v = RawBigInt {Limb} (x . _d, significand_limb_count (x))
501+ v = x . d :: BigFloatData
444502 len = max (ieee_precision + min (exp_diff, 0 ), 0 ):: Int
445503 signif = truncated (U, v, len) & significand_mask (T)
446504
447505 # round up if necessary
448- rh = RawBigIntRoundingIncrementHelper (v, len)
506+ rh = BigFloatDataRoundingIncrementHelper (v, len)
449507 incr = correct_rounding_requires_increment (rh, rm, sb)
450508
451509 # exponent
@@ -1193,10 +1251,8 @@ set_emin!(x) = check_exponent_err(ccall((:mpfr_set_emin, libmpfr), Cint, (Clong,
11931251
11941252function Base. deepcopy_internal (x:: BigFloat , stackdict:: IdDict )
11951253 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′)
12001256 # ccall((:mpfr_custom_move,libmpfr), Cvoid, (Ref{BigFloat}, Ptr{Limb}), y, d) # unnecessary
12011257 return y
12021258 end :: BigFloat
@@ -1210,7 +1266,8 @@ function decompose(x::BigFloat)::Tuple{BigInt, Int, Int}
12101266 s. size = cld (x. prec, 8 * sizeof (Limb)) # limbs
12111267 b = s. size * sizeof (Limb) # bytes
12121268 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)
12141271 s, x. exp - 8 b, x. sign
12151272end
12161273
0 commit comments