|
Thanks Peter,
PeterTheSwede wrote: The type float only gives you 7 digits of precision
But, Result2 as a float type, could have 9 digits in debugger, why when converting to string, it loses precision?
regards,
George
|
|
|
|
|
The reason for the 7-digit precision in ToString() is that the ULP for float is 2^-23 (approximately 10^-7). Showing more digits is generally misleading. However, the internal precision can sometimes be larger, up to a maximum of approximately nine digits, which is probably (wild guess) the reason the debugger chooses to show that many.
This is only briefly explained in the help for System.Single, but for a reasonably good definition of ULP and floating point arithmetics, look here[^].
Then again: Never use float . Use double . Except possibly at gunpoint. Consider float to be obsolete. And remember that in SQL Server, float is double and real is single (go figure).
Peter the small turnip
(1) It Has To Work. --RFC 1925[^]
|
|
|
|
|
Thanks Peter,
ULP is short for?
regards,
George
|
|
|
|
|
Again, that is here[^]
(and in case your browser doesn't allow you to search on the page, it's "Unit in the Last Place", which is defined as "the arithmetical difference between two consecutive representable floating-point numbers which have the same exponent")
Peter the small turnip
(1) It Has To Work. --RFC 1925[^]
|
|
|
|
|
Hi Peter,
1.
Great!
I did some further thinking and proofing yesterday. And I think there are values which could be represented precisely by base 10, like 0.1, while at the same time can not be represented by base 2.
But there is no values vice versa, i.e. the value could be represented by base 2, not but be able to represented by base 10. Any comments? Agree or not?
2.
So, I think only two kinds of numbers can not be represented by Decimal -- infinite (like 1/3) and the values too large/small which are out of range.
regards,
George
|
|
|
|
|
Hi!
Now you're starting to get really interesting...
1. I'm not competent enough with maths these days (I used to be an assistant teacher in numerical analysis, but that was almost 30 years ago) to either agree or disagree. I suspect you may be right, though, and I suspect it may be related to the fact that 10 is a multiple of 2. That is, binary 0.1 is representable as decimal 0.5, from which would follow that all values that can be represented with a finite number of binary digits should be representable with a finite number of decimal digits as well. But again, this is a guess, not a fact...
2. Again, I suspect you are right. Then again - there are an infinite number of values with an infinite number of decimals (or that require a larger number of digits to be exactly represented than any of the precisions we use - whether double , float or decimal ) regardless of base, and there are many calculations that can cause such values to appear. So: Rounding problems will occur in any case, whether we use binary or decimal.
However, when dealing with monetary calculations decimal has an advantage in that it behaves the way a financial calculator does - so it causes fewer surprises for accountants... Then again, you can accomplish the same by carefully using rounding with, say, double .
Peter the small turnip
(1) It Has To Work. --RFC 1925[^]
|
|
|
|
|
Thanks Peter,
"binary 0.1 is representable as decimal 0.5" -- you get it from 0 + 1 * 2 ^ (-1) = 0.5?
regards,
George
|
|
|
|
|
George_George wrote: "binary 0.1 is representable as decimal 0.5" -- you get it from 0 + 1 * 2 ^ (-1) = 0.5?
Precisely so! Binary fractions are negative powers of two, as in:
binary 0.1 = 2 ^ -1 = decimal 0.5
binary 0.01 = 2 ^ -2 = decimal 0.25
... and so on
It becomes even clearer when you consider the following decimal fractions:
decimal 0.1 = 10 ^ -1
decimal 0.01 = 10 ^ -2
... and so on
Same pattern, different base...
Peter the small turnip
(1) It Has To Work. --RFC 1925[^]
|
|
|
|
|
Thanks Peter!
Wonderful "long" help.
regards,
George
|
|
|
|
|
Finally a thought on using decimal (as others have suggested):
It doesn't solve the problem, it only moves it around a bit...
With decimal data types (such as decimal in C#) you still have the problem that for example 1/3 doesn't have an exact representation. It is always rounded to whatever precision you have (0.33333, 0.33333333333 or whatever - no matter how many decimals you add, it's never exactly 1/3).
What you do get rid of is the problem with values like 0.1 that have an exact decimal representation but don't have an exact binary representation. Or, to put it bluntly: using binary decimal, you no longer confuse people who don't understand how binary floating-point works.
So... if you need to cater for values such as 1/3 (and you always do - for example if you need to amortize a loan over 3 years you would divide by 3, and then you have to make sure you round it correctly), you pretty much have to do what I wrote in my previous answer even when using decimal data types (if you want to make sure you get results that people can understand and verify).
The exception is if you have a language like ADA or T-SQL (Microsofts SQL version) where you can define decimal types with exactly the number of decimals you need. In that case, the rounding I do in my examples is done automatically so you don't have to think about it in your code.
The general rule is: know what you do. It never fails, whether using binary or decimal representations...
Peter the small turnip
(1) It Has To Work. --RFC 1925[^]
modified on Thursday, May 29, 2008 7:09 AM
|
|
|
|
|
Hi Peter,
Your reply is so great! I am condering,
1. Why using Decimal type, we can represent 0.1 precisely? Because Decimal type will use base 10 other than base 2 to represent a number?
2. For the numbers (which can be precisely represented by base 2), are there any possibilities which they can not be represented by base 10 precisely? If yes, I think it is not correct to say Decimal has less issues compared with float type?
3. Both float and double will use base 2 as internal representation?
regards,
George
|
|
|
|
|
George_George wrote: 1. Why using Decimal type, we can represent 0.1 precisely? Because Decimal type will use base 10 other than base 2 to represent a number?
Exactly. Internally, I beleive that the C# decimal is represented as a scaled binary integer, but it behaves as if it were a "true" decimal type. And as the names imply, "decimal"=base 10, "binary"=base 2.
George_George wrote: 2. For the numbers (which can be precisely represented by base 2), are there any possibilities which they can not be represented by base 10 precisely? If yes, I think it is not correct to say Decimal has less issues compared with float type?
Regardless of base (10, 2 or whatever), some real numbers won't have a finite decimal (binal is the correct word in Swedish using base 2, I don't know the English word) representation. In base 2 I gave 1/10 (0.1) as an example, in base 2 I gave 1/3 as one. But there are others - infinitely many, in fact. This means that decimal floating-point types don't have less issues than binary floating-point types. They just have other issues.
One exception: Binary floating point types can confuse people who don't understand a) that they are binary or b) what that means. Decimal types don't have that issue. In all other respects (precision limits, error accumulation and whatever) they are identical.
Like I mentioned previously, though, there are also decimal fixed-point types (as in those you create using decimal(13,4) in SQL. These are even easier to understand for people working with economics, as the round everything to the specified number of decimals all the time. They're usually quite useless for advanced calculations, though.
George_George wrote: 3. Both float and double will use base 2 as internal representation?
Yes, they differ only in precision, range and size - see System.Single (=C# float) and System.Double (=C# double) in the documentation for details. A look at System.Decimal (=C# decimal) could be informative, too...
Peter the small turnip
(1) It Has To Work. --RFC 1925[^]
|
|
|
|
|
Thanks Peter,
1.
What means "a scaled binary integer"?
2.
0.1 is a great sample by you, which could be represented by base 10, but not base 2. Do you have an adverse sample, which could be represented by base 2, but not be able to represented to base 10?
3.
PeterTheSwede wrote: One exception: Binary floating point types can confuse people who don't understand a) that they are binary or b) what that means. Decimal types don't have that issue. In all other respects (precision limits, error accumulation and whatever) they are identical.
I think item a means Float and Double are both using base 2 as internal number represetation, correct? Your point b means?
regards,
George
|
|
|
|
|
George_George wrote: What means "a scaled binary integer"?
It is saved as an integer in binary (base 2) and information about the number of decimals (base 10). So if the number is 12345678 and the number of decimals is 5, the actual value is 123.45678. So... the type works as if it were decimal, while it is in fact "faking" that using a binary representation.
George_George wrote: Do you have an adverse sample, which could be represented by base 2, but not be able to represented to base 10?
No. Never thought about it - I can't even guarantee you that it exists. However, there DO exist values that can't be exactly represented in any base (1/3 or PI are two examples).
George_George wrote: I think item a means Float and Double are both using base 2 as internal number represetation, correct? Your point b means?
Hmmm... let me rephrase it:
Problem "a" with float and double is that people don't understand that they are binary floating-point types.
Problem "b" is that even if people do know that, they don't fully understand what it means.
So... there is no real problem with float and double. The "problem" is with people not understanding what they are and how they work...
Peter the small turnip
(1) It Has To Work. --RFC 1925[^]
|
|
|
|
|
Thanks Peter,
1.
PeterTheSwede wrote: It is saved as an integer in binary (base 2)
"It" you mean Decimal or Float/Double?
2.
PeterTheSwede wrote: o if the number is 12345678 and the number of decimals is 5, the actual value is 123.45678.
Why? How do you get the result 123.45678?
regards,
George
|
|
|
|
|
Hi!
1. I'm talking about System.Decimal (or just decimal in C#). The details are here:
System.Decimal[^]
2. The link explains this as well. This is a quote of the relevant text:
------
A decimal number is a floating-point value that consists of a sign, a numeric value where each digit in the value ranges from 0 to 9, and a scaling factor that indicates the position of a floating decimal point that separates the integral and fractional parts of the numeric value.
The binary representation of a Decimal value consists of a 1-bit sign, a 96-bit integer number, and a scaling factor used to divide the 96-bit integer and specify what portion of it is a decimal fraction. The scaling factor is implicitly the number 10, raised to an exponent ranging from 0 to 28. Therefore, the binary representation of a Decimal value is of the form, ((-2^96 to 2^96) / 10^(0 to 28)), where -2^96-1 is equal to MinValue, and 2^96-1 is equal to MaxValue.
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.
------
So, if the 96-bit integer number is 12345678 and the scaling factor is 5, the number represented is 123.45678 (12345678 / 10^5).
Peter the small turnip
(1) It Has To Work. --RFC 1925[^]
|
|
|
|
|
Thanks Peter,
For float and double, it uses base 2 to represent the value, and the bit is conforming to base 2 -- has value 0 and value 1.
But for the 96-bit used to represent Decimal value, which is in base 10 (from 0 to 9), as the bit has only value 0 and 1, I am wondering how it is represented?
regards,
George
|
|
|
|
|
Hi,
It's explained in the System.Decimal documentation, but if I explain it using other words you may get another chance at grasping it. But beware: it's a trick...
The trick is that the Decimal type stores binary integers (whole numbers) along with the number of decimal digits (the scaling factor) in that integer that belong to the right of the decimal point. As integers convert without rounding problems between binary and decimal, this makes it possible for the Decimal type behave as though it was truly decimal while in fact it is a "hybrid".
And again, the details are in the documentation (I sent you a link previously).
Peter the small turnip
(1) It Has To Work. --RFC 1925[^]
|
|
|
|
|
Great Peter!
I read the document,
a few more comments,
1.
"The Decimal value type is appropriate for financial calculations requiring large numbers of significant integral and fractional digits and no round-off errors." -- I do not agree no rounding error conclusion. Remember we discussed the case when data is realy too large/small which is out of range of Decimal, and the case of infinite numebr like 1/3? Any comments?
2.
"The binary representation of a Decimal value consists of a 1-bit sign, a 96-bit integer number, and a scaling factor used to divide the 96-bit integer and specify what portion of it is a decimal fraction." -- Decimal frantion means the right part of a decimal (right part of the decimal point)?
3.
"binary integers (whole numbers)" -- you mean the whole number (except the decimal point used to scale), for example, 123.456 is stored as base 2 form of 123456 with a scale factor of 3?
Binary integers means integer represented in storage in base 2?
(really sorry for my so many questions, my English is not very good and I am really interested to discuss with you.)
regards,
George
|
|
|
|
|
Hi again!
1. I agree. Like I noted before, there will always be round-off errors as some values can never be represented exactly in any (non-infinite) precision. The Microsoft person who wrote "no round-off errors" probably should have written "no round-off errors caused by conversions between base 2 and base 10" - perhaps he did and some editor cut it down, you never know...
2. Exactly. I think "fraction" is from Latin or Greek, meaning something like "not whole" or "part". The opposite of "integer"/"integral". The value 123.456 consists of an integral part (123) and a fraction (.456).
3. Exactly. 123456 is stored like 11110001001000000. The scaling factor (3, stored as 11 binary) tells us that when the number is converted back to it's decimal representation (123456), the last 3 digits belong to the fraction.
No problem with the many questions - I'm Swedish myself, so I recognize your situation - thirty years in this business does miracles with your English, though, so hang in there! However, I can't promise I'll always have time to answer - but because I find a lot of useful articles here and have professional use for them, I try to spend some time looking for stuff that I can answer - just to give something back to the community.
Peter the small turnip
(1) It Has To Work. --RFC 1925[^]
|
|
|
|
|
It is cool, Peter!
Any other more dedicated forums or newsgroups for discussing about numberic topics to refer? Sometimes, I feel this forum is more for discussion of pure C# programming engineering topics.
regards,
George
|
|
|
|
|
George_George wrote: Any other more dedicated forums or newsgroups for discussing about numberic topics to refer?
On CodeProject, that would be the Mathematics and Algorithms[^] forum. Haven't googled for similar boards elsewhere.
If it's stuff related only to the .NET Framework types (not specifically C#, the System.Decimal and other types we have discussed are the same regardless of language), the .NET Framework[^] forum would be a logical choice.
My best,
Peter the small turnip
(1) It Has To Work. --RFC 1925[^]
|
|
|
|
|
Great Peter!
I have found something interesting related to the topic to share here.
http://en.wikipedia.org/wiki/Rounding[^]
It is mentioned "For example, if an integer divided by 7 is rounded to an integer, a computational rounding error up to 1/14 in the division (which is much more than is possible in typical cases) does not affect the outcome." -- I am confused. I think the rounding error should always be from 0 to 0.5, why the rounding error is up to 1/14?
regards,
George
|
|
|
|
|
Hi all,
i am developing a application for ANPR system. My appliaction using thread pool.registerwaitforsingleobject to grab the frames per 40 msec and signal the other thread for processing the frame. My appliaction has crashing becuase of out of memory error. i am running this appliaction in a hi-spec computer. please find my source below.
Main thread
{
Grabframe gf = new Grabframe();
gf.run();
manualresetevent anprevent = new manualresetevent(false);
.. create instance for anprclass anprobj
anprprocessthread(anprobj.run);
anprprocessthread.start();
}
class Grabframe
{
void run()
{
manualresetevent me = new manualresetevent(false);
waitortimercallback thread_method = waitortimercallback(grabframe);
Threadpool.registerwaitforsingleobject(me,thread_method,stateobj,40,false);
me.set();
}
void grabframe(object state,bool timeinterval)
{
...grab the frame
//signal anpr thread
anprevent.set();
}
}// end class grabframe
//anprthread
class anpr
{
void run()
{
anprevent.waitone();
..do anprprocess
.. get frame from global
}
}// end anpr class
Actually i have tried to reset manualresetevent on threadpool obj 'me' and my application didn't crash but the performance of the anpr is dropped.
please provide me suggestion as soon as possible.
Thanks.
sumathi
|
|
|
|
|
sumathi pandarinathan wrote: My appliaction has crashing becuase of out of memory error.
This is likely related to GDI+ issues. Investigate that code.
|
|
|
|
|