我想得到一个BigFloat数的二进制数。我认为最简单的方法是将数字转换为字节数组。在this question中,有一种用于Float64的方法,但是当我对BigFloat进行同样的尝试时,它告诉我写没有一个用于BigFloat的方法。
我怎么能和朱莉娅做这件事?
PS。我知道有一种方法可以将二进制数字作为字符串,但是这会带来巨大的开销,我希望避免它。
发布于 2017-10-06 16:56:06
序列化或表示BigFloats很棘手,因为:a. BigFloat结构使用指针,而b.指向缓冲区是由包装在Julia中的外部库控制的。
因此,作为第一步,这里有一些函数可以以准确和易于操作的方式对BigFloat进行文本格式化:
# numbits(a) returns the number of significant digits in a BigFloat
# including digits both left and right of floating point.
# For example:
# julia> numbits(BigFloat(3/8)
# 2
#
# This is the trickiest function since it looks slightly into
# the internal representation in GMP of BigInt data.
function numbits(a::BigFloat)
n = a.prec
for i=1:(a.prec>>count_ones(sizeof(Base.GMP.Limb)*8-1))
tz = trailing_zeros(unsafe_load(a.d,i))
n -= tz
if tz < sizeof(Base.GMP.Limb)*8
break
end
end
return n
end# mantissarep(a) returns a tuple with two elements. The first element is a BigInt
# holding all the significant bits of a BigFloat, and the second holds
# the exponent needed to return the floating point to its position.
# Thus, as an example, the following holds:
# julia> a = BigFloat(1.1)
# 1.100000000000000088817841...
#
# julia> mantissarep(a)
# (2476979795053773, 51)
#
# julia> big"2476979795053773"/big"2"^51 == a
# true
#
mantissarep(a::BigFloat) = (BigInt(a*BigFloat(2)^(numbits(a)-a.exp)),
numbits(a)-a.exp)# bigfloattext(a) returns an easy textual representation of a BigFloat
function bigfloattext(bf::BigFloat)
(a,b) = mantissarep(bf)
return "$(sign(a)==-1 ? "-" : "")big\"$(dec(abs(a)))\"/big\"2\"^$(b)"
end# bigfloatbintext(a) returns an easy binary textual representation a BigFloat
function bigfloatbintext(bf::BigFloat)
(a,b) = mantissarep(bf)
return "$(sign(a)==-1 ? "-" : "")big\"0b$(bin(abs(a)))\"/big\"2\"^0b$(bin(b))"
end有了这些函数,序列化BigFloat的一种方法就是编写bigfloattext的字符串输出。这种方法不太紧凑,但反序列化(可以使用parse方法用于BigFloats )很容易,而且比较清晰。为了进行更紧凑的序列化,可以编写mantissarep的字节和BigFloat的精度字段。这将使这个答案稍微长一点,所以如果有要求,我会添加。
例如,编写:
julia> a = sin(BigFloat(π)/3) # calculate some BigFloat
8.660254037844386467637231707529361834714026269051903140279034897259665084543988e-01
julia> println(bigfloattext(a)) # represent it as a string
big"100278890836790510567389408543623384672710501789331344711007167057270294106993"/big"2"^256
julia> # show representation is faithful
julia> big"100278890836790510567389408543623384672710501789331344711007167057270294106993"/big"2"^256 == a
true请注意(对于其他答案)编写d字段(= BigFloat字段)是非常无用的,可能会导致内存损坏。
UPDATE:在海报下面的注释的指导下,下面是几个将BigFloat转换为字节表示的函数:
function BigFloat2Bytes(bf::BigFloat)
bf2 = bf/big"2"^exponent(bf)-1.0
bvec = Vector{UInt8}()
push!(bvec,0x01)
while bf2 != 0.0
bf2 *= 256
b = trunc(Int, bf2)
push!(bvec, UInt8(b))
bf2 -= b
end
return (bvec, exponent(bf))
end
function Bytes2BigFloat(bvec, e)
bf = zero(BigInt)
for b in bvec
bf = bf*256 + b
end
return BigFloat(bf*BigFloat(2)^(e-8*length(bvec)+8))
end有了这些,我们就有:
julia> a = BigFloat(123.2323)
1.23232299999999995065991242881...e+02
julia> BigFloat2Bytes(a)
(UInt8[0x01, 0xec, 0xed, 0xe0, 0x0d, 0x1b, 0x71, 0x70], 6)
julia> Bytes2BigFloat(BigFloat2Bytes(a)...)
1.23232299999999995065991242881...e+02
julia> Bytes2BigFloat(BigFloat2Bytes(a)...) == a
true发布于 2017-10-06 23:07:51
我正试着用别的方法。我不确定我做得对不对!但也许这是有趣的。:)
我们可能通过使用负责BigFloat (MPFR)的库获得最小的开销。因此,我试图调用mpfr_sprintf (http://www.mpfr.org/mpfr-current/mpfr.html#Formatted-Output-Functions)来获取BigFloat的十六进制和二进制表示:
julia> begin
a = " "^1000 # this could be not enough!
f = BigFloat(123.2323)
ccall(
(:mpfr_sprintf, :libmpfr),
Int64,
(Cstring, Cstring, Ref{BigFloat}...),
a,
"%Rb\n%Ra",
Ref(f), Ref(f))
res_bin = a[1:search(a, '\n')-1]
res_hex = a[search(a, '\n')+1:search(a, '\0')-1]
println(res_bin)
println(res_hex)
println(f == BigFloat(res_hex))
end
1.1110110011101101111000000000110100011011011100010111p+6
0x7.b3b780346dc5cp+4
true我是不是错过了更好的Julia (而不是ccall)到mpfr_sprintf (和其他函数)在BigFloat附近的某个地方呢?
编辑:对tst的一些解释。
对不起,我想我的答案不是你的主要问题,因为它是关于转换为字符串。
BigFloat是基于MPFR库的。它具有mpfr_sprintf函数,可以将输出格式化为string。例如,"%Ra“是mpfr_t类型的十六进制输出的格式字符串(Ref(BigFloat)是这种类型的引用)。朱莉娅善于调用c-库.所以你可以打电话给mpfr_sprintf。我显示了二进制和十六进制输出。输出为空结束字符串,因此我需要从结果中解析它。res_hex值-> "0x7.b3b780346dc5cp+4“的内容,可以用于REPL或代码-它支持十六进制浮点格式:
julia> 0x7.b3b780346dc5cp+4
123.2323
julia> typeof(0x7.b3b780346dc5cp+4)
Float64 p+4在它中的意思是“二元指数”(BTW.0x7b == 123 (来自BigFloat(123.2323))
你可以重写丹对十六进制浮点表示->的回答的结果
# [0x01, 0xec, 0xed, 0xe0, 0x0d, 0x1b, 0x71, 0x70], 6) ->
julia> 0x1.ecede00d1b7170p+6
123.2323和BTW python具有十六进制函数返回十六进制表示-> https://pythonhosted.org/bigfloat/reference/index.html#bigfloat.BigFloat.hex。
发布于 2021-07-14 19:34:17
Dan(编辑)的答案看起来比我的更有力,但是对于序列化来说还是有点尴尬。
仅供参考,这里有一个快速而肮脏的答案,我用来从BigFloat到Vector{UInt8}
function unsafe_serialize(p::BigFloat)
vcat(
reinterpret(UInt8, [p.prec]),
reinterpret(UInt8, [p.sign]),
reinterpret(UInt8, [p.exp]),
reinterpret(UInt8, unsafe_wrap(Array, p.d, (4,)))
)
end来回
function unsafe_deserialize(::Type{BigFloat}, p::Array{UInt8})
Base.MPFR._BigFloat(
reinterpret(Int64, p[1:8])[1],
reinterpret(Int32, p[9:12])[1],
reinterpret(Int64, p[13:20])[1],
String(p[21:52])
)
end它们脏的原因是我对数字和类型进行了硬编码。在第一个函数中,4假设您的机器对C类型使用了Int64,并且您已经保持了默认的精度(或者稍微降低了一点)。在第二种情况下,每种Int*类型和相应的范围都与机器有关,而最终的范围取决于精度。这些可能通过实际使用正确的大小和类型来改进,但我太懒了。
我知道这些工作在我的机器上的默认精度,并可能会工作在大多数安装,但你的里程可能会变化(直接到分段故障),如果你有一些非标准的机器。
https://stackoverflow.com/questions/46604972
复制相似问题