I'm trying to convert a double number into array of digits
Input:
double num
Output:
int[] arrDigit
int dotIdx
bool isMinus
for example:
Input:
double num = -69.69777
Output:
int[] arrDigit = { 7,7,7,9,6,9,6}
int dotIdx = 5
bool isMinus = true
And vice versa:
Input:
array of input digit commands
Output:
double num
for example:
Input:
Insert digit 6
Insert digit 9
Start dot
Insert digit 6
Insert digit 9
Insert digit 7
Insert digit 7
Insert digit 7
Output:
double num=69.69777
The easiest way is using C# string method, I've implemented it:
class DigitToNumTranslator
{
private bool m_isDot;
//Minus is handled as operator, not the job for translator
//Helper
private StringBuilder m_builder = new StringBuilder();
public double NumResult
{
get
{
return double.Parse(m_builder.ToString(), System.Globalization.CultureInfo.InvariantCulture);
}
}
public void Reset()
{
m_builder.Clear();
m_isDot = false;
}
public void StartDot()
{
if (!m_isDot)
{
m_isDot = true;
m_builder.Append('.');
}
}
public void InsertDigit(int digit)
{
m_builder.Append(digit.ToString());
}
}
class NumToDigitTranslator
{
private List<int> m_lstDigit;
private IList<int> m_lstDigitReadOnly;
private int m_dotIdx;
private bool m_isMinus;
public IList<int> LstDigit => m_lstDigitReadOnly;
public int DotIdx => m_dotIdx;
public bool IsMinus => m_isMinus;
public NumToDigitTranslator()
{
m_lstDigit = new List<int>();
m_lstDigitReadOnly = m_lstDigit.AsReadOnly();
}
public void Translate(double num)
{
m_lstDigit.Clear();
m_dotIdx = 0;
m_isMinus = false;
var szNum = num.ToString(System.Globalization.CultureInfo.InvariantCulture);
//Won't work if it's 1E+17
for (var i = 0; i < szNum.Length; ++i)
{
if (char.IsNumber(szNum[i]))
m_lstDigit.Add(int.Parse(szNum[i].ToString()));
else if (szNum[i] == '-')
m_isMinus = true;
else if (szNum[i] == '.')
m_dotIdx = i;
}
//Reverse for display
if (m_dotIdx != 0)
m_dotIdx = szNum.Length - 1 - m_dotIdx;
m_lstDigit.Reverse();
}
}
But the string method is met with the issue "1E+17" (when the number is too long). I don't like the string method very much because it may have unexpected bug (e.g CultureInfo, 1E+17,... ) who knows if there is more case that I don't know - too risky and my application doesn't use string to display number, it combines sprite image to draw the number.
So I'd like to try the math method:
class DigitToNumTranslatorRaw
{
private double m_numResult;
private bool m_isDot;
private int m_dotIdx;
public double NumResult => m_numResult;
public void Reset()
{
m_numResult = 0;
m_dotIdx = 1;
m_isDot = false;
}
public void StartDot()
{
m_isDot = true;
}
public void InsertDigit(int digit)
{
if (m_isDot)
{
m_numResult += digit * Math.Pow(10, -m_dotIdx);
++m_dotIdx;
}
else
{
m_numResult *= 10;
m_numResult += digit;
}
}
}
class NumToDigitTranslatorRaw
{
private List<int> m_lstDigit;
private IList<int> m_lstDigitReadOnly;
private int m_dotIdx;
public IList<int> LstDigit => m_lstDigitReadOnly;
public int DotIdx => m_dotIdx;
public NumToDigitTranslatorRaw()
{
m_lstDigit = new List<int>();
m_lstDigitReadOnly = m_lstDigit.AsReadOnly();
}
public void Translate(double num)
{
m_dotIdx = 0;
m_lstDigit.Clear();
//WIP (work with int, but not with double, thus failed to get the numbers after dot)
var intNum = (int)num;
while (num > 10)
{
m_lstDigit.Add((intNum % 10));
num /= 10;
}
if (m_lstDigit.Count > 0)
m_lstDigit.Reverse();
else
m_lstDigit.Add(0);
}
}
But I meet with 2 problems:
In
DigitToNumTranslatorRaw
, I don't now if it's better than the string solution. them_numResult += digit * Math.Pow(10, -m_dotIdx);
,num /= 10;
,... may cause floating point precision problem and Is Pow the best way for performance?In
NumToDigitTranslatorRaw
, I'm still not able to get the number after dot.
I tried to extract the code TryParse of Mircosoft to see how they do it, but it's too complicated I couldn't find where they put the that code.
So my purpose is:
Math method: write
DigitToNumTranslatorRaw
&NumToDigitTranslatorRaw
and make sure it's bug free & floating point accurate & better performance than string method (because I don't deal with CultureInfo.InvariantCulture, 1E+17,...).If the math method is too hard, I'll just use the string method
DigitToNumTranslator
&NumToDigitTranslator
and deal with each string problem (e.g too long number turn into 1E+17), but the problem is I don't know if I cover all the string problem (e.g the 1E+17 I found out by random testing, the CultureInfo problem I found out by searching on stack overflow), the docs didn't list all the problems I may encounter.