I'm converting a Guid to a BigInteger so I can base62 encode it. This works well, however, I can get negative numbers in BigInterger. How do I shift the BigInteger so the number is positive. I'll also need to be able to shift it back so I can convert back to a Guid.
// GUID is a 128-bit signed integer
Guid original = new Guid("{35db5c21-2d98-4456-88a0-af263ed87bc2}");
BigInteger b = new BigInteger(original.ToByteArray());
// shift so its a postive number?
Note: For url-safe version of Base64 consider using modifyed set of characters for Base64 ( http://en.wikipedia.org/wiki/Base64#URL_applications) instead of custom Base62.
I believe you can append 0 to the array first (will make higest byte always not to contain 1 in the highest bit) and then convert to BigInteger if you really need positive BigInteger.
do you mean base64 encode?
Convert.ToBase64String(Guid.NewGuid().ToByteArray());
If you sometimes get negative numbers, it means that your GUID value is large enough to fill all 128 bits of the BigInteger or else the BigInteger byte[] ctor is interpreting the data as such. To make sure your bytes are actually positive, check that you are getting <= 16 bytes (128 bits) and that the most-significant bit of the last byte (because it's little endian) is zero. If you have <16 bytes, you can simply append a zero byte to your array (again, append because it is little endian) to make sure the BigInteger ctor treats it as a positive number.
This article I think it can give you the solution:
In summary it is to add one more byte, to 0, if the most significant bit of the last byte is a 1
Guid original = Guid.NewGuid();
byte[] bytes = original.ToByteArray();
if ((bytes[bytes.Length - 1] & 0x80) > 0)
{
byte[] temp = new byte[bytes.Length];
Array.Copy(bytes, temp, bytes.Length);
bytes = new byte[temp.Length + 1];
Array.Copy(temp, bytes, temp.Length);
}
BigInteger guidPositive = new BigInteger(bytes);
Related
so I am outputting the char 0x11a1 by converting it to char
than I multiply 0x11a1 by itself and output it again but I do not get what I expect to get as
by doing this {int hgvvv = chch0;} and outputting to the console I can see that the computer thinks that 0x11a1 * 0x11a1 equals 51009 but it actually equals 20367169
As a result I do not gat what I want.
Could you please explain to me why?
char chch0 = (char)0x11a1;
Console.WriteLine(chch0);
chch0 = (char)(chch0 * chch0);
Console.WriteLine(chch0);
int hgvvv = chch0;
Console.WriteLine(hgvvv);
We know that 1 bytes is 8 bits.
We know that a char in c# is 2 bytes, which would be 16 bits.
If we multiply 0x11a1 X 0x11a1 we get 0x136c741.
0x136c741 in binary is 0001001101101100011101000001
Considering we only have 16 bits - we would only see the last 16 bits which is: 1100011101000001
1100011101000001 in hex is 0xc741.
This is 51009 that you are seeing.
You are being limited by the type size of char in c#.
Hope this answer cleared things up!
By enabling the checked context in your project or by adding it this way in your code:
checked {
char chch0 = (char)0x11a1;
Console.WriteLine(chch0);
chch0 = (char)(chch0 * chch0); // OverflowException
Console.WriteLine(chch0);
int hgvvv = chch0;
Console.WriteLine(hgvvv);
}
You will see that you will get an OverflowException, because the char type (2 bytes big) is only able to store values up to Char.MaxValue = 0xFFFF.
The value you expect (20367169) is larger than than 0xFFFF and you basically get only the two least significate bytes the type was able to store. Which is:
Console.WriteLine(20367169 & 0xFFFF);
// prints: 51009
I have a string that only contains 1 and 0 and I need to save this to a .txt-File.
I also want it to be as small as possible. Since I have binary code, I can turn it into pretty much everything. Saving it as binary is not an option, since apparently every character will be a whole byte, even if it's a 1 or a 0.
I thought about turning my string into an Array of Byte but trying to convert "11111111" to Byte gave me a System.OverflowException.
My next thought was using an ASCII Codepage or something. But I don't know how reliable that is. Alternatively I could turn all of the 8-Bit pieces of my string into the corresponding numbers. 8 characters would turn into a maximum of 3 (255), which seems pretty nice to me. And since I know the highest individual number will be 255 I don't even need any delimiter for decoding.
But I'm sure there's a better way.
So:
What exactly is the best/most efficient way to store a string that only contains 1 and 0?
You could represent all your data as 64 bit integers and then write them to a binary file:
// The string we are working with.
string str = #"1010101010010100010101101";
// The number of bits in a 64 bit integer!
int size = 64;
// Pad the end of the string with zeros so the length of the string is divisible by 64.
str += new string('0', str.Length % size);
// Convert each 64 character segment into a 64 bit integer.
long[] binary = new long[str.Length / size]
.Select((x, idx) => Convert.ToInt64(str.Substring(idx * size, size), 2)).ToArray();
// Copy the result to a byte array.
byte[] bytes = new byte[binary.Length * sizeof(long)];
Buffer.BlockCopy(binary, 0, bytes, 0, bytes.Length);
// Write the result to file.
File.WriteAllBytes("MyFile.bin", bytes);
EDIT:
If you're only writing 64 bits then it's a one-liner:
File.WriteAllBytes("MyFile.bin", BitConverter.GetBytes(Convert.ToUInt64(str, 2)));
I would suggest using BinaryWriter. Like this:
BinaryWriter writer = new BinaryWriter(File.Open(fileName, FileMode.Create));
Can someone please advise, why after computed hash, stores a negative value to e?
static byte[] bytes;
BigInteger[] numbers = {A, ANeg, Aseed, AseedNeg, C1, C2, C1Neg, C2Neg};
foreach (BigInteger number in numbers)
{
bytes = number.ToByteArray();
}
SHA1 sha = new SHA1CryptoServiceProvider();
hash = sha.ComputeHash(bytes);
e = new BigInteger(hash);
For the same reason "-3" is negative and "2" isn't; the symbol used to indicate the number is below zero is there: In the case of someone writing down "-3" this is "-". In the case of a BigInteger, this is the most significant bit.
The BigInteger(byte[]) constructor documentation on MSDN offers the following:
if the highest-order bit of the highest-order byte in value is set, the resulting BigInteger value is negative
and
To prevent positive values from being misinterpreted as negative values, you can add a zero-byte value to the end of the array.
Applying the documentation:
e will be negative if the last byte in hash (i.e., hash[hash.Length - 1]) is greater than 0x7f (127).
To interpret the value of hash as an unsigned number, add a zero-byte value to the end of hash, e.g.,
e = new BigInteger(hash.Concat(new byte[]{0}).ToArray());
The problem
I have a byte[] that is converted to a hex string, and then that string is parsed like this BigInteger.Parse(thatString,NumberSyles.Hexnumber).
This seems wasteful since BigInteger is able to accept a byte[], as long as the two's complement is accounted for.
An working (inefficient) example
According to MSDN the most significant bit of the last byte should be zero in order for the following hex number be a positive one. The following is an example of a hex number that has this issue:
byte[] ripeHashNetwork = GetByteHash();
foreach (var item in ripeHashNetwork)
{
Console.Write(item + "," );
}
// Output:
// 0,1,9,102,119,96,6,149,61,85,103,67,158,94,57,248,106,13,39,59,238,214,25,103,246
// Convert to Hex string using this http://stackoverflow.com/a/624379/328397
// Output:
// 00010966776006953D5567439E5E39F86A0D273BEED61967F6`
Okay, let's pass that string into the static method of BigInteger:
BigInteger bi2 = BigInt.Parse(thatString,NumberSyles.Hexnumber);
// Output bi2.ToString() ==
// {25420294593250030202636073700053352635053786165627414518}
Now that I have a baseline of data, and known conversions that work, I want to make it better/faster/etc.
A not working (efficient) example
Now my goal is to round-trip a byte[] into BigInt and make the result look like 25420294593250030202636073700053352635053786165627414518. Let's get started:
So according to MSDN I need a zero in my last byte to avoid my number from being seen as a two's compliment. I'll add the zero and print it out to be sure:
foreach (var item in ripeHashNetwork)
{
Console.Write(item + "," );
}
// Output:
// 0,1,9,102,119,96,6,149,61,85,103,67,158,94,57,248,106,13,39,59,238,214,25,103,246,0
Okay, let's pass that byte[] into the constructor of BigInteger:
BigInteger bi2 = new BigInteger(ripeHashNetwork);
// Output bi2.ToString() ==
// {1546695054495833846267861247985902403343958296074401935327488}
What I skipped over is the sample of what bigInt does to my byte array if I don't add the trailing zero. What happens is that I get a negative number which is wrong. I'll post that if you want.
So what am I doing wrong?
When you are going via the hex string, the first byte of your array is becoming the most significant byte of the resulting BigInteger.
When you are adding a trailing zero, the last bye of your array is the most significant.
I'm not sure which case is right for you, but that's why you're getting different answers.
From MSDN "The individual bytes in the value array should be in little-endian order, from lowest-order byte to highest-order byte". So the mistake is the order of bytes:
BigInteger bi2 = new BigInteger(ripeHashNetwork.Reverse().ToArray<byte>());
I have a control that has a byte array in it.
Every now and then there are two bytes that tell me some info about number of future items in the array.
So as an example I could have:
...
...
Item [4] = 7
Item [5] = 0
...
...
The value of this is clearly 7.
But what about this?
...
...
Item [4] = 0
Item [5] = 7
...
...
Any idea on what that equates to (as an normal int)?
I went to binary and thought it may be 11100000000 which equals 1792. But I don't know if that is how it really works (ie does it use the whole 8 items for the byte).
Is there any way to know this with out testing?
Note: I am using C# 3.0 and visual studio 2008
BitConverter can easily convert the two bytes in a two-byte integer value:
// assumes byte[] Item = someObject.GetBytes():
short num = BitConverter.ToInt16(Item, 4); // makes a short
// out of Item[4] and Item[5]
A two-byte number has a low and a high byte. The high byte is worth 256 times as much as the low byte:
value = 256 * high + low;
So, for high=0 and low=7, the value is 7. But for high=7 and low=0, the value becomes 1792.
This of course assumes that the number is a simple 16-bit integer. If it's anything fancier, the above won't be enough. Then you need more knowledge about how the number is encoded, in order to decode it.
The order in which the high and low bytes appear is determined by the endianness of the byte stream. In big-endian, you will see high before low (at a lower address), in little-endian it's the other way around.
You say "this value is clearly 7", but it depends entirely on the encoding. If we assume full-width bytes, then in little-endian, yes; 7, 0 is 7. But in big endian it isn't.
For little-endian, what you want is
int i = byte[i] | (byte[i+1] << 8);
and for big-endian:
int i = (byte[i] << 8) | byte[i+1];
But other encoding schemes are available; for example, some schemes use 7-bit arithmetic, with the 8th bit as a continuation bit. Some schemes (UTF-8) put all the continuation bits in the first byte (so the first has only limited room for data bits), and 8 bits for the rest in the sequence.
If you simply want to put those two bytes next to each other in binary format, and see what that big number is in decimal, then you need to use this code:
if (BitConverter.IsLittleEndian)
{
byte[] tempByteArray = new byte[2] { Item[5], Item[4] };
ushort num = BitConverter.ToUInt16(tempByteArray, 0);
}
else
{
ushort num = BitConverter.ToUInt16(Item, 4);
}
If you use short num = BitConverter.ToInt16(Item, 4); as seen in the accepted answer, you are assuming that the first bit of those two bytes is the sign bit (1 = negative and 0 = positive). That answer also assumes you are using a big endian system. See this for more info on the sign bit.
If those bytes are the "parts" of an integer it works like that. But beware, that the order of bytes is platform specific and that it also depends on the length of the integer (16 bit=2 bytes, 32 bit=4bytes, ...)
In case that item[5] is the MSB
ushort result = BitConverter.ToUInt16(new byte[2] { Item[5], Item[4] }, 0);
int result = 256 * Item[5] + Item[4];