【问题标题】:Which is the fastest way to convert an integer to a byte array in Julia这是在Julia中将整数转换为字节数组的最快方法
【发布时间】:2022-01-20 06:26:56
【问题描述】:

问题1:将整数转换为字节数组最快的方法是什么?

a = 1026
aHexStr = string(a,base = 16,pad = 4) #2 bytes, 4 chars
b = zeros(UInt8,2)
k = 1
for i in 1:2:4
  b[k] = parse(UInt8,aHexStr[i:i+1],base = 16)
  k += 1
end

这种方法最快吗?

相关问题2: 将十六进制字符串转换为字节数组的最快方法是什么?

我有一串十六进制数字

a = "ABCDEF12345678"

How can I convert this hex string to byte array?

b = zeros(UInt8,7)
k = 1
for i in 1:2:14
  b[k] = parse(UInt8,a[i:i+1],base = 16)
  k += 1
end

这种方法最快吗?

【问题讨论】:

    标签: arrays parsing integer julia hex


    【解决方案1】:

    对于第一个问题,如果您对额外的 0 值没问题,您可以 reinterpret 字节:reinterpret(UInt8, [a])。 这比 Bogumił Kamiński 答案中的代码略快 5-10% - 但相差几纳秒。因此,如果额外的 0 很麻烦,那可能就不值得了。

    编辑:您可以通过以下方式删除多余的零:

    julia> bytesfromint(i::Int64) =
             @inbounds @view reinterpret(UInt8, [i])[1:8-leading_zeros(i)>>3]
    

    这似乎也比 Bogumil Kaminsky 的回答中提到的方法快了 20% 左右。

    @inbounds @view reinterpret(UInt8, [ai])[(8-leading_zeros(ai)>>3):-1:1] 将首先为您提供最重要的字节(类似大端),或者@inbounds @view reinterpret(UInt8, [ai])[2:-1:1] 如果您知道您的数据将只占用 2 个字节。

    (@view 告诉 Julia 不要复制我们要求的数组部分,而是索引到原始数组本身 - 从而避免复制开销。@inbounds 向 Julia 保证我们的索引在数组的边界——因此避免了边界检查开销。)

    【讨论】:

    • 我同意 - 这也是我通常会推荐的(但在最初的问题中,这些 0s 被删除了)。
    • reverse(reinterpret(UInt8, [a])[1:2]) 将为大端完成这项工作。
    • @Vinod 查看我的编辑。我提到的最后一个代码段(带有[2:-1:1] 索引)比调用reverse 运行得更快。
    【解决方案2】:

    对于第一个操作,我假设您只想保留整数中设置的字节数,因此您可以这样做:

    julia> a = 1026
    1026
    
    julia> [(a>>((i-1)<<3))%UInt8 for i in 1:sizeof(a)-leading_zeros(a)>>3]
    2-element Vector{UInt8}:
     0x02
     0x04
    

    解释:

    • leading_zeros(a) 获取以a 开头的零位数
    • leading_zeros(a)&gt;&gt;3 计算完全空的字节数(&gt;&gt;3 将数字右移3 位;在这种情况下,地板除以 8)
    • sizeof(a)-leading_zeros(a)&gt;&gt;3 计算要转换的字节数
    • (i-1)&lt;&lt;3) 计算我们需要移动索引的位数(在本例中为 i-1 乘以 8)
    • (a&gt;&gt;((i-1)&lt;&lt;3))%UInt8 获取ai-1th 字节

    对于第二个操作,我假设如果您有奇数个字符,我们会用 0 位 + 填充最后一个字节的剩余部分,我们不需要检查传递的数据是否有效:

    julia> a = "ABCDEF12345678"
    "ABCDEF12345678"
    
    julia> function s2b(a::String)
               b = zeros(UInt8, (sizeof(a) + 1) >> 1)
               for (i, c) in enumerate(codeunits(a))
                   b[(i+1)>>1] |= (c - (c < 0x40 ? 0x30 : 0x37))<<(isodd(i)<<2)
               end
               return b
           end
    s2b (generic function with 1 method)
    
    julia> s2b(a)
    7-element Vector{UInt8}:
     0xab
     0xcd
     0xef
     0x12
     0x34
     0x56
     0x78
    

    这两种方法都应该很快,但很难保证它们是最快的。


    编辑

    基准测试:

    julia> function f1(a)
               aHexStr = string(a,base = 16,pad = 4) #2 bytes, 4 chars
               b = zeros(UInt8,2)
                   k = 1
               for i in 1:2:4
                   b[k] = parse(UInt8,aHexStr[i:i+1],base = 16)
                   k += 1
               end
               return b
           end
    f1 (generic function with 1 method)
    
    julia> f2(a) = [(a>>((i-1)<<3))%UInt8 for i in 1:sizeof(a)-leading_zeros(a)>>3]
    f2 (generic function with 1 method)
    
    julia> using BenchmarkTools
    
    julia> a = 1026
    1026
    
    julia> @btime f1($a)
      141.795 ns (5 allocations: 224 bytes)
    2-element Vector{UInt8}:
     0x04
     0x02
    
    julia> @btime f2($a)
      29.317 ns (1 allocation: 64 bytes)
    2-element Vector{UInt8}:
     0x02
     0x04
    
    julia> function s2b(a::String)
               b = zeros(UInt8, (sizeof(a) + 1) >> 1)
               for (i, c) in enumerate(codeunits(a))
                   b[(i+1)>>1] |= (c - (c < 0x40 ? 0x30 : 0x37))<<(isodd(i)<<2)
               end
               return b
           end
    s2b (generic function with 1 method)
    
    julia> a = "ABCDEF12345678"
    "ABCDEF12345678"
    
    julia> @btime hex2bytes($a)
      50.000 ns (1 allocation: 64 bytes)
    7-element Vector{UInt8}:
     0xab
     0xcd
     0xef
     0x12
     0x34
     0x56
     0x78
    
    julia> @btime s2b($a)
      48.830 ns (1 allocation: 64 bytes)
    7-element Vector{UInt8}:
     0xab
     0xcd
     0xef
     0x12
     0x34
     0x56
     0x78
    

    正如@SundarR 在后一种情况下评论的那样,应该使用hex2bytes。我忘记了它的存在。

    【讨论】:

    • ``` julia> a = 1026 1026 julia> [(a>>((i-1)>3] 2-element Vector{UInt8}: 0x02 0x04 ``` 这个方法比问题中提供的解决方案要慢。
    • 方法 s2b 比我的问题中给出的代码要快。
    • @Vinod 你是用@btime 还是@time 来衡量时间?使用@btime,答案中的方法比问题中的方法运行速度大约快 4 倍。
    • 我正在使用@elapsed begin end 语法
    • 顺便说一句,Base 中有一个 hex2bytes 函数用于第二个问题,但它的运行速度比这里的慢四到五倍。我的猜测是,区别在于为安全付出的代价——hex2bytes 检查字符串的长度是偶数,并且不假设字符都是有效的十六进制——但它可能值得研究。
    猜你喜欢
    • 1970-01-01
    • 2013-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-16
    • 2011-05-18
    • 2010-09-19
    • 1970-01-01
    相关资源
    最近更新 更多