C# 等效于从现有数组的 .buffer 创建的 JavaScript TypedArray

C# equivalent of a javascript TypedArray created from an existing array's .buffer?

本文关键字:buffer 创建 JavaScript TypedArray 数组      更新时间:2023-09-26

我正在尝试将javascript函数转换为C#脚本。javascript版本所做的一件事是从现有的Float32Array的.buffer创建一个Uint32Array。

有谁知道在 C# 中会有什么等效物?我不是在谈论 C# 中的 Float32Array 和 Uint32Array 是什么,而是在谈论使用 dst 变量中的缓冲区初始化 javascript 类型数组的方式(请参阅代码)...https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray 这很重要,因为其他数组在此函数之后使用(例如)var dstUint32 = new Uint32Array(dst.buffer)...

这是代码(src 是一个现有的 Float32Array - 请参阅下面的一些初始值)...

compileClassifier = function(src, width, scale, dst) {
        width += 1;
        if (!dst) dst = new Float32Array(src.length);
        var dstUint32 = new Uint32Array(dst.buffer);
        dstUint32[0] = src[0];
        dstUint32[1] = src[1];
        var dstIndex = 1;
        for (var srcIndex = 1, iEnd = src.length - 1; srcIndex < iEnd; ) {
            dst[++dstIndex] = src[++srcIndex];
            var numComplexClassifiers = dstUint32[++dstIndex] = src[++srcIndex];
            for (var j = 0, jEnd = numComplexClassifiers; j < jEnd; ++j) {
                var tilted = dst[++dstIndex] = src[++srcIndex];
                var numFeaturesTimes3 = dstUint32[++dstIndex] = src[++srcIndex] * 3;
                if (tilted) {
                    for (var kEnd = dstIndex + numFeaturesTimes3; dstIndex < kEnd; ) {
                        dstUint32[++dstIndex] = src[++srcIndex] + src[++srcIndex] * width;
                        dstUint32[++dstIndex] = src[++srcIndex] * (width + 1) + ((src[++srcIndex] * (width - 1)) << 16);
                        dst[++dstIndex] = src[++srcIndex];
                    }
                } else {
                    for (var kEnd = dstIndex + numFeaturesTimes3; dstIndex < kEnd; ) {
                        dstUint32[++dstIndex] = src[++srcIndex] + src[++srcIndex] * width;
                        dstUint32[++dstIndex] = src[++srcIndex] + ((src[++srcIndex] * width) << 16);
                        dst[++dstIndex] = src[++srcIndex];
                    }
                }
                var inverseClassifierThreshold = 1 / src[++srcIndex];
                for (var k = 0; k < numFeaturesTimes3; ) {
                    dst[dstIndex - k] *= inverseClassifierThreshold;
                    k += 3;
                }
                if (inverseClassifierThreshold < 0) {
                    dst[dstIndex + 2] = src[++srcIndex];
                    dst[dstIndex + 1] = src[++srcIndex];
                    dstIndex += 2;
                } else {
                    dst[++dstIndex] = src[++srcIndex];
                    dst[++dstIndex] = src[++srcIndex];
                }
            }
        }
        dst = dst.subarray(0, dstIndex + 1);
        return dst;
    }

其中的 src 变量是从这里创建的(这是一个非常精简的版本,完整版本有数千个数字长):-

var classifier = [20,20,0.8226894140243530,3,0,2,3,7,14,4,-1.,3,9,14,2,2.,4.0141958743333817e-003,0.0337941907346249,0.8378106951713562,0,2,1,2,18,4,-1.,7,2,6,4,3.,0.0151513395830989,0.1514132022857666,0.7488812208175659,0,2,1,7,15,9,-1.,1,10,15,3,3.,4.2109931819140911e-003,0.0900492817163467,0.6374819874763489,6.9566087722778320,16,0,2,5,6,2,6,-1.,5,9,2,3,2.,1.6227109590545297e-003,0.0693085864186287];
src = new Float32Array(classifier);
这是分别在

控制台中记录的 dstUint32 和 dst 中将这些数字设置为 src 的内容(该函数不仅适用于这些数字,因为正如我所说,实际数组要长得多)有趣的是,几乎没有一个数字与原始数组匹配......

[20, 20, 1062378438, 3, 0, 6, 1641, 61341710, 3279494571, 2109, 30670862, 1140399531, 1024093127, 1062632131, 0, 6, 469, 61341714, 3263430756, 475, 61341702, 1128661142, 1041959952, 1061140142, 0, 6, 1639, 138018831, 3278731586, 2341, 46006287, 1144134386, 1035496386, 1059271173, 1088330890, 16, 0, 6, 1409, 92012546, 3290042412, 2111, 46006274, 1150947372, 1032712617, 4294967295, 4294967295, 0, 4294967295, 4294967295, 4294967295, 0, 4294967295, 4294967295, 4294967295, 0, 4294967295, 4294967295, 4294967295, 0, 4294967295, 4294967295, 4294967295, 0, 4294967295]

[2.802596928649634e-44, 2.802596928649634e-44, 0.822689414024353, 4.203895392974451e-45, 0, 8.407790785948902e-45, 2.2995307799570248e-42, 9.874165102541455e-37, -249.1158905029297, 2.955338461261039e-42, 7.787657921469055e-38, 498.2317810058594, 0.03379419073462486, 0.8378106951713562, 0, 8.407790785948902e-45, 6.572089797683392e-43, 9.874168689865524e-37, -66.00076293945312, 6.656167705542881e-43, 9.874157927893318e-37, 198.00228881835938, 0.1514132022857666, 0.7488812208175659, 0, 8.407790785948902e-45, 2.2967281830283752e-42, 5.597240788537616e-34, -237.47366333007812, 3.280439704984397e-42, 2.7918024463192472e-37, 712.4210205078125, 0.09004928171634674, 0.6374819874763489, 6.956608772277832, 2.2420775429197073e-44, 0, 8.407790785948902e-45, 1.9744295362336673e-42, 1.1848984491218286e-35, -616.252685546875, 2.958141058189689e-42, 2.7917995316184414e-37, 1232.50537109375, 0.06930858641862869, NaN, NaN, 0, NaN, NaN, NaN, 0, NaN, NaN, NaN, 0, NaN, NaN, NaN, 0, NaN, NaN, NaN, 0, NaN]

所以你可以在这里看到代码

dstUint32[0] = src[0];
dstUint32[1] = src[1];

似乎已将 dstUint32[0]/dstUint32[1] 和 dst[0]/dst[1] 设置为某些内容,只是在 dst[0]/dst[1] 中,该值被记录为 2.802596928649634e-44 而不是 20?

  • 相当于 js UInt32ArrayUInt32[]
  • 相当于 js Float32Arrayfloat[]
  • 相当于
  • ArrayBufferbyte[]

JavaScript 类型化数组是数组缓冲区的视图。因此,UInt32Array 中的元素不会强制转换为浮点数,而是将物理存储的内容(位)重新解释为浮点数。

若要在 C# 中执行此操作,您需要执行以下几件事之一。

如果您关心共享数组缓冲区

如果你关心共享数组缓冲区,即你需要在一个数组中进行更改以立即显示在另一个数组中,那么你需要实现整个事情。C# 不提供现成的功能。为了实现这一目标,您需要使用InteropServices.Marshal设施。这些将允许您访问底层内存。

如果你不关心共享数组缓冲区

如果您只想在一个方向上转换,那么也许稍后会再次转换回来,但您不需要立即显示更改,或者使用共享 ArrayBuffer,您可以更轻松地完成工作。

  • 创建一个内存流,
  • 从数组中写入 Float32 元素
  • 读取 UInt32 元素

像这样:

    static byte[] ReinterpretAsByteArray(UInt32[] a)
    {
        using (MemoryStream s = new MemoryStream())
        {
            using (BinaryWriter w = new BinaryWriter(s, Encoding.Unicode, true))
            {
                for (int i = 0; i < a.Length; i++)
                {
                    w.Write(a[i]);
                }
            }
            return s.ToArray();
        }
    }
    static float[] ReinterpretAsFloatArray(byte[] b) {
        using (MemoryStream s = new MemoryStream(b, false)) {
            using (BinaryReader r = new BinaryReader(s, Encoding.Unicode, true))
            {
                float[] f = new float[b.Length / 4]; // 4 = sizeof float
                for (int i = 0; i < b.Length; i++)
                {
                    f[i] = r.ReadSingle();
                }
                return f;
            }
        }
    }    

您将需要编写一个类似的函数来将字节数组转换为 Uint32 数组,并将浮点数组转换为字节数组,但这是更改两行的问题。