Double precision when number converted from string - c#

I’m getting numbers from a database. Some are stored as double in the database and some are stored as string.
What I want to do is count the decimal number of caracters so : 345.34938 would give me a result of 5.
As I said, some of my double come from the database as double and some as string. I’m wondering if there could be any kind of problem when casting the string numbers to double, hence giving me wrong result when trying to count the decimals.
I think I should be ok but I’m afraid that in some situations I’ll end up receiving wrong double numbers when they’re casted from the string (thinking about having 1.9999999 instead of 2.0, things like that)...
Is there any kind of risk that casting my number from string to double would give me strange result when stored as double in my application ? Am I being to frisky around that ?

Consider converting the string representations to System.Decimal with the decimal.Parse method. Because for a decimal there's a much better correspondence between the value of the number and its string representation. Also, it can handle more digits.
A System.Decimal will preserve trailing zeros present in the string (like "2.7500"), which a System.Double will not.
But if your strings never have more than 15 digits in total (including digits before the decimal point .), your approach with double will probably work. But the exact number represented almost always differs from "what you see" with a double, so the number of decimal figures is to be understood as what double.ToString() shows...
Maybe it's easier to just use the string directly, like
int numberOfDecimals = myString.Length - (myString.IndexOf('.') + 1);

Related

Rounding the SIGNIFICANT digits in a double, not to decimal places [duplicate]

This question already has answers here:
Round a double to x significant figures
(17 answers)
Closed 7 years ago.
I need to round significant digits of doubles. Example
Round(1.2E-20, 0) should become 1.0E-20
I cannot use Math.Round(1.2E-20, 0), which returns 0, because Math.Round() doesn't round significant digits in a float, but to decimal digits, i.e. doubles where E is 0.
Of course, I could do something like this:
double d = 1.29E-20;
d *= 1E+20;
d = Math.Round(d, 1);
d /= 1E+20;
Which actually works. But this doesn't:
d = 1.29E-10;
d *= 1E+10;
d = Math.Round(d, 1);
d /= 1E+10;
In this case, d is 0.00000000013000000000000002. The problem is that double stores internally fractions of 2, which cannot match exactly fractions of 10. In the first case, it seems C# is dealing just with the exponent for the * and /, but in the second case it makes an actual * or / operation, which then leads to problems.
Of course I need a formula which always gives the proper result, not only sometimes.
Meaning I should not use any double operation after the rounding, because double arithmetic cannot deal exactly with decimal fractions.
Another problem with the calculation above is that there is no double function returning the exponent of a double. Of course one could use the Math library to calculate it, but it might be difficult to guarantee that this has always precisely the same result as the double internal code.
In my desperation, I considered to convert a double to a string, find the significant digits, do the rounding and convert the rounded number back into a string and then finally convert that one to a double. Ugly, right ? Might also not work properly in all case :-(
Is there any library or any suggestion how to round the significant digits of a double properly ?
PS: Before declaring that this is a duplicate question, please make sure that you understand the difference between SIGNIFICANT digits and decimal places
The problem is that double stores internally fractions of 2, which cannot match exactly fractions of 10
That is a problem, yes. If it matters in your scenario, you need to use a numeric type that stores numbers as decimal, not binary. In .NET, that numeric type is decimal.
Note that for many computational tasks (but not currency, for example), the double type is fine. The fact that you don't get exactly the value you are looking for is no more of a problem than any of the other rounding error that exists when using double.
Note also that if the only purpose is for displaying the number, you don't even need to do the rounding yourself. You can use a custom numeric format to accomplish the same. For example:
double value = 1.29e-10d;
Console.WriteLine(value.ToString("0.0E+0"));
That will display the string 1.3E-10;
Another problem with the calculation above is that there is no double function returning the exponent of a double
I'm not sure what you mean here. The Math.Log10() method does exactly that. Of course, it returns the exact exponent of a given number, base 10. For your needs, you'd actually prefer Math.Floor(Math.Log10(value)), which gives you the exponent value that would be displayed in scientific notation.
it might be difficult to guarantee that this has always precisely the same result as the double internal code
Since the internal storage of a double uses an IEEE binary format, where the exponent and mantissa are both stored as binary numbers, the displayed exponent base 10 is never "precisely the same as the double internal code" anyway. Granted, the exponent, being an integer, can be expressed exactly. But it's not like a decimal value is being stored in the first place.
In any case, Math.Log10() will always return a useful value.
Is there any library or any suggestion how to round the significant digits of a double properly ?
If you only need to round for the purpose of display, don't do any math at all. Just use a custom numeric format string (as I described above) to format the value the way you want.
If you actually need to do the rounding yourself, then I think the following method should work given your description:
static double RoundSignificant(double value, int digits)
{
int log10 = (int)Math.Floor(Math.Log10(value));
double exp = Math.Pow(10, log10);
value /= exp;
value = Math.Round(value, digits);
value *= exp;
return value;
}

C# Convert.ToDouble() loses decimal points when converting string to double

Let's say we have the following simple code
string number = "93389.429999999993";
double numberAsDouble = Convert.ToDouble(number);
Console.WriteLine(numberAsDouble);
after that conversion numberAsDouble variable has the value 93389.43. What can i do to make this variable keep the full number as is without rounding it? I have found that Convert.ToDecimal does not behave the same way but i need to have the value as double.
-------------------small update---------------------
putting a breakpoint in line 2 of the above code shows that the numberAsDouble variable has the rounded value 93389.43 before displayed in the console.
93389.429999999993 cannot be represented exactly as a 64-bit floating point number. A double can only hold 15 or 16 digits, while you have 17 digits. If you need that level of precision use a decimal instead.
(I know you say you need it as a double, but if you could explain why, there may be alternate solutions)
This is expected behavior.
A double can't represent every number exactly. This has nothing to do with the string conversion.
You can check it yourself:
Console.WriteLine(93389.429999999993);
This will print 93389.43.
The following also shows this:
Console.WriteLine(93389.429999999993 == 93389.43);
This prints True.
Keep in mind that there are two conversions going on here. First you're converting the string to a double, and then you're converting that double back into a string to display it.
You also need to consider that a double doesn't have infinite precision; depending on the string, some data may be lost due to the fact that a double doesn't have the capacity to store it.
When converting to a double it's not going to "round" any more than it has to. It will create the double that is closest to the number provided, given the capabilities of a double. When converting that double to a string it's much more likely that some information isn't kept.
See the following (in particular the first part of Michael Borgwardt's answer):
decimal vs double! - Which one should I use and when?
A double will not always keep the precision depending on the number you are trying to convert
If you need to be precise you will need to use decimal
This is a limit on the precision that a double can store. You can see this yourself by trying to convert 3389.429999999993 instead.
The double type has a finite precision of 64 bits, so a rounding error occurs when the real number is stored in the numberAsDouble variable.
A solution that would work for your example is to use the decimal type instead, which has 128 bit precision. However, the same problem arises with a smaller difference.
For arbitrary large numbers, the System.Numerics.BigInteger object from the .NET Framework 4.0 supports arbitrary precision for integers. However you will need a 3rd party library to use arbitrary large real numbers.
You could truncate the decimal places to the amount of digits you need, not exceeding double precision.
For instance, this will truncate to 5 decimal places, getting 93389.42999. Just replace 100000 for the needed value
string number = "93389.429999999993";
decimal numberAsDecimal = Convert.ToDecimal(number);
var numberAsDouble = ((double)((long)(numberAsDecimal * 100000.0m))) / 100000.0;

Most efficient/right practice to trim the meaningless zeroes at the end of a decimal

This is so many times repeated at SO, but I would want to state my question explicitly.
How is a decimal which would look like 2.0100 "rightly" presented to the user as
another "decimal" 2.01?
I see a lot of questions on SO where the input is a string "2.0100" and need a decimal 2.01 out of it and questions where they need decimal 2.0100 to be represented as string "2.01". All this can be achieved by basic string.Trim, decimal.Parse etc. And these are some of the approaches followed:
decimal.Parse(2.0100.ToString("G29"))
Using # literal
Many string.Format options.
Various Regex options
My own one I used till now:
if (2.0100 == 0)
return 0;
decimal p = decimal.Parse(2.0100.ToString().TrimEnd('0'));
return p == 2.0100 ? p : 2.0100;
But I believe there has to be some correct way of doing it in .Net (at least 4) which deals with numeric operation and not string operation. I am asking for something that is not dealing with the decimal as string because I feel that ain't the right method to do this. I'm trying to learn something new. And would fancy my chances of seeing at least .1 seconds of performance gain since I'm pulling tens of thousands of decimal values from database :)
Question 2: If it aint present in .Net, which is the most efficient string method to get a presentable value for the decimal?
Edit: I do not just want a decimal to be presented it to users. In that case I can use it as a string. I do want it as decimal back. I will have to process on those decimal values later. So going by ToString approach, I first needs to convert it to string, and then again parse it to decimal. I am looking for something that doesn't deal with String class. Some option to convert decimal .20100 to decimal .201?
The "extra zeroes" that occur in a decimal value are there because the System.Decimal type stores those zeroes explicitly. For a System.Decimal, 1.23400 is a different value from 1.234, even though numerically they are equal:
The scaling factor also preserves any trailing zeroes in a Decimal number. Trailing zeroes do not affect the value of a Decimal number in arithmetic or comparison operations. However, trailing zeroes can be revealed by the ToString method if an appropriate format string is applied.
It's important to have the zeroes because many Decimal computations involve significant digits, which are a necessity of many scientific and high-precision calculations.
In your case, you don't care about them, but the appropriate answer is not "change Decimal for my particular application so that it doesn't store those zeroes". Instead, it's "present this value in a way that's meaningful to my users". And that's what decimal.ToString() is for.
The easiest way to format a decimal in a given format for the user is to use decimal.ToString()'s formatting options.
As for representing the value, 2.01 is equal to 2.0100. As long as you're within decimal's precision, it shouldn't matter how the value is stored in the system. You should only be worried with properly formatting the value for the user.
Numbers are numbers and strings are strings. The concept of "two-ness" represented as a string in the English language is 2. The concept of "two-ness" represented as a number is not really possibly to show because when you observe a number you see it as a string. But for the sake of argument it could be 2 or 2.0 or 02 or 02.0 or even 10/5. These are all representations of "two-ness".
Your database isn't actually returning 2.0100, something that you are inspecting that value with is converting it to a string and representing it that way for you. Whether a number has zeros at the end of it is merely a preference of string formatting, always.
Also, never call Decimal.parse() on a decimal, it doesn't make sense. If you want to convert a decimal literal to a string just call (2.0100).ToString().TrimEnd('0')
As noted, a decimal that internally stores 2.0100 could differ from one that stores 2.01, and the default behaviour of ToString() can be affected.
I recommend that you never make use of this.
Firstly, decimal.Parse("2.0100") == decimal.Parse("2.01") returns true. While their internal representations are different this is IMO unfortunate. When I'm using decimal with a value of 2.01 I want to be thinking:
2.01
Not:
struct decimal
{
private int flags;
private int hi;
private int lo;
private int mid;
/methods that make this actually useful/
}
While different means of storing 2.01 in the above structure might exist, 2.01 remains 2.01.
If you care about it being presented as 2.01 and not as 2.0 or 2.0100 then you care about a string representation. Your concern is about how a decimal is represented as a string, and that is how you should think about it at that stage. Consider the rule in question (minimum and maximum significant figures shown, and whether to include or exclude trailing zeros) and then code a ToString call appropriate.
And do this close to where the string is used.
When you care about 2.01, then deal with it as a decimal, and consider any code where the difference between 2.01 and 2.0100 matters to be a bug, and fix it.
Have a clear split in your code between where you are using strings, and where you are using decimals.
Ok, so I'm answering for myself, I got a solution.
return d / 1.00000000000000000000000000000m
That just does it. I did some benchmarking as well (time presented as comments are mode, not mean):
Method:
internal static double Calculate(Action act)
{
Stopwatch sw = new Stopwatch();
sw.Start();
act();
sw.Stop();
return sw.Elapsed.TotalSeconds;
}
Candidates:
return decimal.Parse(string.Format("{0:0.#############################}", d));
//0.02ms
return decimal.Parse(d.ToString("0.#############################"));
//0.014ms
if (d == 0)
return 0;
decimal p = decimal.Parse(d.ToString().TrimEnd('0').TrimEnd('.'));
return p == d ? p : d;
//0.016ms
return decimal.Parse(d.ToString("G29"));
//0.012ms
return d / 1.00000000000000000000000000000m;
//0.007ms
Needless to cover regex options. I dont mean to say performance makes a lot of difference. I'm just pulling 5k to 20k rows at a time. But still it's nice to know a simpler and cleaner alternative to string approach exists.
If you liked the answer, pls redirect your votes to here or here or here.

System.Single accuracy with C#

In the example below the number 12345678.9 loses accuracy when it's converted to a string as it becomes 1.234568E+07. I just need a way to preserve the accuracy for large floating point numbers. Thanks.
Single sin1 = 12345678.9F;
String str1 = sin1.ToString();
Console.WriteLine(str1); // displays 1.234568E+07
If you want to preserve decimal numbers, you should use System.Decimal. It's as simple as that. System.Single is worse than System.Double in that as per the documentation:
By default, a Single value contains only 7 decimal digits of precision, although a maximum of 9 digits is maintained internally.
You haven't just lost information when you've converted it to a string - you've lost information in the very first line. That's not just because you're using float instead of double - it's because you're using a floating binary point number.
The decimal number 0.1 can't be represented accurately in a binary floating point system no matter how big you make the type...
See my articles on floating binary point and floating decimal point for more information. Of course, it's possible that you should be using double or even float and just not caring about the loss of precision - it depends on what you're trying to represent. But if you really do care about preserving decimal digits, then use a decimal-based type.
You can't. Simple as that. In memory your number is 12345679. Try the code below.
Single sin1 = 12345678.9F;
String str1 = sin1.ToString("r"); // Shows "all" the number
Console.WriteLine(sin1 == 12345679); // true
Console.WriteLine(str1); // displays 12345679
Technically r means (quoting from MSDN) round-trip: Result: A string that can round-trip to an identical number. so in reality it isn't showing all the decimals. It's only showing all the decimals needed to distinguish it from other possible values of Single. If you want to show all the decimals use F20.
If you want more precision use double or better use decimal. float has the precision that it has. As we say in Italy "Non puoi spremere sangue da una rapa" (You can't squeeze blood from a turnip)
You could also write an IFormatProvider for your purpose - but the precision doesn't get any better unless you use a different type.
this article may help - http://www.csharp-examples.net/string-format-double/

How to decide what to use - double or decimal? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
decimal vs double! - Which one should I use and when?
I'm using double type for price in my trading software.
I've noticed that sometimes there are a odd errors.
They occur if price contains 4 digits after "dot", like 2.1234.
When I sent from my program "2.1234" on the market order appears at the price of "2.1235".
I don't use decimal because I don't need "extreme" precision. I don't need to distinguish for examle "2.00000000003" from "2.00000000002". I need maximum 6 digits after a dot.
The question is - where is the line? When to use decimal?
Should I use decimal for any finansical operations? Even if I need just one digit after the dot? (1.1 1.2 etc.)
I know decimal is pretty slow so I would prefer to use double unless decimal is absolutely required.
Use decimal whenever you're dealing with quantities that you want to (and can) be represented exactly in base-10. That includes monetary values, because you want 2.1234 to be represented exactly as 2.1234.
Use double when you don't need an exact representation in base-10. This is usually good for handling measurements, because those are already approximations, not exact quantities.
Of course, if having or not an exact representation in base-10 is not important to you, other factors come into consideration, which may or may not matter depending on the specific situation:
double has a larger range (it can handle very large and very small magnitudes);
decimal has more precision (has more significant digits);
you may need to use double to interact with some older APIs that are not aware of decimal;
double is faster than decimal;
decimal has a larger memory footprint;
When accuracy is needed and important, use decimal.
When accuracy is not that important, then you can use double.
In your case, you should be using decimal, as its financial matter.
For financial operation I always use the decimal type
Use decimal it's built for representing powers of 10 well (i.e. prices).
Decimal is the way to go when dealing with prices.
If it's financial software you should probably use decimal. This wiki article summarises quite nicely.
A simple response is in this example:
decimal d = 0.3M+0.3M+0.3M;
bool ret = d == 0.9M; // true
double db = 0.3 + 0.3 + 0.3;
bool dret = db == 0.9; // false
the test with the double fails since 0.3 in its binary representation ( base 2 ) is periodic, so you loose precision the decimal is represented by BCD, so base 10, and you did not loose significant digit unexpectedly. The Decimal are unfortunately dramattically slower than double. Usually we use decimal for financial calculation, where any digit has to be considered to avoid tolerance, double/float for engineering.
Double is meant as a generic floating-point data type, decimal is specifically meant for money and financial domains. Even though double usually works just fine decimal might prevent problems in some cases (e.g. rounding errors when you get to values in the billions)
There is an Explantion of it on MSDN
As soon as you start to do calculations on doubles you may get unexpected rounding problems because a double uses a binary representation of the number while the decimal uses a decimal representation preserving the decimal digits. That is probably what you are experiencing. If you only serialize and deserialize doubles to text or database without doing any rounding you will actually not loose any precision.
However, decimals are much more suited for representing monetary values where you are concerned about the decimal digits (and not the binary digits that a double uses internally). But if you need to do complex calculations (e.g. integrals as used by actuary computations) you will have to convert the decimal to double before doing the calculation negating the advantages of using decimals.
A decimal also "remembers" how many digits it has, e.g. even though decimal 1.230 is equal to 1.23 the first is still aware of the trailing zero and can display it if formatted as text.
If you always know the maximum amount of decimals you are going to have (digits after the point). Then the best practice is to use fixed point notation. That will give you an exact result while still working very fast.
The simplest manner in which to use fixed point is to simply store the number in an int of thousand parts. For example if the price always have 2 decimals you would be saving the amount of cents ($12.45 is stored in an int with value 1245 which thus would represent 1245 cents). With four decimals you would be storing pieces of ten-thousands (12.3456 would be stored in an int with value 123456 representing 123456 ten-thousandths) etc etc.
The disadvantage of this is that you would sometimes need a conversion if for example you are multiplying two values together (0.1 * 0.1 = 0.01 while 1 * 1 = 1, the unit has changed from tenths to hundredths). And if you are going to use some other mathematical functions you also has to take things like this into consideration.
On the other hand if the amount of decimals vary a lot using fixed point is a bad idea. And if high-precision floating point calculations are needed the decimal datatype was constructed for exactly that purpose.

Categories

Resources