How to avoid double conversion (byte [] to string for single) in .NET?

In a low latency HFT application, I have sockets receiving Byte[] messages containing stock market data.

The supplier price protocol contains Byte[] fields containing the ASCII sequence.
Those. the byte sequence [51-51-46-56] matches the ascii characters [3-3 -. -8], equal to the number 33.8.

Actually, while parsing the message, I convert Byte[] to a string, and then the string to Single / float.

Is there a way to avoid such a double conversion and convert directly Byte[] to single / float?
Secondly, is there a way to avoid using a string type that is inefficient in NET (prone to garbage collection of immutable garbage)?

Thank you in advance.

Yours faithfully

[edit January 2019]: this is the final solution, working flawlessly from 3 years:

 /// <summary> Read a Double precision float field in GL format from the stream and advances stream position of n (1 of field lenght flag + field lenght). </summary> /// <returns>-1 in case of error, Double precision floating point value ROUNDED TO 8 DECIMAL PLACES in case of success </returns> /// <param name="IniPos"> Initial Stream Position</param> public double ReadGLFieldAsDouble(long IniPos = -1) { // -- if (IniPos >= 0) Strm.Position = IniPos; int FLenght = Strm.ReadByte - 32; // case of "01000" SW Snapshot, field 7 doesn't exists, but in the message is a blank (32) // --early exit if (FLenght <= 0) return -1; // a blank field (byte 32) returns -1 if (Strm.Length - Strm.Position < FLenght) return -1; // -- double Dbl = 0; int Cpos = -1; int b = 0; int sign = 1; // --Builds as Integer with no point Separator for (int i = 0; i < FLenght ; i++) { b = Strm.ReadByte; switch (b) { case 45: // ASCII 45="-" sign { sign = -1; break; } case 46: // ASCII 46 is decimal point="." ; ASCII 44 is comma="," { Cpos = i; // decimal point position break; } default: { Dbl = Dbl * 10 + (b - 48); // increments as integer ASCII 48=0 break; } } } // --Transforms in floating point dividing by power of 10, multiplies by sign and returns if (Cpos != -1) Dbl = (Dbl / (Math.Pow(10, (FLenght - 1 - Cpos)))); return Math.Round(sign * Dbl, 8); } 
+5
source share
2 answers
  byte[] arr = new byte[] { 51, 51, 46, 56}; double res = 0, floatindex = 0.1; bool isFraction = false; for (int i = 0; i < arr.Length; i++) { if (arr[i] == 46) { isFraction = true; continue; } if (!isFraction) res = 10*res + arr[i] - 48; else { res += (arr[i] - 48)*floatindex; floatindex /= 10.0; } } return res; 

From a cultural point of view, it is assumed that you always have a “dot” to indicate decimal separation (and not coma, for example, in French culture)

+6
source

It is possible. Assuming you know that the format is always like this (digits, comma, and decimal):

float v = 0.1f * (100.0f * (buf [0] - 48) + 10 * (buf [1] - 48) + (buf [3] - 48));

or: float v = 0.1f * (100.0f * buf [0] + 10 * buf [1] + buf [3] - 4800 - 480 - 48);

+1
source

All Articles