You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在F# 5.0中从decimal变量指针创建Span<int>?

在F# 5.0中无分配访问decimal内部表示的实现方法

问题背景

用户在C#中可通过以下无分配方式获取decimal的内部结构:

decimal v = 123.456M;
            
var span = new ReadOnlySpan<int>(&v, 4);

var flags = span[0];
var hi32 = span[1];
var lo32 = span[2];
var mi32 = span[3];

需求是在F# 5.0中实现相同逻辑,用于移植.NET 7的Decimal.IsCanonical方法到.NET Framework 4.7.2,且要求避免使用会分配数组的Decimal.GetBits()方法(因为用于热路径)。

可行实现方案

F# 5.0支持通过不安全代码结合指针或Span<T>实现无分配访问,以下是两种可靠方案:

方案1:借助ReadOnlySpan

open System

let getDecimalBits (v: decimal) =
    unsafe {
        let ptr = &&v |> NativePtr.toVoidPtr
        let span = ReadOnlySpan<int>(ptr, 4)
        let flags = span[0]
        let hi32 = span[1]
        let lo32 = span[2]
        let mi32 = span[3]
        flags, hi32, lo32, mi32
    }

方案2:直接使用指针操作

open System

let getDecimalBits (v: decimal) =
    unsafe {
        fixed (decimal* p = &v) {
            let intPtr = p |> NativePtr.toVoidPtr :?> int*
            let flags = NativePtr.read intPtr
            let hi32 = NativePtr.read (NativePtr.add intPtr 1)
            let lo32 = NativePtr.read (NativePtr.add intPtr 2)
            let mi32 = NativePtr.read (NativePtr.add intPtr 3)
            flags, hi32, lo32, mi32
        }
    }

关键注意事项

  • 开启不安全代码:需在F#项目设置中勾选「允许不安全代码」,或编译时添加--unsafe参数。
  • 结构一致性:decimal的内部布局和C#完全一致,四个int的顺序对应标志位、高32位、低32位、中32位,可直接用于实现IsCanonical的校验逻辑。
  • 性能保障:两种方案均无堆分配,性能与C#实现持平,适合热路径场景。

内容的提问来源于stack exchange,提问作者Andrew Rybka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 05:01:40