I am getting values in a format like this 00-C6 (Hex). It complains when I try to convert it to double (format execption). What to do?
public void check()
{
double low;
double high;
percentageCalculator(4095, 5, out low, out high);
Dictionary[] A_1 = {Max_1, Min_1};
for (int i = 0; i < A_1.Length; i++)
{
if ((Convert.ToDouble(A_1[i].CurrentValue) <= low) || ((Convert.ToDouble(A_1[i].CurrentValue) >= high))
{
Fault++;
}
}
}
Assuming the Hex 00-C6 string represents Integer value (because if it represents floating-point value like float or double, it must consists of 4-byte or 8-byte), then one way to process it is to split the Hex string:
string hexString = "00-C6";
string[] hexes = hexString.Split('-');
Then you process each element in the hexes like this:
int hex0 = Convert.ToInt32(hexes[0], 16);
int hex1 = Convert.ToInt32(hexes[1], 16);
If the hex is little endian, then your double value would be:
double d = hex0 << 8 + hex1;
And if it is big endtion, your double will be:
double d = hex1 << 8 + hex0;
The key here is to know that you can convert hex string representation to Int by using Convert.ToInt32 with second argument as 16.
You can combine all the steps above into one liner if you feel like. Here I purposely break them down for the sake of presentation clarity.
Take a look at this piece of code:
string hexnumber = "00-c6";
double doubleValue = (double)Convert.ToInt32(hexnumber.Replace("-", ""), 16);
Related
I am attempting to manually convert numbers between decimal and hexadecimal. I have it working for positive numbers and converting a negative decimal to 'negative' hexadecimal but I can't convert it from 'negative' hexadecimal to negative decimal.
Here is the code I am attempting to work with:
private string HexToDecimal(char[] toConvert)
{
if (negativeValue)
{
negativeValue = false;
long var = Convert.ToInt64(HexToDecimal(ResultLabel.Text.ToCharArray()));
long valueToHex = var - (long)Math.Pow(16, 15);
return ResultLabel.Text = valueToHex.ToString();
}
else
{
double total = 0;
//Convert hex to decimal
HexOrDecimalLabel.Text = "Decimal";
//TODO: create int array from indivial int
char[] charArray = toConvert;
long[] numberArray = HexSwitchFunction(charArray);
//TODO: reverse array
Array.Reverse(numberArray);
//loop array, times value by 16^i++, adding to total. This is the method used to convert hex to decimal
double power = 0;
foreach (int i in numberArray)
{
total += (i * (Math.Pow(16, power)));
power++;
}
//set the result label to total
isHex = false;
AllowHexButtons();
return ResultLabel.Text = total.ToString();
}
}
For instance, I can turn - 10 into FFFFFFFFFFFFFFF6, but when i attempt to turn that into decimal, I get 1.15292150460685E+18, which I can't do any equations with.
Does anyone know of a way around this?
This is because double uses a different representation for negative numbers. Changing the type of total and power from double to long will fix the problem.
I am looking for a method that adds zero's up to 16 characters before a decimal, and a minus sign if the value is minus. E.g.,
18,52 becomes 000000000000001852, and
-18,52 becomes-00000000000001852
I have an idea how to implement this by using replacements and if-statements, and using the PadLeft method where characters are padded to the left to what length you specify. But I am not sure how to make it exactly.
What I have right now is this:
static string FormatDecimal(decimal d, int length = 0, char a = '0')
{
var sb = new StringBuilder();
var rounded = decimal.Round(d, 2, MidpointRounding.AwayFromZero);
if (rounded < 0)
{
sb.Append("-");
}
else
{
sb.Append("");
}
var lastPart = rounded.ToString().Replace(",", "").Replace(".", "");
var lengthMiddle = length - sb.Length - lastPart.Length;
for (int i = 0; i < lengthMiddle; i++)
{
sb.Append(a);
}
sb.Append(lastPart);
return sb.ToString();
}
When I look at the code and do Console.WriteLine(FormatDecimal(-18m, 16, '0')) I see that
The code is 1. very long, and 2. it does not work... The rounding fails and just keeps the -18 and no minus sign is added.
I would be very grateful if someone could help me out with this one!
If you want to represent two decimal digits in your string and eliminate the decimal mark, you can simply multiply your number by 100. To pad up to 16 digits, use the D format string:
decimal d = -18.52m;
string s = ((int)(d * 100)).ToString("D16");
Edit: If you only want to pad up to 15 digits for negative numbers, you could use a conditional:
decimal d = -18.52m;
int i = (int)(d * 100);
string s = i.ToString(i >= 0 ? "D16" : "D15");
Alternatively, you could express the conditional within the format string itself using section separators:
string s = i.ToString("0000000000000000;-000000000000000");
Instead of building this yourself, use what's already there. decimal.ToString() will format a number for you:
decimal d = 18.52;
string s = d.ToString("0000000000.##"); // = "0000000018.52"
decimal d = 18.00;
string s = d.ToString("0000000000.##"); // = "0000000018"
You could build your format string using the string constructor:
int length = 10;
string formatString = string.Concat(new string('0', length), ".##")
string s = d.ToString(formatString); // = "0000000018"
Note: this doesn't take care of your rounding, but I'm not clear from the question what your requirement is there.
I'm having a problem with modulo from int which has 31 chars. It seems to bug out on
Int64 convertedNumber = Int64.Parse(mergedNumber); with Value was either too large or too small for an Int64. (Overflow Exception). How to fix it so that modulo doesn't bug out ?
class GeneratorRachunkow {
private static string numerRozliczeniowyBanku = "11111155"; // 8 chars
private static string identyfikatorNumeruRachunku = "7244"; // 4 chars
private static string stalaBanku = "562100"; // 6 chars
public static string generator(string pesel, string varKlientID) {
string peselSubstring = pesel.Substring(pesel.Length - 5); // 5 chars (from the end of the string);
string toAttach = varKlientID + peselSubstring;
string indywidualnyNumerRachunku = string.Format("{0}", toAttach.ToString().PadLeft(13, '0')); // merging pesel with klient id and adding 0 to the begining to match 13 chars
string mergedNumber = numerRozliczeniowyBanku + identyfikatorNumeruRachunku + indywidualnyNumerRachunku + stalaBanku; // merging everything -> 31 chars
Int64 convertedNumber = Int64.Parse(mergedNumber);
Int64 modulo = MathMod(convertedNumber, 97);
Int64 wynik = 98 - modulo;
string wynikString = string.Format("{0}", wynik.ToString().PadLeft(2, '0')); // must be 2 chars
indywidualnyNumerRachunku = wynikString + numerRozliczeniowyBanku + identyfikatorNumeruRachunku + indywidualnyNumerRachunku;
return indywidualnyNumerRachunku;
}
private static Int64 MathMod(Int64 a, Int64 b) {
return (Math.Abs(a * b) + a) % b;
}
}
The max value for Int64 is 9223372036854775807 (19 characters when printed). You will probably want to use BigInteger instead (which was introduced in .NET 4):
public static string generator(string pesel, string varKlientID) {
// I have cut some code here to keep it short
BigInteger convertedNumber;
if (BigInteger.TryParse(mergedNumber , out convertedNumber))
{
BigInteger modulo = convertedNumber % 97;
// The rest of the method goes here...
}
else
{
// string could not be parsed to BigInteger; handle gracefully
}
}
private static BigInteger MathMod(BigInteger a, BigInteger b)
{
return (BigInteger.Abs(a * b) + a) % b;
}
Int64.MaxValue is 9,223,372,036,854,775,807 that's 19 characters. So you just can't fit that in. I suggest looking at this question for working with big numbers.
Try this function instead of "MathMod":
static int ModString(string x, int y)
{
if (x.Length == 0)
return 0;
string x2 = x.Substring(0,x.Length - 1); // first digits
int x3 = int.Parse(x.Substring(x.Length - 1)); // last digit
return (ModString(x2, y) * 10 + x3) % y;
}
(since all of your numbers are positive, there is no point in using Math.Abs, as in your original MathMod function).
Use it this way:
modulo = ModString(mergedNumber,97);
This should works with all versions of .NET since 1.1, without the need of BigInteger.
The answer you are looking for is demonstrated here. It includes various manners to calculate the modulus for huge numbers. I used similar methods as described here for international bank account numbers.
A direct link to someone who has a copy pastable method is here.
Given a potentially huge integer value (in C# string format), I want to be able to generate its hex equivalent. Normal methods don't apply here as we are talking arbitrarily large numbers, 50 digits or more. The techniques I've seen which use a technique like this:
// Store integer 182
int decValue = 182;
// Convert integer 182 as a hex in a string variable
string hexValue = decValue.ToString("X");
// Convert the hex string back to the number
int decAgain = int.Parse(hexValue, System.Globalization.NumberStyles.HexNumber);
won't work because the integer to convert is too large.
For example I need to be able to convert a string like this:
843370923007003347112437570992242323
to its hex equivalent.
these don't work:
C# convert integer to hex and back again
How to convert numbers between hexadecimal and decimal in C#?
Oh, that's easy:
var s = "843370923007003347112437570992242323";
var result = new List<byte>();
result.Add( 0 );
foreach ( char c in s )
{
int val = (int)( c - '0' );
for ( int i = 0 ; i < result.Count ; i++ )
{
int digit = result[i] * 10 + val;
result[i] = (byte)( digit & 0x0F );
val = digit >> 4;
}
if ( val != 0 )
result.Add( (byte)val );
}
var hex = "";
foreach ( byte b in result )
hex = "0123456789ABCDEF"[ b ] + hex;
Use a BigInteger to store the integer, and than use the .ToString("X") on that object.
Example:
var number = BigInteger.Parse("843370923007003347112437570992242323");
string hexValue = number.ToString("X");
This is however limited to .NET 4 and later. But Jens A. pointed to a BigInteger class on codeproject that class contains a method called ToHexString so that would work for a < .NET 4 scenario.
As Jens said, take a look at the BigInt implementation on Code Project. Even if they don't have a function to convert to hex, you could easily write a function to do it yourself as long as this BigInt has a divide and modulo operation (I don't think it has a modulo function, so you would also need to write modulo yourself)
heh nice solutions for dec<->hex conversions here on stackoverflow so far ,... but i needed (gigantic int . gigantic fraction) with almost none precision lost so i modded all codes i found with my already done codes and here is some i can share (without big int/real lib usage)
//---------------------------------------------------------------------------
AnsiString str_hex2dec(const AnsiString &hex)
{
char c;
AnsiString dec="",s;
int i,j,l,ll,cy,val;
int i0,i1,i2,i3,sig;
sig=+1; l=hex.Length();
if (l) { c=hex[l]; if (c=='h') l--; if (c=='H') l--; }
i0=0; i1=l; i2=0; i3=l;
for (i=1;i<=l;i++) // scan for parts of number
{
char c=hex[i];
if (c=='-') sig=-sig;
if ((c=='.')||(c==',')) i1=i-1;
if ((c>='0')&&(c<='9')) { if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; }
if ((c>='A')&&(c<='F')) { if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; }
if ((c>='a')&&(c<='f')) { if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; }
}
l=0; s=""; if (i0) for (i=i0;i<=i1;i++)
{
c=hex[i];
if ((c>='0')&&(c<='9')) c-='0';
else if ((c>='A')&&(c<='F')) c-='A'-10;
else if ((c>='a')&&(c<='f')) c-='A'-10;
for (cy=c,j=1;j<=l;j++)
{
val=(s[j]<<4)+cy;
s[j]=val%10;
cy =val/10;
}
while (cy>0)
{
l++;
s+=char(cy%10);
cy/=10;
}
}
if (s!="")
{
for (j=1;j<=l;j++) { c=s[j]; if (c<10) c+='0'; else c+='A'-10; s[j]=c; }
for (i=l,j=1;j<i;j++,i--) { c=s[i]; s[i]=s[j]; s[j]=c; }
dec+=s;
}
if (dec=="") dec="0";
if (sig<0) dec="-"+dec;
if (i2)
{
dec+='.';
s=hex.SubString(i2,i3-i2+1);
l=s.Length();
for (i=1;i<=l;i++)
{
c=s[i];
if ((c>='0')&&(c<='9')) c-='0';
else if ((c>='A')&&(c<='F')) c-='A'-10;
else if ((c>='a')&&(c<='f')) c-='A'-10;
s[i]=c;
}
ll=((l*1234)>>10); // num of decimals to compute
for (cy=0,i=1;i<=ll;i++)
{
for (cy=0,j=l;j>=1;j--)
{
val=s[j];
val*=10;
val+=cy;
s[j]=val&15;
cy=val>>4;
}
dec+=char(cy+'0');
for (;;)
{
if (!l) break;;
if (s[l]) break;
l--;
}
if (!l) break;;
}
}
return dec;
}
//---------------------------------------------------------------------------
AnsiString str_dec2hex(AnsiString dec)
{
AnsiString hex=""; BYTE a,b;
int i,j,i0,i1,i2,i3,l,sig;
sig=+1; l=dec.Length();
i0=0; i1=l; i2=0; i3=l;
for (i=1;i<=l;i++) // scan for parts of number
{
char c=dec[i];
if (c=='-') sig=-sig;
if ((c=='.')||(c==',')) i1=i-1;
if ((c>='0')&&(c<='9')) { if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; }
}
if (i0) for (;i1>=i0;i1=j-1)// process integer part /16
{
for (a=0,j=i0,i=i0;i<=i1;i++)
{
a*=10; a+=dec[i]-'0';
if (a<16) { if (j>i0){ dec[j]='0'; j++; } continue; }
b=a>>4; a=a&15;
if (b>10) { dec[j]='1'; j++; b-=10; }
dec[j]=b+'0'; j++;
}
if ((!a)&&(hex=="")) continue;
if (a<10) a+='0'; else a+='A'-10;
hex=AnsiString(char(a))+hex;
}
if (hex=="") hex="0";
if ((i2)&&(i2<=i3)) // process fractional part *16
for (hex+=".",j=i3-i2+2;j;j--)
{
for (a=0,b=0,i=i3;i>=i2;i--)
{
a=dec[i]-'0';
b+=a<<4; dec[i]=(b%10)+'0'; b/=10;
}
if (b<10) b+='0'; else b+='A'-10;
hex+=char(b);
}
if (sig<0) hex="-"+hex; hex+="h";
return hex;
}
//---------------------------------------------------------------------------
P.S. if you need to cut off fractional digits (to format numbers) than you have to round by most significant digit of the cutted part.
rounding abs up in dec mode if digit >='5'
rounding abs up in hex mode if digit >='8'
if you wonder what means this line:
ll=((l*1234)>>10); // num of decimals to compute
than it compute the number of fractional digits that match input string precision (1.205 decimal fractional digits per hexadecimal fractional digit). This ratio i get by empirical measurement of accuracy up to 1280 bits per fractional part of number. for simplicity
1e-l can be stored with max error up to 1e-(l+1). This ratio is almost constant (except for low fractional digit values (<16 digits) so this formula can be used for any larger num of digits safely. In low input digit values is output wrong max by 1 (>8 digits) or max 2 (<=8 digits) digits
All began with these simple lines of code:
string s = "16.9";
double d = Convert.ToDouble(s);
d*=100;
The result should be 1690.0, but it's not. d is equal to 1689.9999999999998.
All I want to do is to round a double to value with 2 digit after decimal separator.
Here is my function.
private double RoundFloat(double Value)
{
float sign = (Value < 0) ? -0.01f : 0.01f;
if (Math.Abs(Value) < 0.00001) Value = 0;
string SVal = Value.ToString();
string DecimalSeparator = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator;
int i = SVal.IndexOf(DecimalSeparator);
if (i > 0)
{
int SRnd;
try
{
// вземи втората цифра след десетичния разделител
SRnd = Convert.ToInt32(SVal.Substring(i + 3, 1));
}
catch
{
SRnd = 0;
}
if (SVal.Length > i + 3)
SVal = SVal.Substring(0, i + 3);
//SVal += "00001";
try
{
double result = (SRnd >= 5) ? Convert.ToDouble(SVal) + sign : Convert.ToDouble(SVal);
//result = Math.Round(result, 2);
return result;
}
catch
{
return 0;
}
}
else
{
return Value;
}
But again the same problem, converting from string to double is not working as I want.
A workaround to this problem is to concatenate "00001" to the string and then use the Math.Round function (commented in the example above).
This double value multiplied to 100 (as integer) is send to a device (cash register) and this values must be correct.
I am using VS2005 + .NET CF 2.0
Is there another more "elegant" solution, I am not happy with this one.
Doubles can't exactly represent 16.9. I suggest you convert it to decimal instead:
string s = "16.9";
decimal m = Decimal.Parse(s) * 100;
double d = (double)m;
You might just want to keep using the decimal instead of the double, since you say you'll be using it for monetary purposes. Remember that decimal is intended to exactly represent decimal numbers that fit in its precision, while double will only exactly represent binary numbers that do.
Math.Round(number, 1)
Edit I got the wrong question - the rounding problems are inherent to a floating point type (float, double). You should use decimal for this.
The best solution for not going be crazy is:
string s = "16.9";
For ,/.
double d = Convert.ToDouble(s.Replace(',','.'),System.Globalization.CultureInfo.InvariantCulture);
For rounding:
Convert.ToDouble((d).ToString("F2"));