I am trying to convert a javascript function to a C# script. One of the things the javascript version does is create a Uint32Array from an existing Float32Array's .buffer
Does anyone know what the equivalent of this would be in C#? I am NOT talking about what Float32Array and Uint32Array are in C# I am talking about the way that the javascript typed array gets initialized using the buffer from the dst variable (see code)... https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray Its important because other arrays get initialized later on after this function using (for example) var dstUint32 = new Uint32Array(dst.buffer)...
This is the code (src is an existing Float32Array - see a bit of the initial values for this below)...
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;
}
The src variable in there is created from this (this is a very cut down version the full version is thousands of numbers long):-
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);
This is what gets logged in the console for dstUint32 and dst respectively with those numbers set as src (the function doesn't work with just those numbers since as I say the actual array is far, far longer) Its interesting that almost none of the numbers match the original array...
[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]
So you can see here that the code
dstUint32[0] = src[0];
dstUint32[1] = src[1];
appears to have set BOTH dstUint32[0]/dstUint32[1] AND dst[0]/dst[1] to something, just that in dst[0]/dst[1] the value is getting logged as 2.802596928649634e-44 rather than 20?
UInt32Array
is UInt32[]
.Float32Array
is float[]
.ArrayBuffer
is byte[]
.JavaScript typed arrays are views onto the array buffer. Thus the element in the UInt32Array is not cast to a float, rather the contents of the physical storage - the bits - are reinterpreted as a float.
To do this in C# you need to do one of a couple of things.
If you care about sharing the arraybuffer
If you care about sharing the arraybuffer, i.e. you need change in one array to show up in the other array immediately, then you need to implement the whole thing. C# doesn't offer this out of the box. In order to achieve it you will need to use the InteropServices.Marshal
facilities. These will allow you to get access to the underlying memory.
If you don't care about sharing the arraybuffer
If you just want to convert in one direction, then maybe later convert back again, but you don't need changes to be visible immediately, or to use a shared ArrayBuffer, you have an easier job.
Something like this:
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;
}
}
}
You will need to write a similar function to convert a byte array to a Uint32 array, and to convert a float array to a byte array, but that is a matter of changing two lines.