OCaml的'lsr'和'asr'的等效F#位运算符是什么?

Mic*_*mas 4 f# ocaml bitwise-operators

我一直在研究Hash Array Mapped Tries的OCaml实现,并注意到使用了三个不同的位级运算符:

  • lsl: 左移
  • lsr:右转
  • asr:无符号右移

我想把它移植到F#,但我不确定F#位运算符的确切行为.

F#语言引用提供了两个按位运算符:

  • <<<: 左移
  • >>>:右转

我如何使用这些运算符来复制OCaml原件?

问候,

迈克尔

Jus*_*mer 6

检查运算符的实现<<<>>>解决方案的提示(https://github.com/Microsoft/visualfsharp/blob/fsharp4/src/fsharp/FSharp.Core/prim-types.fs)

let inline mask (n:int) (m:int) = (# "and" n m : int #)

[<NoDynamicInvocation>]
let inline (<<<) (x: ^T) (n:int) : ^T = 
     (^T: (static member (<<<) : ^T * int -> ^T) (x,n))
     when ^T : int32      = (# "shl" x (mask n 31) : int #)
     when ^T : uint32     = (# "shl" x (mask n 31) : uint32 #)
     when ^T : int64      = (# "shl" x (mask n 63) : int64 #)
     when ^T : uint64     = (# "shl" x (mask n 63) : uint64 #)
     when ^T : nativeint  = (# "shl" x n : nativeint #)
     when ^T : unativeint = (# "shl" x n : unativeint #)
     when ^T : int16      = (# "conv.i2" (# "shl" x (mask n 15) : int32  #) : int16 #)
     when ^T : uint16     = (# "conv.u2" (# "shl" x (mask n 15) : uint32 #) : uint16 #)
     when ^T : sbyte      = (# "conv.i1" (# "shl" x (mask n 7 ) : int32  #) : sbyte #)
     when ^T : byte       = (# "conv.u1" (# "shl" x (mask n 7 ) : uint32 #) : byte #)

[<NoDynamicInvocation>]
let inline (>>>) (x: ^T) (n:int) : ^T = 
     (^T: (static member (>>>) : ^T * int -> ^T) (x,n))
     when ^T : int32      = (# "shr"    x (mask n 31) : int32 #)
     when ^T : uint32     = (# "shr.un" x (mask n 31) : uint32 #)
     when ^T : int64      = (# "shr"    x (mask n 63) : int64 #)
     when ^T : uint64     = (# "shr.un" x (mask n 63) : uint64 #)
     when ^T : nativeint  = (# "shr"    x n : nativeint #)
     when ^T : unativeint = (# "shr.un" x n : unativeint #)
     when ^T : int16      = (# "conv.i2" (# "shr"    x (mask n 15) : int32  #) : int16 #)
     when ^T : uint16     = (# "conv.u2" (# "shr.un" x (mask n 15) : uint32 #) : uint16 #)
     when ^T : sbyte      = (# "conv.i1" (# "shr"    x (mask n 7 ) : int32  #) : sbyte #)
     when ^T : byte       = (# "conv.u1" (# "shr.un" x (mask n 7 ) : uint32 #) : byte #)
Run Code Online (Sandbox Code Playgroud)

此代码使用内联IL以及仅适用于F#devs的类型重载,但有趣的行似乎是:

when ^T : int32      = (# "shr"    x (mask n 31) : int32 #)
when ^T : uint32     = (# "shr.un" x (mask n 31) : uint32 #)
Run Code Online (Sandbox Code Playgroud)

要向右移动int32版本,然后使用shr(符号右移),对应于对应asruint32用途shr.un(无符号右移)lsr.

转换留下版本所有用途shl.

因此,int32潜在的解决方案可能是:

module ShiftOps =
    let inline ( lsl ) (x: int32) (n:int) : int32 = x <<< n
    let inline ( lsr ) (x: int32) (n:int) : int32 = int32 (uint32 x >>> n)
    let inline ( asr ) (x: int32) (n:int) : int32 = x >>> n

open ShiftOps

[<EntryPoint>]
let main argv = 
    printfn "0x%x" <| -1 lsr 4
    printfn "0x%x" <| -1 asr 4
    printfn "0x%x" <| -1 lsl 4

    0
Run Code Online (Sandbox Code Playgroud)