mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-19 20:39:01 +00:00
- Fixed typos on DoubleTest - Restored GetNumberString() as it was on my commit of the end of August
494 lines
16 KiB
C#
494 lines
16 KiB
C#
//#define COSMOSDEBUG
|
|
|
|
using System;
|
|
using Cosmos.Debug.Kernel;
|
|
|
|
namespace Cosmos.Common
|
|
{
|
|
public static class StringHelper
|
|
{
|
|
private static Debugger mDebugger = new Debugger("Common", "StringHelper");
|
|
|
|
internal enum StringComparisonResultEnum
|
|
{
|
|
Less = -1,
|
|
|
|
Equal = 0,
|
|
|
|
Greater = 1
|
|
}
|
|
|
|
public static string GetNumberString(uint aValue)
|
|
{
|
|
mDebugger.SendInternal("StringHelper.GetNumberString(uint)");
|
|
|
|
string[] xChars = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
|
string xResult = string.Empty;
|
|
|
|
if (aValue == 0)
|
|
{
|
|
xResult = "0";
|
|
}
|
|
else
|
|
{
|
|
uint xValue = aValue;
|
|
while (xValue > 0)
|
|
{
|
|
uint xValue2 = xValue % 10;
|
|
xResult = string.Concat(xChars[xValue2], xResult);
|
|
xValue /= 10;
|
|
}
|
|
}
|
|
|
|
return xResult;
|
|
}
|
|
|
|
public static string GetNumberString(int aValue)
|
|
{
|
|
mDebugger.SendInternal("StringHelper.GetNumberString(int)");
|
|
|
|
string[] xChars = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
|
string xResult = string.Empty;
|
|
|
|
if (aValue == 0)
|
|
{
|
|
xResult = "0";
|
|
}
|
|
else
|
|
{
|
|
int xValue = aValue;
|
|
|
|
if (aValue < 0)
|
|
{
|
|
xValue *= -1;
|
|
}
|
|
|
|
while (xValue > 0)
|
|
{
|
|
int xValue2 = xValue % 10;
|
|
xResult = string.Concat(xChars[xValue2], xResult);
|
|
xValue /= 10;
|
|
}
|
|
}
|
|
|
|
if (aValue < 0)
|
|
{
|
|
xResult = string.Concat("-", xResult);
|
|
}
|
|
|
|
return xResult;
|
|
}
|
|
|
|
public static string GetNumberString(ulong aValue)
|
|
{
|
|
mDebugger.SendInternal("StringHelper.GetNumberString(ulong)");
|
|
|
|
string[] xChars = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
|
string xResult = string.Empty;
|
|
|
|
if (aValue == 0)
|
|
{
|
|
xResult = "0";
|
|
mDebugger.SendInternal("xResult =");
|
|
mDebugger.SendInternal(xResult);
|
|
}
|
|
else
|
|
{
|
|
ulong xValue = aValue;
|
|
mDebugger.SendInternal("xValue =");
|
|
mDebugger.SendInternal(xValue);
|
|
while (xValue > 0)
|
|
{
|
|
ulong xValue2 = xValue % 10;
|
|
mDebugger.SendInternal("xValue2 =");
|
|
mDebugger.SendInternal(xValue2);
|
|
xResult = string.Concat(xChars[xValue2], xResult);
|
|
mDebugger.SendInternal("xResult =");
|
|
mDebugger.SendInternal(xResult);
|
|
xValue /= 10;
|
|
mDebugger.SendInternal("xValue =");
|
|
mDebugger.SendInternal(xValue);
|
|
}
|
|
}
|
|
|
|
mDebugger.SendInternal("xResult =");
|
|
mDebugger.SendInternal(xResult);
|
|
return xResult;
|
|
}
|
|
|
|
public static string GetNumberString(long aValue)
|
|
{
|
|
mDebugger.SendInternal("StringHelper.GetNumberString(long)");
|
|
|
|
string[] xChars = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
|
string xResult = string.Empty;
|
|
long xValue = aValue;
|
|
|
|
if (aValue == 0)
|
|
{
|
|
xResult = "0";
|
|
mDebugger.SendInternal("xResult =");
|
|
mDebugger.SendInternal(xResult);
|
|
}
|
|
else
|
|
{
|
|
if (aValue < 0)
|
|
{
|
|
xValue *= -1;
|
|
}
|
|
|
|
mDebugger.SendInternal("xValue =");
|
|
mDebugger.SendInternal(xValue);
|
|
while (xValue > 0)
|
|
{
|
|
long xValue2 = xValue % 10;
|
|
mDebugger.SendInternal("xValue2 =");
|
|
mDebugger.SendInternal(xValue2);
|
|
xResult = string.Concat(xChars[xValue2], xResult);
|
|
mDebugger.SendInternal("xResult =");
|
|
mDebugger.SendInternal(xResult);
|
|
xValue /= 10;
|
|
mDebugger.SendInternal("xValue =");
|
|
mDebugger.SendInternal(xValue);
|
|
}
|
|
}
|
|
|
|
if (aValue < 0)
|
|
{
|
|
xResult = string.Concat("-", xResult);
|
|
}
|
|
|
|
mDebugger.SendInternal("xResult =");
|
|
mDebugger.SendInternal(xResult);
|
|
return xResult;
|
|
}
|
|
|
|
/*
|
|
* This implementation could only print values which integer part is < ULONG_MAX, the only solution would have been to use BigInteger but then
|
|
* I'd have an analogous problem: to plug BigInteger.ToString() and I don't know how many other things.
|
|
* We will retain this code for now it is OK for debug purposes and big value should be printed in scientific notation to be readable anyway...
|
|
*/
|
|
public static string GetNumberString(float aValue)
|
|
{
|
|
mDebugger.SendInternal("StringHelper.GetNumberString(float)");
|
|
|
|
var singleBytes = BitConverter.GetBytes(aValue);
|
|
int hexVal = BitConverter.ToInt32(singleBytes, 0);
|
|
|
|
/* Let's extract the parts that compose our single: sign, exponent and mantissa */
|
|
bool isNeg = (hexVal >> 31) != 0;
|
|
int exp = ((hexVal >> 23) & 0xFF);
|
|
ulong mantissa = (ulong)(hexVal & 0x7FFFFF);
|
|
|
|
ulong intPart = 0, fracPart = 0;
|
|
|
|
/* First we handle the special cases INF, NaN, 0 and denormalized float */
|
|
switch (exp)
|
|
{
|
|
/*
|
|
* INF or NaN?
|
|
*/
|
|
case 0xFF:
|
|
if (mantissa == 0)
|
|
{
|
|
if (isNeg)
|
|
return "-∞";
|
|
else
|
|
return "∞";
|
|
}
|
|
else
|
|
/* It could exist -NaN but this is always printed as NaN */
|
|
return "NaN";
|
|
|
|
/* 0 or denormalized float? */
|
|
case 0x00:
|
|
if (mantissa == 0)
|
|
return "0";
|
|
/* Denormalized float have always exp -126 */
|
|
else
|
|
exp = -126;
|
|
break;
|
|
|
|
/* Normalized float the exponent is unbiased and the implicit leading one is placed in the mantissa */
|
|
default:
|
|
exp -= 127;
|
|
mantissa |= 0x800000;
|
|
break;
|
|
}
|
|
|
|
if (exp >= 23)
|
|
{
|
|
intPart = mantissa << (exp - 23);
|
|
}
|
|
else if (exp >= 0)
|
|
{
|
|
intPart = mantissa >> (23 - exp);
|
|
fracPart = (mantissa << (exp + 1)) & 0xFFFFFF;
|
|
}
|
|
else
|
|
{
|
|
fracPart = (mantissa & 0xFFFFFF) >> (-(exp + 1));
|
|
}
|
|
|
|
string result = "";
|
|
|
|
if (isNeg)
|
|
{
|
|
result += "-";
|
|
}
|
|
|
|
result += intPart.ToString();
|
|
int usedDigits = intPart.ToString().Length;
|
|
if (fracPart == 0)
|
|
{
|
|
return result;
|
|
}
|
|
result += ".";
|
|
|
|
if (usedDigits >= 7)
|
|
{
|
|
usedDigits = 6;
|
|
}
|
|
for (int m = usedDigits; m < 7; m++)
|
|
{
|
|
fracPart = (fracPart << 3) + (fracPart << 1);
|
|
|
|
char p = (char)((fracPart >> 24) + '0');
|
|
result += p;
|
|
|
|
fracPart &= 0xFFFFFF;
|
|
}
|
|
fracPart = (fracPart << 3) + (fracPart << 1);
|
|
char remain = (char)((fracPart >> 24) + '0');
|
|
if ((remain > '5') && (result[result.Length - 1] > '0'))
|
|
{
|
|
char[] answer = result.ToCharArray();
|
|
int digitPos = answer.Length - 1;
|
|
char digit = result[digitPos];
|
|
answer[digitPos] = (char)(digit + 1);
|
|
while (answer[digitPos] > '9')
|
|
{
|
|
answer[digitPos] = '0';
|
|
digitPos--;
|
|
digit = result[digitPos];
|
|
if (digit == '.')
|
|
{
|
|
digitPos--;
|
|
digit = result[digitPos];
|
|
}
|
|
answer[digitPos] = (char)(digit + 1);
|
|
}
|
|
|
|
result = new string(answer);
|
|
}
|
|
|
|
while (result[result.Length - 1] == '0')
|
|
{
|
|
result = result.Substring(0, result.Length - 1);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* This implementation could only print values which integer part is < ULONG_MAX, the only solution would have been to use BigInteger but then
|
|
* I'd have an analogous problem: to plug BigInteger.ToString() and I don't know how many other things.
|
|
* We will retain this code for now it is OK for debug purposes and big value should be printed in scientific notation to be readable anyway...
|
|
*/
|
|
public static string GetNumberString(double aValue)
|
|
{
|
|
mDebugger.SendInternal("StringHelper.GetNumberString(double)");
|
|
mDebugger.SendInternal("aValue = ");
|
|
mDebugger.SendInternal(aValue);
|
|
|
|
long hexVal = BitConverter.DoubleToInt64Bits(aValue);
|
|
mDebugger.SendInternal("hexVal = ");
|
|
mDebugger.SendInternal(hexVal);
|
|
|
|
/* Let's extract the parts that compose our double: sign, exponent and mantissa */
|
|
bool isNeg = (hexVal >> 63) != 0;
|
|
int exp = (int)((hexVal >> 52) & 0x07FF);
|
|
ulong mantissa = (ulong)(hexVal & 0x0FFFFFFFFFFFFF);
|
|
mDebugger.SendInternal("isNeg = ");
|
|
mDebugger.SendInternal(isNeg.ToString());
|
|
mDebugger.SendInternal("exp = ");
|
|
mDebugger.SendInternal(exp);
|
|
mDebugger.SendInternal("mantissa = ");
|
|
mDebugger.SendInternal(mantissa);
|
|
|
|
ulong intPart = 0, fracPart = 0;
|
|
|
|
/* First we handle the special cases INF, NaN, 0 and denormalized float */
|
|
switch (exp)
|
|
{
|
|
case 0x07ff:
|
|
if (mantissa == 0)
|
|
{
|
|
if (isNeg)
|
|
return "-∞";
|
|
else
|
|
return "∞";
|
|
}
|
|
else
|
|
/* It could exist -NaN but this is always printed as NaN */
|
|
return "NaN";
|
|
|
|
/* 0 or denormalized double? */
|
|
case 0x0000:
|
|
if (mantissa == 0)
|
|
return "0";
|
|
/* Denormalized float have always exp -1022 */
|
|
else
|
|
exp = -1022;
|
|
break;
|
|
|
|
/* Normalized double the exponent is unbiased and the implicit leading one is placed in the mantissa */
|
|
default:
|
|
exp -= 1023;
|
|
mantissa |= 0x10000000000000;
|
|
break;
|
|
}
|
|
|
|
if (exp >= 52)
|
|
{
|
|
intPart = mantissa << (exp - 52);
|
|
}
|
|
else if (exp >= 0)
|
|
{
|
|
intPart = mantissa >> (52 - exp);
|
|
fracPart = (mantissa << (exp + 1)) & 0x1FFFFFFFFFFFFF;
|
|
}
|
|
else
|
|
{
|
|
fracPart = (mantissa & 0x1FFFFFFFFFFFFF) >> (-(exp + 1));
|
|
}
|
|
|
|
string result = "";
|
|
|
|
if (isNeg)
|
|
{
|
|
result += "-";
|
|
}
|
|
|
|
result += intPart.ToString();
|
|
int usedDigits = result.Length;
|
|
if (fracPart == 0)
|
|
{
|
|
return result;
|
|
}
|
|
result += ".";
|
|
|
|
if (usedDigits >= 15)
|
|
{
|
|
usedDigits = 14;
|
|
}
|
|
for (int m = usedDigits; m < 15; m++)
|
|
{
|
|
fracPart = (fracPart << 3) + (fracPart << 1);
|
|
char p = (char)(((fracPart >> 53) & 0xFF) + '0');
|
|
result += p;
|
|
|
|
fracPart &= 0x1FFFFFFFFFFFFF;
|
|
}
|
|
fracPart = (fracPart << 3) + (fracPart << 1);
|
|
char remain = (char)((fracPart >> 53) + '0');
|
|
if ((remain > '5') && (result[result.Length - 1] > '0'))
|
|
{
|
|
char[] answer = result.ToCharArray();
|
|
int digitPos = answer.Length - 1;
|
|
char digit = result[digitPos];
|
|
answer[digitPos] = (char)(digit + 1);
|
|
while (answer[digitPos] > '9')
|
|
{
|
|
answer[digitPos] = '0';
|
|
digitPos--;
|
|
digit = result[digitPos];
|
|
if (digit == '.')
|
|
{
|
|
digitPos--;
|
|
digit = result[digitPos];
|
|
}
|
|
answer[digitPos] = (char)(digit + 1);
|
|
}
|
|
|
|
result = new string(answer);
|
|
}
|
|
|
|
while (result[result.Length - 1] == '0')
|
|
{
|
|
result = result.Substring(0, result.Length - 1);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public static int GetStringToNumber(string aString)
|
|
{
|
|
bool xIsNegative = false;
|
|
int xNumber = 0;
|
|
if (!string.IsNullOrWhiteSpace(aString))
|
|
{
|
|
char[] xCharArray = aString.ToCharArray();
|
|
for (int i = 0; i < xCharArray.Length; i++)
|
|
{
|
|
if (char.IsDigit(xCharArray[i]))
|
|
{
|
|
int xValue = xCharArray[i] - '0';
|
|
int xMax = xCharArray.Length - 1;
|
|
for (int j = 0; j < xMax - i; i++)
|
|
{
|
|
xValue *= 10;
|
|
}
|
|
|
|
xNumber += xValue;
|
|
}
|
|
else if (xCharArray[i] == '-')
|
|
{
|
|
xIsNegative = true;
|
|
}
|
|
else if (xCharArray[i] == '.')
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
throw new FormatException("The string parameter is not a number and is invalid.");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (xIsNegative)
|
|
{
|
|
xNumber *= -1;
|
|
}
|
|
|
|
return xNumber;
|
|
}
|
|
|
|
public static int Compare(string aString1, int aIndex1, string aString2, int aIndex2, int aLength1, int aLength2)
|
|
{
|
|
if (aString1.Length < aString2.Length)
|
|
{
|
|
return (int)StringComparisonResultEnum.Less;
|
|
}
|
|
if (aString1.Length > aString2.Length)
|
|
{
|
|
return (int)StringComparisonResultEnum.Greater;
|
|
}
|
|
|
|
for (int i = aString1.Length; i < aString1.Length; i++)
|
|
{
|
|
if (aString1[i] < aString2[i])
|
|
{
|
|
return (int)StringComparisonResultEnum.Equal;
|
|
}
|
|
if (aString1[i] > aString2[i])
|
|
{
|
|
return (int)StringComparisonResultEnum.Greater;
|
|
}
|
|
}
|
|
return (int)StringComparisonResultEnum.Equal;
|
|
}
|
|
}
|
|
}
|
|
|