When to use System.Convert and when to use System.BitConverter - c#

Please help me to understand the different between Convert and BitConverter. In the below example, the above two methods give me two different answer:
UInt64 x = 0x4028b0a3d70a3d71;
// Use Convert
double d = Convert.ToDouble(x); // d = 4.6231392352297441E+18
// Use BitConverter
byte[] xArray = BitConverter.GetBytes(x);
double d1 = BitConverter.ToDouble(xArray, 0); // d1 = 12.345
Thank you

These two methods are used for different purposes; Convert.ToDouble(x) is equivalent to a cast: (double)x; which can be useful if you need the integer value to be treated as a floating point value, say, for mathematical operations:
int x = 7;
Console.WriteLine(x / 3); // 2
Console.WriteLine(Convert.ToDouble(x) / 3); // 2.3333333333333335
Console.WriteLine((double)x / 3); // 2.3333333333333335
BitConverter class is useful if you want to transmit the value over the network as a series of bytes; you'd use the BitConverter.GetBytes() on the sending side, and BitConverter.ToOriginalType() on the receiving end:
double x = 12.345;
byte[] xArray = BitConverter.GetBytes(x);
// Send xArray to another system over the network
// ...on the receiving system, presuming same endianness:
double d1 = BitConverter.ToDouble(xArray, 0); // d1 = 12.345
Now, in your example, let's take a look at what happens to the value of x in both cases:
UInt64 x = 0x4028b0a3d70a3d71;
// Use Convert
double d = Convert.ToDouble(x); // d = 4.6231392352297441E+18
d is a cast of x to double; in decimal form, 0x4028b0a3d70a3d71 = 4,623,139,235,229,744,497 = 4.623139235229744497+18 in scientific notation. No magic here, it's pretty much what you'd expect to happen. Onward.
// Use BitConverter
byte[] xArray = BitConverter.GetBytes(x);
double d1 = BitConverter.ToDouble(xArray, 0); // d1 = 12.345
...what? well, let's see how the double type is stored in memory. According to IEEE 754 specification for double, the format is:
first bit is a sign bit (0 = positive; 1 = negative)
next 11 bits are the exponent
next 52 bits are the significand (well, 53, but only 52 are stored)
Here's the binary representation of 0x4028b0a3d70a3d71, arranged into the 3 sections we need to consider:
0 10000000010 1000101100001010001111010111000010100011110101110001
The following formula is used to convert this storage format to an actual numeric value:
(-1)sign x (1.b51b50...b0)base2 x 2exponent - 1023
Instead of going through this math manually, we can use this awesome floating point converter; here's the snapshot of the result:
See the decimal result? 12.345, same as what you're getting with BitConverter.ToDouble(xArray, 0) - but certainly not the same as the casting operation performed by Convert.ToDouble(x)

The first:
you convert int hex representation to double
The second:
you treat the value in x as a bit representation of a double, not integer.

Related

C#. Strange behavior of double

Here is the code which made me post this question.
// int integer;
// int fraction;
// double arg = 110.1;
this.integer = (int)(arg);
this.fraction = (int)((arg - this.integer) * 100);
The variable integer is getting 110. That's OK.
The variable fraction is getting 9, however I am expecting 10.
What is wrong?
Update
It seems I have discovered that the source of the problem is subtraction
arg - this.integer
Its result is 0.099999999999994316.
Now I am wondering how I should correctly subtract so that the result was 0.1.
You have this:
fraction = (int)((110.1 - 110) * 100);
The inner part ((110.1 - 110) * 100), will be 9.999999
When you cast it to int, it will be round off to 9
This is because of "floating point" (see here) limitations:
Computers always need some way of representing data, and ultimately
those representations will always boil down to binary (0s and 1s).
Integers are easy to represent, but non-integers are a bit more
tricky. Consider the following var:
double x = 0.1d;
The variable x will actually store the closest available double to
that value. When you understand this, it becomes obvious why some
calculations seem to be "wrong".
If you were asked to add a third to a third, but could only use 3
decimal places, you'd get the "wrong" answer: the closest you could
get to a third is 0.333, and adding two of those together gives 0.666,
rather than 0.667 (which is closer to the exact value of two thirds).
Update:
In financial applications or where the numbers are so important to be exact, you can use decimal data type:
(int)((110.1m - 110) * 100) //will be 10 (m is decimal symbol)
or:
decimal arg = 110.1m;
int integer = (int)(arg); //110
decimal fraction = (int)((arg - integer) * 100); //will be 10
It is because you are using double, precision gets rounded, if you want it to be 10 use decimal type:
check the following:
int integer;
int fraction;
decimal arg = 110.1M;
integer = (int)(arg);
decimal diff = arg - integer;
decimal multiply = diff * 100;
fraction = (int)multiply;//output will be 10 as you expect

How to (theoretically) print all possible double precision numbers in C#?

For a little personal research project I want to generate a string list of all possible values a double precision floating point number can have.
I've found the "r" formatting option, which guarantees that the string can be parsed back into the exact same bit representation:
string s = myDouble.ToString("r");
But how to generate all possible bit combinations? Preferably ordered by value.
Maybe using the unchecked keyword somehow?
unchecked
{
//for all long values
myDouble[i] = myLong++;
}
Disclaimer: It's more a theoretical question, I am not going to read all the numbers... :)
using unsafe code:
ulong i = 0; //long is 64 bit, like double
unsafe
{
double* d = (double*)&i;
for(;i<ulong.MaxValue;i++)
Console.WriteLine(*d);
}
You can start with all possible values 0 <= x < 1. You can create those by having zero for exponent and use different values for the mantissa.
The mantissa is stored in 52 bits of the 64 bits that make a double precision number, so that makes for 2 ^ 52 = 4503599627370496 different numbers between 0 and 1.
From the description of the decimal format you can figure out how the bit pattern (eight bytes) should be for those numbers, then you can use the BitConverter.ToDouble method to do the conversion.
Then you can set the first bit to make the negative version of all those numbers.
All those numbers are unique, beyond that you will start getting duplicate values because there are several ways to express the same value when the exponent is non-zero. For each new non-zero exponent you would get the value that were not possible to express with the previously used expontents.
The values between 0 and 1 will however keep you busy for the forseeable future, so you can just start with those.
This should be doable in safe code: Create a bit string. Convert that to a double. Output. Increment. Repeat.... A LOT.
string bstr = "01010101010101010101010101010101"; // this is 32 instead of 64, adjust as needed
long v = 0;
for (int i = bstr.Length - 1; i >= 0; i--) v = (v << 1) + (bstr[i] - '0');
double d = BitConverter.ToDouble(BitConverter.GetBytes(v), 0);
// increment bstr and loop

Convert 24 bit value to float and back

It is possible to convert 24 bit integer value into float and then back to 24 bit integer without losing data?
For example, let's consider 8 bit int, a byte, range is [-127..127] (we drop -128).
public static float ToFloatSample (byte x) { return x / 127f; }
So, if x == -127, result will be -1, if x == 127, result will be 1. If x == 64, result will be ~0.5
public static int ToIntSample (float x) { return (int) (x * 127f); }
So now:
int x = some_number;
float f = ToFloatSample (x);
int y = ToIntSample (f);
Will always x == y ? Using 8 bit int yes, but what if I use 24 bit?
Having thought about your question, I now understand what you're asking.
I understand you have 24-bits which represent a real number n such that -1 <= n <= +1 and you want to load this into an instance of System.Single, and back again.
In C/C++ this is actually quite easy with the frexp and ldexp functions, documented here ( how can I extract the mantissa of a double ), but in .NET it's a more involved process.
The C# language specification (and thusly, .NET) states it uses IEEE-754 1989 format, which means you'll need to dump the bits into an integer type so you can perform the bitwise logic to extract the components. This question has already been asked here on SO except for System.Double instead of System.Single, but converting the answer to work with Single is a trivial exercise for the reader ( extracting mantissa and exponent from double in c# ).
In your case, you'd want to store your 24-bit mantissa value in the low-24 bits of an Int32 and then use the code in that linked question to load and extract it from a Single instance.
Every integer in the range [-16777216, 16777216] is exactly representable as an IEEE 754 32-bit binary floating point number. That includes both the unsigned and 2's complement 24 bit integer ranges. Simple casting will do the job.
The range is wider than you would expect because there is an extra significand bit that is not stored - it is a binary digit that is known not to be zero.

C# double to integer

Lets say I have the double 42.433243 and I would like to convert it to the integer 42433243.
What is the code for doing that when the decimal length is random?
Further examples:
45.25 => 4525
125.152254 => 125152254
etc...
You can multiply the value by 10 as long as there are any fraction part:
Decimal m = 42.433243m;
while (m % 1 != 0) m *= 10;
int i = (int)m;
Quick and dirty:
double x = 42.25;
int big = int.Parse(x.ToString().Replace(".",""));
This doesn't work if the number is too big (e.g. overflow, bigger than 2^32 for int, or you could replace int with double on line 2 and get it a lot larger).
Let me know if you have other considerations.
Perhaps something like this would work.
while ((double_num - Math.floor(double_num)) != 0.0) double_num *= 10;
int num = (int) double_num;
int result = Convert.ToInt32(Regex.Match(digits.Replace(".","").Replace(",",""), #"^\d+$").Value);
A more direct way to do this would be to convert the number to a decimal and examine the bits.
The first 96 least-significant bits represents the mantissa while the 32 most-significant bits represents the exponent. So the actual value that you would be interested in is the 32 least significant bits. The Decimal.GetBits() method returns the bits as an array ints so all you need to do is grab the first int in the array. As long as the numbers don't exceed int.MaxValue, you're golden.
var number = 42.433243;
var asDecimal = (Decimal)number;
var bits = Decimal.GetBits(asDecimal);
var digits = bits[0]; // 42433243

How do you round a number to two decimal places in C#?

I want to do this using the Math.Round function
Here's some examples:
decimal a = 1.994444M;
Math.Round(a, 2); //returns 1.99
decimal b = 1.995555M;
Math.Round(b, 2); //returns 2.00
You might also want to look at bankers rounding / round-to-even with the following overload:
Math.Round(a, 2, MidpointRounding.ToEven);
There's more information on it here.
Try this:
twoDec = Math.Round(val, 2)
If you'd like a string
> (1.7289).ToString("#.##")
"1.73"
Or a decimal
> Math.Round((Decimal)x, 2)
1.73m
But remember! Rounding is not distributive, ie. round(x*y) != round(x) * round(y). So don't do any rounding until the very end of a calculation, else you'll lose accuracy.
Personally I never round anything. Keep it as resolute as possible, since rounding is a bit of a red herring in CS anyway. But you do want to format data for your users, and to that end, I find that string.Format("{0:0.00}", number) is a good approach.
Wikipedia has a nice page on rounding in general.
All .NET (managed) languages can use any of the common language run time's (the CLR) rounding mechanisms. For example, the Math.Round() (as mentioned above) method allows the developer to specify the type of rounding (Round-to-even or Away-from-zero). The Convert.ToInt32() method and its variations use round-to-even. The Ceiling() and Floor() methods are related.
You can round with custom numeric formatting as well.
Note that Decimal.Round() uses a different method than Math.Round();
Here is a useful post on the banker's rounding algorithm.
See one of Raymond's humorous posts here about rounding...
// convert upto two decimal places
String.Format("{0:0.00}", 140.6767554); // "140.67"
String.Format("{0:0.00}", 140.1); // "140.10"
String.Format("{0:0.00}", 140); // "140.00"
Double d = 140.6767554;
Double dc = Math.Round((Double)d, 2); // 140.67
decimal d = 140.6767554M;
decimal dc = Math.Round(d, 2); // 140.67
=========
// just two decimal places
String.Format("{0:0.##}", 123.4567); // "123.46"
String.Format("{0:0.##}", 123.4); // "123.4"
String.Format("{0:0.##}", 123.0); // "123"
can also combine "0" with "#".
String.Format("{0:0.0#}", 123.4567) // "123.46"
String.Format("{0:0.0#}", 123.4) // "123.4"
String.Format("{0:0.0#}", 123.0) // "123.0"
If you want to round a number, you can obtain different results depending on: how you use the Math.Round() function (if for a round-up or round-down), you're working with doubles and/or floats numbers, and you apply the midpoint rounding. Especially, when using with operations inside of it or the variable to round comes from an operation. Let's say, you want to multiply these two numbers: 0.75 * 0.95 = 0.7125. Right? Not in C#
Let's see what happens if you want to round to the 3rd decimal:
double result = 0.75d * 0.95d; // result = 0.71249999999999991
double result = 0.75f * 0.95f; // result = 0.71249997615814209
result = Math.Round(result, 3, MidpointRounding.ToEven); // result = 0.712. Ok
result = Math.Round(result, 3, MidpointRounding.AwayFromZero); // result = 0.712. Should be 0.713
As you see, the first Round() is correct if you want to round down the midpoint. But the second Round() it's wrong if you want to round up.
This applies to negative numbers:
double result = -0.75 * 0.95; //result = -0.71249999999999991
result = Math.Round(result, 3, MidpointRounding.ToEven); // result = -0.712. Ok
result = Math.Round(result, 3, MidpointRounding.AwayFromZero); // result = -0.712. Should be -0.713
So, IMHO, you should create your own wrap function for Math.Round() that fit your requirements. I created a function in which, the parameter 'roundUp=true' means to round to next greater number. That is: 0.7125 rounds to 0.713 and -0.7125 rounds to -0.712 (because -0.712 > -0.713). This is the function I created and works for any number of decimals:
double Redondea(double value, int precision, bool roundUp = true)
{
if ((decimal)value == 0.0m)
return 0.0;
double corrector = 1 / Math.Pow(10, precision + 2);
if ((decimal)value < 0.0m)
{
if (roundUp)
return Math.Round(value, precision, MidpointRounding.ToEven);
else
return Math.Round(value - corrector, precision, MidpointRounding.AwayFromZero);
}
else
{
if (roundUp)
return Math.Round(value + corrector, precision, MidpointRounding.AwayFromZero);
else
return Math.Round(value, precision, MidpointRounding.ToEven);
}
}
The variable 'corrector' is for fixing the inaccuracy of operating with floating or double numbers.
This is for rounding to 2 decimal places in C#:
label8.Text = valor_cuota .ToString("N2") ;
In VB.NET:
Imports System.Math
round(label8.text,2)
I know its an old question but please note for the following differences between Math round and String format round:
decimal d1 = (decimal)1.125;
Math.Round(d1, 2).Dump(); // returns 1.12
d1.ToString("#.##").Dump(); // returns "1.13"
decimal d2 = (decimal)1.1251;
Math.Round(d2, 2).Dump(); // returns 1.13
d2.ToString("#.##").Dump(); // returns "1.13"
Had a weird situation where I had a decimal variable, when serializing 55.50 it always sets default value mathematically as 55.5. But whereas, our client system is seriously expecting 55.50 for some reason and they definitely expected decimal. Thats when I had write the below helper, which always converts any decimal value padded to 2 digits with zeros instead of sending a string.
public static class DecimalExtensions
{
public static decimal WithTwoDecimalPoints(this decimal val)
{
return decimal.Parse(val.ToString("0.00"));
}
}
Usage should be
var sampleDecimalValueV1 = 2.5m;
Console.WriteLine(sampleDecimalValueV1.WithTwoDecimalPoints());
decimal sampleDecimalValueV1 = 2;
Console.WriteLine(sampleDecimalValueV1.WithTwoDecimalPoints());
Output:
2.50
2.00
One thing you may want to check is the Rounding Mechanism of Math.Round:
http://msdn.microsoft.com/en-us/library/system.midpointrounding.aspx
Other than that, I recommend the Math.Round(inputNumer, numberOfPlaces) approach over the *100/100 one because it's cleaner.
You should be able to specify the number of digits you want to round to using Math.Round(YourNumber, 2)
You can read more here.
Math.Floor(123456.646 * 100) / 100
Would return 123456.64
string a = "10.65678";
decimal d = Math.Round(Convert.ToDouble(a.ToString()),2)
public double RoundDown(double number, int decimalPlaces)
{
return Math.Floor(number * Math.Pow(10, decimalPlaces)) / Math.Pow(10, decimalPlaces);
}

Categories

Resources