2017-10-07 16 views
1

BigFloatの数字をバイト形式で取得することに興味があります。私はデバッグできない非常に奇妙なエラーが発生します。私はエラーが現れる最小の例を提供します。Julia:BigFloatの整数部分を取得しようとすると不正確なエラーが発生する

function floatToBytes(x::BigFloat) 
    ret = zeros(UInt8, 4) 
    xs = significand(x)/2 
    b = UInt8(0) 
    for i = 1:4 
    xs *= 256 
    b = trunc(UInt8, xs) 
    ret[i] = b 
    xs -= b 
    end 
    return ret 
end 

println(floatToBytes(BigFloat(0.9921875001164153))) 
println(floatToBytes(BigFloat(0.9960937501164153))) 

これを実行すると、それはUInt8に255をオンにしたくないようだなど

UInt8[0xfe, 0x00, 0x00, 0x00] 
ERROR: LoadError: InexactError() 
Stacktrace: 
[1] trunc(::Type{UInt8}, ::BigFloat) at ./mpfr.jl:201 

あるとき、私は何を得ます。関数を定義することで問題を回避することができます。

function floatToBytes(x::BigFloat) 
    ret = zeros(UInt8, 4) 
    xs = significand(x)/2 
    b = UInt8(0) 
    for i = 1:4 
    xs *= 256 
    try 
     b = trunc(UInt8, xs) 
    catch 
     b = trunc(UInt8, xs-1)+UInt8(1) 
    end 
    ret[i] = b 
    xs -= b 
    end 
    return ret 
end 

これは非常に不満足です。ここで何が起こっているのですか?

+1

BigFloatでは 'trunc'のバグのようです。 '(typemin(T)<= x <= typemax(T))|| 'x'がtypemaxである255より大きいのでエラーを投げるthrow(InexactError(:trunc、T、x))'実際には、BigFloatで 'trunc'を実行してからTにキャストする必要があります(そして、typemaxのキャストチェックがあります)。あなたは問題を提出したいのですか(それともしますか)?コードは 'base/mpfr.jl:209'にあります –

+1

ああ、できますか? – tst

+1

もちろん、関数内で 'UInt8(trunc(BigFloat(0.9960937501164153)* 256))'や 'UInt8(trunc(xs))'を実行できます。私はこれを答えとして書くこともできます。 –

答えて

3

問題はBigFloatのtruncのバグのようです。現在のコードでは、xがtypemaxである255より大きいため、エラーをスローする(typemin(T) <= x <= typemax(T)) || throw(InexactError(:trunc, T, x))が問題になります。

実際にはBigFloatドメインでtruncを実行し、次にTにキャストする必要があります(また、typemaxのキャストチェックがあります)。私がこれに関する問題を開いた

:一方でhttps://github.com/JuliaLang/julia/issues/24041

、解決策は何をすることができます

UInt8(trunc(xs)) 

すなわちtrunc最初と後でキャスト。例:

julia> UInt8(trunc(BigFloat(0.9960937501164153)*256)) 
0xff 
関連する問題