I have this value:
double headingAngle = 135.34375;
I would like to convert it to HEX and print the HEX to the console. I have already converted a string and int into their respective HEX values, but a double seems to be much more tricky. Can someone point me in the right direction?
Well, I googled for a minute or two and according to this
here is a quite ellegant solution
double d = 12.09;
Console.WriteLine("Double value: " + d.ToString());
byte[] bytes = BitConverter.GetBytes(d);
Console.WriteLine("Byte array value:");
Console.WriteLine(BitConverter.ToString(bytes));
You can convert base 10 to base 16 by continually multiplying the fraction by 16, stripping out the 'whole' number, and repeating with the remainder.
So to convert 0.1 Decimal to Hex
0.1 * 16
= 1.6
So 1 becomes the first hex value. Keep going with the remaining 0.6
0.6 * 16 = 9.6
So 9 becomes the second hex value. Keeping going with the remaining 0.6
0.6 * 16 = 9.6
etc.
So 0.1 Decimal = 0.19999.. recurring hex
From memory this works for any radix. Obviously in hex a whole value of 10 would be A etc.
Assuming you want to convert to hexadecimal base/radix, the following should do the trick:
static void Main(string[] args)
{
Console.WriteLine(Base16(135.34375, 10));
Console.ReadLine();
}
private static string Base16(double number, int fractionalDigits)
{
return Base(number, fractionalDigits, new char[]{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F' });
}
private static string Base(double number, int fractionalDigits, params char[] characters)
{
int radix = characters.Length;
StringBuilder sb = new StringBuilder();
// The 'whole' part of the number.
long whole = (long)Math.Floor(number);
while (whole > 1)
{
sb.Insert(0, characters[whole % radix]);
whole = whole / radix;
}
// The fractional part of the number.
double remainder = number % 1;
if (remainder > Double.Epsilon || remainder < -Double.Epsilon)
{
sb.Append('.');
double nv;
for (int i = 0; i < fractionalDigits; i++)
{
nv = remainder * radix;
if (remainder < Double.Epsilon && remainder > -Double.Epsilon)
break;
sb.Append(characters[(int)Math.Floor(nv)]);
remainder = nv % 1;
}
}
return sb.ToString();
}
The hexadecimal conversion of 135.34375 is 87.58.
BitConverter.DoubleToInt64Bits(value).ToString("X")
Try this:
public static string Format(double number, double #base)
{
StringBuilder format = new StringBuilder();
if(number < 0)
{
format.Append('-');
number = -number;
}
double log = Math.Log(number, #base);
bool frac = false;
double order;
if(log < 0)
{
frac = true;
format.Append(digits[0]);
format.Append('.');
order = 1/#base;
}else{
order = Math.Pow(#base, Math.Floor(log));
}
while(number != 0 || order >= 1)
{
double digit = Math.Floor(number/order);
if(digit >= #base) break;
number = number-digit*order;
number = Math.Round(number, 15);
if(order < 1 && !frac)
{
format.Append('.');
frac = true;
}
order /= #base;
if(digit >= 10)
{
format.Append((char)('A'+(digit-10)));
}else{
format.Append((char)('0'+digit));
}
}
return format.ToString();
}
Use it like Format(headingAngle, 16). You can also comment out number = Math.Round(number, 15); for more interesting results. ☺
Result is in culture-invariant format. For 135.34375, it returns 87.58.
Related
I'm trying to create a sequence of numbers in string format, once I reach "99999" I want to continue the sequence using leading letters.
Example:
"00000" -> "00100" -> "99999" -> "A0001" -> "A9999" -> "B0001" -> "ZZZZZ"
Is there an easy way to achieve this ?
So far I tried to split my string in numbers and letters and then I have some code cheking if numbers reach maximum, if it reach the maximum available I add a letter. Doesn't look really elegant to me.
Let's implement GetNextValue method: for a given value (e.g. "A9999") we compute the next ("B0001"):
private static string GetNextValue(string value) {
StringBuilder sb = new StringBuilder(value);
// Digits only: 1239 -> 1240
for (int i = value.Length - 1; i >= 0; --i) {
if (sb[i] < '9') {
sb[i] = (char)(sb[i] + 1);
return sb.ToString();
}
else if (sb[i] >= 'A')
break;
else
sb[i] = '0';
}
// 1st letter: 9999 -> A001
if (sb[0] == '0') {
sb[0] = 'A';
if (sb[sb.Length - 1] == '0')
sb[sb.Length - 1] = '1';
return sb.ToString();
}
// Leading letters AZ999 -> BA001
for (int i = value.Length - 1; i >= 0; --i) {
if (sb[i] >= 'A') {
if (sb[i] < 'Z') {
sb[i] = (char)(sb[i] + 1);
if (sb[sb.Length - 1] == '0')
sb[sb.Length - 1] = '1';
return sb.ToString();
}
else
sb[i] = 'A';
}
}
// All letters increment: ABCDZ -> ABCEA
for (int i = 0; i < value.Length; ++i) {
if (sb[i] == '0') {
sb[i] = 'A';
if (sb[sb.Length - 1] == '0')
sb[sb.Length - 1] = '1';
return sb.ToString();
}
}
// Exhausting: ZZZZZ -> 00000
return new string('0', value.Length);
}
If you want to enumerate these values:
private static IEnumerable<string> Generator(int length = 5) {
string item = new string('0', length);
do {
yield return item;
item = GetNextValue(item);
}
while (!item.All(c => c == '0'));
}
Demo: (let's use a string of length 3)
Console.Write(string.Join(Environment.NewLine, Generator(3)));
Outcome: (27234 items in total; 18769482 items if length == 5)
000
001
002
...
009
010
...
999
A01
...
A99
B01
...
Z99
AA1
...
AA9
AB1
...
AZ9
BA1
...
ZZ9
AAA
AAB
AAC
...
AAZ
ABA
...
ZZY
ZZZ
Here is an extension method which formats integer values to your format (with leading letters):
public static string ToZormat(this int value, int length = 5)
{
string map = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char[] result = new char[length];
var x = value;
for(int i = 0; i < length; i++)
{
int threshold = (int)Math.Pow(10, length - i - 1);
var index = Math.Min(map.Length - 1, x / threshold);
result[i] = map[index];
x -= threshold * index;
}
return new String(result);
}
When you have number formatted to a string of length 5, leading letters appear after value 99,999, next go A0,000, ... A9,999, B0,000 etc. As you can see the first character changes every 10,000 numbers. The second character changes every 1,000 numbers. And last, the fifth character will change for every number. We just need to implement that algorithm.
Basic steps:
Define map of characters which are used in your format
Calculate character change threshold for the current position (i) - it will be power of 10: 10,000, 1,000, 100, 10, 1.
Get the index of character from map. Its simply number of thresholds which fits the value, but not more than the number of characters in your map.
Calculate what's left from input value and go to next postion
You should add validation for the max value which fits the given length of the formatted string.
Sample for length 3:
Enumerable.Range(0, 3886).Select(x => x.ToZormat(3))
Output:
000
001
002
...
999
A00
A01
...
A99
B00
B01
...
Z99
ZA0
ZA1
...
ZZ9
ZZA
...
ZZZ
So we were asked to convert a Hexadecimal Value (stored in a String) to its Decimal Value. Each character in the String should be manually converted to decimal within a loop, and then post the total Decimal Value of the Hexadecimal Value. I got here the codes that I have written but I couldn't identify where I could have gone wrong for an "F4" Hexa (as an example) to have a Decimal Equivalent of "292" instead of "244". I have debugged everything, the code seems fine. Any ideas?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AdvProgCS
{
class Program
{
static int dec=0;
static string hex;
static void Main(string[] args)
{
do{
Console.Write("[Press 0 to Stop] Hexadecimal Value: ");
hex = Console.ReadLine();
if (hex == "0") break;
int length = hex.Length;
for (int i = 0; i < length+1; i++)
{
if (hex[i] == 'A' || hex[i] == 'B' || hex[i] == 'C' || hex[i] == 'D' || hex[i] == 'E' || hex[i] == 'F')
{
if (hex[i] == 'A')
dec+= 10 * Convert.ToInt32(Math.Pow(16, length - 1));
if (hex[i] == 'B')
dec += 11 * Convert.ToInt32(Math.Pow(16, length - 1));
if (hex[i] == 'C')
dec += 12 * Convert.ToInt32(Math.Pow(16, length - 1));
if (hex[i] == 'D')
dec += 13 * Convert.ToInt32(Math.Pow(16, length - 1));
if (hex[i] == 'E')
dec += 14 * Convert.ToInt32(Math.Pow(16, length - 1));
if (hex[i] == 'F')
dec += 15 * (Convert.ToInt32(Math.Pow(16, length - 1)));
}
else
dec += hex[i];
length--;
}
Console.WriteLine("DECIMAL EQUIVALENT: " + dec + "\n");
}
while(hex != "0");
}
}
}
You forgot about the Math.Pow in the dec += hex[i] line where you also have to convert hex[i] from char into a number.
dec += (int)char.GetNumericValue(hex[i]) * (int)Math.Pow(16, length - 1);
Moreover, as observed by Partha:
Also add dec = 0; after your print statement. I think the dec values
are getting adding to itself for each iteration.
Personally, my brain likes it better like this:
static void Main(string[] args)
{
int dec;
string hex;
int decValue;
string hexReversed;
string hexValues = "0123456789ABCDEF";
do
{
Console.Write("[Press 0 to Stop] Hexadecimal Value: ");
hex = Console.ReadLine().ToUpper().Trim();
if (hex != "0")
{
dec = 0;
hexReversed = new String(hex.Reverse().ToArray());
for (int i = 0; i < hexReversed.Length; i++)
{
decValue = hexValues.IndexOf(hexReversed.Substring(i, 1));
if (decValue != -1)
{
dec = dec + (decValue * (int)Math.Pow(16, i));
}
else
{
Console.WriteLine("Invalid Hexadecimal Value!");
break;
}
}
if (dec != 0)
{
Console.WriteLine(String.Format("{0} hex = {1} dec", hex, dec.ToString()));
}
}
} while (hex != "0");
}
Here is my hex to decimal function, much smaller but it doesnt check if the input is a hex value or not.
private int hex2Decimal(string hex)
{
string hexV = "0123456789ABCDEF"; // For the hex values (ex: F=15)
hex = hex.ToUpper().Replace("0X", ""); // Get good string format
int res;
char[] cArr = hex.ToCharArray();
Array.Reverse(cArr); // Reverse hex string
List<int> iArr = new List<int>();
for (int i = hex.Length - 1; i > -1; i--) // Get the bits
iArr.Add(hexV.IndexOf(cArr[i]) * (int)Math.Pow(16, i)); // Calculate each bits and add to an array
res = iArr.ToArray().Sum(); // Calculate all the numbers and add to the final result
return res;
}
I need to convert int to bin and with extra bits.
string aaa = Convert.ToString(3, 2);
it returns 11, but I need 0011, or 00000011.
How is it done?
11 is binary representation of 3. The binary representation of this value is 2 bits.
3 = 20 * 1 + 21 * 1
You can use String.PadLeft(Int, Char) method to add these zeros.
// convert number 3 to binary string.
// And pad '0' to the left until string will be not less then 4 characters
Convert.ToString(3, 2).PadLeft(4, '0') // 0011
Convert.ToString(3, 2).PadLeft(8, '0') // 00000011
I've created a method to dynamically write leading zeroes
public static string ToBinary(int myValue)
{
string binVal = Convert.ToString(myValue, 2);
int bits = 0;
int bitblock = 4;
for (int i = 0; i < binVal.Length; i = i + bitblock)
{ bits += bitblock; }
return binVal.PadLeft(bits, '0');
}
At first we convert my value to binary.
Initializing the bits to set the length for binary output.
One Bitblock has 4 Digits. In for-loop we check the length of our converted binary value und adds the "bits" for the length for binary output.
Examples:
Input: 1 -> 0001;
Input: 127 -> 01111111
etc....
You can use these methods:
public static class BinaryExt
{
public static string ToBinary(this int number, int bitsLength = 32)
{
return NumberToBinary(number, bitsLength);
}
public static string NumberToBinary(int number, int bitsLength = 32)
{
string result = Convert.ToString(number, 2).PadLeft(bitsLength, '0');
return result;
}
public static int FromBinaryToInt(this string binary)
{
return BinaryToInt(binary);
}
public static int BinaryToInt(string binary)
{
return Convert.ToInt32(binary, 2);
}
}
Sample:
int number = 3;
string byte3 = number.ToBinary(8); // output: 00000011
string bits32 = BinaryExt.NumberToBinary(3); // output: 00000000000000000000000000000011
public static String HexToBinString(this String value)
{
String binaryString = Convert.ToString(Convert.ToInt32(value, 16), 2);
Int32 zeroCount = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(binaryString.Length) / 8)) * 8;
return binaryString.PadLeft(zeroCount, '0');
}
Just what Soner answered use:
Convert.ToString(3, 2).PadLeft(4, '0')
Just want to add just for you to know. The int parameter is the total number of characters that your string and the char parameter is the character that will be added to fill the lacking space in your string. In your example, you want the output 0011 which which is 4 characters and needs 0's thus you use 4 as int param and '0' in char.
string aaa = Convert.ToString(3, 2).PadLeft(10, '0');
This may not be the most elegant solution but it is the fastest from my testing:
string IntToBinary(int value, int totalDigits) {
char[] output = new char[totalDigits];
int diff = sizeof(int) * 8 - totalDigits;
for (int n = 0; n != totalDigits; ++n) {
output[n] = (char)('0' + (char)((((uint)value << (n + diff))) >> (sizeof(int) * 8 - 1)));
}
return new string(output);
}
string LongToBinary(int value, int totalDigits) {
char[] output = new char[totalDigits];
int diff = sizeof(long) * 8 - totalDigits;
for (int n = 0; n != totalDigits; ++n) {
output[n] = (char)('0' + (char)((((ulong)value << (n + diff))) >> (sizeof(long) * 8 - 1)));
}
return new string(output);
}
This version completely avoids if statements and therfore branching which creates very fast and most importantly linear code. This beats the Convert.ToString() function from microsoft by up to 50%
Here is some benchmark code
long testConv(Func<int, int, string> fun, int value, int digits, long avg) {
long result = 0;
for (long n = 0; n < avg; n++) {
var sw = Stopwatch.StartNew();
fun(value, digits);
result += sw.ElapsedTicks;
}
Console.WriteLine((string)fun(value, digits));
return result / (avg / 100);//for bigger output values
}
string IntToBinary(int value, int totalDigits) {
char[] output = new char[totalDigits];
int diff = sizeof(int) * 8 - totalDigits;
for (int n = 0; n != totalDigits; ++n) {
output[n] = (char)('0' + (char)((((uint)value << (n + diff))) >> (sizeof(int) * 8 - 1)));
}
return new string(output);
}
string Microsoft(int value, int totalDigits) {
return Convert.ToString(value, toBase: 2).PadLeft(totalDigits, '0');
}
int v = 123, it = 10000000;
Console.WriteLine(testConv(Microsoft, v, 10, it));
Console.WriteLine(testConv(IntToBinary, v, 10, it));
Here are my results
0001111011
122
0001111011
75
Microsofts Method takes 1.22 ticks while mine only takes 0.75 ticks
With this you can get binary representation of string with corresponding leading zeros.
string binaryString = Convert.ToString(3, 2);;
int myOffset = 4;
string modified = binaryString.PadLeft(binaryString.Length % myOffset == 0 ? binaryString.Length : binaryString.Length + (myOffset - binaryString.Length % myOffset), '0'));
In your case modified string will be 0011, if you want you can change offset to 8, for instance, and you will get 00000011 and so on.
C# - truncate decimals beyond first positive
a number is 0.009012
result should be 0.009
or is 1.1234 and 'd be 1.1
or 2.099 ~ 2.09
and so on
in a fast and optimum way
Think mathematically, use logarithmus with base 10
this function will just take the first cipher
public double RoundOnFirstDecimal(double number)
{
int shift = -1 * ((int)Math.Floor(Math.Log10(number)));
return Math.Floor(number * Math.Pow(10, shift)) / Math.Pow(10, shift);
}
But you want to have it this way: (will shift only regarding the decimal fractions, but not full numbers)
public double RoundOnFirstDecimal(double number)
{
int shift = -1 * ((int)Math.Floor(Math.Log10(number % 1)));
return Math.Floor(number % 1 * Math.Pow(10, shift)) / Math.Pow(10, shift) + number - number % 1;
}
thats gonna be significantly faster than any regex or looping
Try this method:
private static string RoundSpecial(double x)
{
string s = x.ToString();
int dotPos = s.IndexOf('.');
if (dotPos != -1)
{
int notZeroPos = s.IndexOfAny(new[] { '1', '2', '3', '4', '5', '6', '7', '8', '9' }, dotPos + 1);
return notZeroPos == -1 ? s : s.Substring(0, notZeroPos + 1);
}
return s;
}
I'm not sure that it is the fastest and optimal method, but it does what you want.
Second approach is to use Log10 and %:
private static double RoundSpecial(double x)
{
int pos = -(int)Math.Log10(x - (int)x);
return Math.Round(x - (x % Math.Pow(0.1, pos + 1)), pos + 1);
}
You may try regular expression too:
decimal d = 2.0012m;
Regex pattern = new Regex(#"^(?<num>(0*[1-9]))\d*$");
Match match = pattern.Match(d.ToString().Split('.')[1]);
string afterDecimal = match.Groups["num"].Value; //afterDecimal = 001
Here's a solution that uses math instead of string logic:
double nr = 0.009012;
var partAfterDecimal = nr - (int) nr;
var partBeforeDecimal = (int) nr;
int count = 1;
partAfterDecimal*=10;
int number = (int)(partAfterDecimal);
while(number == 0)
{
partAfterDecimal *= 10;
number = (int)(partAfterDecimal);
count++;
}
double dNumber = number;
while(count > 0){
dNumber /= 10.0;
count--;
}
double result = (double)partBeforeDecimal + dNumber;
result.Dump();
if you don't want to use the Math library:
static double truncateMyWay(double x)
{
double afterDecimalPoint = x - (int)x;
if (afterDecimalPoint == 0.0) return x;
else
{
int i = 0;
int count10 = 1;
do
{
afterDecimalPoint *= 10;
count10 *= 10;
i++;
} while ((int) afterDecimalPoint == 0);
return ((int)(x * count10))/((double)count10);
}
}
Happy Codding! ;-)
I'm trying to parse a string to a decimal and the parsing should failed if there are more than 2 digits after the decimal point in the string.
e.g:
1.25 is valid but 1.256 is invalid.
I tried to use the decimal.TryParse method in C# to solve in the following manner but this does not help...
NumberFormatInfo nfi = new NumberFormatInfo();
nfi.NumberDecimalDigits = 2;
if (!decimal.TryParse(test, NumberStyles.AllowDecimalPoint, nfi, out s))
{
Console.WriteLine("Failed!");
return;
}
Console.WriteLine("Passed");
Any suggestions?
Have a look at Regex. There are various threads covering this subjects.
example:
Regex to match 2 digits, optional decimal, two digits
Regex decimalMatch = new Regex(#"[0-9]?[0-9]?(\.[0-9]?[0-9]$)"); this should do in your case.
var res = decimalMatch.IsMatch("1111.1"); // True
res = decimalMatch.IsMatch("12111.221"); // False
res = decimalMatch.IsMatch("11.21"); // True
res = decimalMatch.IsMatch("11.2111"); // False
res = decimalMatch.IsMatch("1121211.21143434"); // false
I've found the solution within stackoverflow:
(Posted by carlosfigueira: C# Check if a decimal has more than 3 decimal places? )
static void Main(string[] args)
{
NumberFormatInfo nfi = new NumberFormatInfo();
nfi.NumberDecimalDigits = 2;
decimal s;
if (decimal.TryParse("2.01", NumberStyles.AllowDecimalPoint, nfi, out s) && CountDecimalPlaces(s) < 3)
{
Console.WriteLine("Passed");
Console.ReadLine();
return;
}
Console.WriteLine("Failed");
Console.ReadLine();
}
static decimal CountDecimalPlaces(decimal dec)
{
int[] bits = Decimal.GetBits(dec);
int exponent = bits[3] >> 16;
int result = exponent;
long lowDecimal = bits[0] | (bits[1] >> 8);
while ((lowDecimal % 10) == 0)
{
result--;
lowDecimal /= 10;
}
return result;
}
Maybe not so elegant as the other options proposed, but somewhat simpler I think:
string test= "1,23"; //Change to your locale decimal separator
decimal num1; decimal num2;
if(decimal.TryParse(test, out num1) && decimal.TryParse(test, out num2))
{
//we FORCE one of the numbers to be rounded to two decimal places
num1 = Math.Round(num1, 2);
if(num1 == num2) //and compare them
{
Console.WriteLine("Passed! {0} - {1}", num1, num2);
}
else Console.WriteLine("Failed! {0} - {1}", num1, num2);
}
Console.ReadLine();
Or you could just do some simple integer math:
class Program
{
static void Main( string[] args )
{
string s1 = "1.25";
string s2 = "1.256";
string s3 = "1.2";
decimal d1 = decimal.Parse( s1 );
decimal d2 = decimal.Parse( s2 );
decimal d3 = decimal.Parse( s3 );
Console.WriteLine( d1 * 100 - (int)( d1 * 100) == 0);
Console.WriteLine( d2 * 100 - (int)( d2 * 100) == 0);
Console.WriteLine( d3 * 100 - (int)( d3 * 100 ) == 0 );
}
}