simple math problem?

  • Thread starter Thread starter Param R.
  • Start date Start date
P

Param R.

Hi all, take a look at the following code:-

Dim val1, val2, val3 as single

val1 = 134410.10
val2 = 28494.11
val3 = (val1+val2)

If you end up echoing val3 it will have a value of 162,904.20. That is
wrong. It should be .21. Why is this happening??? We are having all kinds of
issues and please dont tell me not to use the Single data type because it is
a bit too late for that. We have millions of lines of code with the Single
data type.

thanks!
 
Param R. said:
Hi all, take a look at the following code:-

Dim val1, val2, val3 as single

val1 = 134410.10
val2 = 28494.11
val3 = (val1+val2)

If you end up echoing val3 it will have a value of 162,904.20. That is
wrong. It should be .21. Why is this happening???

Mr. Skeet has written an excellent article about floating point arithmetic:
Have a look at: http://www.yoda.arachsys.com/csharp/floatingpoint.html
We are having all kinds of issues and please dont tell me not to use the
Single data type because it is a bit too late for that. We have millions
of lines of code with the Single data type.

Find & Replace ?

Why did you use Single in the first place?

Niki
 
Param R. said:
Hi all, take a look at the following code:-

Dim val1, val2, val3 as single

val1 = 134410.10
val2 = 28494.11
val3 = (val1+val2)

If you end up echoing val3 it will have a value of 162,904.20. That is
wrong. It should be .21. Why is this happening??? We are having all kinds
of issues and please dont tell me not to use the Single data type because
it is a bit too late for that. We have millions of lines of code with the
Single data type.

thanks!
Welcome to the wonderful world of real number representation in a binary
digital system.
Real numbers (e.g. numbers with a whole number and a decimal-fraction part
such as the ones you used, can only be approximated in a binary system.
To get the closest possible approximation, use the greatest precision
available. You used the least precision, short of truncating the
decimal-fraction portion by using an integer type.
By declaring your variables as doubles, your error goes away. QED.
If your example numbers represent money, you're still in trouble. There is a
third, most precise, real number datatype available to you designed
specifically for highest precision work with things like money. That type is
Decimal.

As far as not going back and doing it right is concerned, the original
design (especially the decision to use Singles) is flawed. I see no
alternative to fixing it.
 
We used Single simply because we did not have a need for more than 2 places
after the decimal point and Double/Decimal was overkill in terms of memory
usage etc..

I wish we could do a find/replace, but it is a little more complicated than
that. We using Remoting/Web Services, objects in several places will need to
be updated.

thanks!
 
Yes, all my data types are used to represent money. Oh well, I wish MS had
put in their documentation on the Single type somewhere that it should not
be used for currencies. They should have put it right here:-

Represents a single-precision floating point number.

For a list of all members of this type, see Single Members.

System.Object
System.ValueType
System.Single

[Visual Basic]
<Serializable>
Public Structure Single
Implements IComparable, IFormattable, IConvertible
[C#]
[Serializable]
public struct Single : IComparable, IFormattable, IConvertible
[C++]
[Serializable]
public __value struct Single : public IComparable, IFormattable,
IConvertible
[JScript] In JScript, you can use the structures in the .NET Framework, but
you cannot define your own.

Thread Safety
Any public static (Shared in Visual Basic) members of this type are safe for
multithreaded operations. Any instance members are not guaranteed to be
thread safe.

Remarks
The Single value type represents a single-precision 32-bit number with
values ranging from negative 3.402823e38 to positive 3.402823e38, as well as
positive or negative zero, PositiveInfinity, NegativeInfinity, and not a
number (NaN).

Single complies with the IEC 60559:1989 (IEEE 754) standard for binary
floating-point arithmetic.

Single provides methods to compare instances of this type, convert the value
of an instance to its string representation, and convert the string
representation of a number to an instance of this type.

For information about how format specification codes control the string
representation of value types, see Formatting Overview.This type implements
interfaces IComparable, IFormattable, and IConvertible. Use the Convert
class for conversions instead of this type's explicit interface member
implementation of IConvertible.

When performing binary operations, if one of the operands is a
floating-point type, Single or Double, then the other operand is required to
be an integral type or a floating-point type. The operation is evaluated as
follows:

a.. If one of the operands is of an integral type, then that operand is
converted to the floating-point type of the other operand.
b.. Then, if either of the operands is Double, the other operand is
converted to Double, and the operation is performed using at least the range
and precision of the Double. For numeric operations, the type of the result
is Double.
c.. Otherwise, the operation is performed using at least the range and
precision of the Single type and, for numeric operations, the type of the
result is Single.
The floating-point operators, including the assignment operators, do not
throw exceptions. Instead, in exceptional situations, the result of a
floating-point operation is zero, infinity, or NaN, as described below:

a.. If the result of a floating-point operation is too small for the
destination format, the result of the operation is zero.
b.. If the magnitude of the result of a floating-point operation is too
large for the destination format, the result of the operation is
PositiveInfinity or NegativeInfinity, as appropriate for the sign of the
result.
c.. If a floating-point operation is invalid, the result of the operation
is NaN.
d.. If one or both operands of a floating-point operation are NaN, the
result of the operation is NaN.
Requirements
Namespace: System

Platforms: Windows 98, Windows NT 4.0, Windows Millennium Edition, Windows
2000, Windows XP Home Edition, Windows XP Professional, Windows Server 2003
family, .NET Compact Framework - Windows CE .NET

Assembly: Mscorlib (in Mscorlib.dll)

See Also

thanks!
 
He ends the article with "binary floating point is generally faster on
current hardware than decimal floating point." So which one should I use for
the best combination of precision and performance? I dont need 10 places
after the decimal point. I just need 2 to be stored accurately since most of
my calculations involve money.

thanks!
 
Param R. said:
He ends the article with "binary floating point is generally faster on
current hardware than decimal floating point." So which one should I use
for the best combination of precision and performance? I dont need 10
places after the decimal point. I just need 2 to be stored accurately
since most of my calculations involve money.

thanks!
You need to read up on the Decimal type. You keep saying that you need only
two places to the right of the decimal point, but that's not the issue. You
need all the precision you can get to avoid the types of errors you
demonstrated in your original post.

I'd suggest you read the article "Decimal Data Type" in the Visual Studio
help. FWIW, in VB.NET, Decimal replaces the VB 6 Currency data type.
 
Param R. said:
He ends the article with "binary floating point is generally faster on
current hardware than decimal floating point." So which one should I use for
the best combination of precision and performance? I dont need 10 places
after the decimal point. I just need 2 to be stored accurately since most of
my calculations involve money.

If you are doing calculations involving money, you should almost
certainly use the decimal type.

You seem to be worried about performance, but do you have any concrete
data to say that your bottlenecks are actually in the calculations,
rather than IO, database access etc?
 
Param R. said:
He ends the article with "binary floating point is generally faster on
current hardware than decimal floating point." So which one should I use
for the best combination of precision and performance? I dont need 10
places after the decimal point. I just need 2 to be stored accurately
since most of my calculations involve money.

In a floating point number, the decimal point might not be where you'd
expect it, so you probably need a lot more digits after it that you'd think.
In your original example "val1 = 134410.10" will be represented as
"1.3441010E+5", so you'd need at least 7 digits after the decimal point.
(And even then the value might be incorrect, because there might be no
binary representation for your value)

I'd suggest using the Decimal type, if you can live with the size/speed
penalty. Otherwise, if you can give a maximum range for your values, you
could use integer math (Int or Long datatype), and do all calculations in
Cents (or is the smallest monetarian unit in your country).

Niki
 
Param said:
Yes, all my data types are used to represent money.
In most banking organizations, it is strictly forbidden to use a floating
point representation for money because, whatever precision (ie number of
digits) you use, floating point calculation *always* involves some
imprecision (btw, it is also true on your pocket calculator).
Floating point arithmetic IS NOT real arithmetic : it is an entirely
different field that gives approximately the same results in most of the
cases.
Oh well, I wish
MS had put in their documentation on the Single type somewhere that
it should not be used for currencies.
I believe it was considered to be common knowledge, known and understood by
every programmer. What is more, it is descripted in (excrutiating) details
in the referenced ISO standard IEC 60559:1989 (IEEE 754).

If you need a good reference on the subject, see
http://docs.sun.com/source/806-3568/ncg_goldberg.html

Arnaud
MVP - VC
 
Lets leave aside database and IO for a second. Lets assume my apps dont use
them. If I have an object with about 1000 Decimal variables. As per the docs
this will consume 16,000 bytes of memory or roughly 15K. Now if my server
had 1GB RAM, that would give me a max possible of about 69,000 objects
living in memory. Ofcourse that is assuming all memory is reserved for my
objects which is not the case. OS, Services etc need RAM. I guess I could
add more RAM if the server could take it.

thanks!
 
Param R. said:
Lets leave aside database and IO for a second. Lets assume my apps dont use
them. If I have an object with about 1000 Decimal variables. As per the docs
this will consume 16,000 bytes of memory or roughly 15K. Now if my server
had 1GB RAM, that would give me a max possible of about 69,000 objects
living in memory. Ofcourse that is assuming all memory is reserved for my
objects which is not the case. OS, Services etc need RAM. I guess I could
add more RAM if the server could take it.

And do you have many objects with 1000 decimal variables, that you'll
need 69,000 of at a time? Those both sound like fairly rare situations
to me. Of course, you know more than I do about your application,
but...
 
Arnaud Debaene said:
In most banking organizations, it is strictly forbidden to use a floating
point representation for money because, whatever precision (ie number of
digits) you use, floating point calculation *always* involves some
imprecision (btw, it is also true on your pocket calculator).
Floating point arithmetic IS NOT real arithmetic : it is an entirely
different field that gives approximately the same results in most of the
cases.

Note that if that's the case, that prevents the use of decimal as well,
which is also a floating point type - it's just a floating decimal
point type rather than a floating binary point type.
 
Param R. said:
So if i am writing apps for the banking then what data type should i
use?

Decimal, almost certainly. The fact that it's a floating point type
isn't a problem, so long as you don't stretch it beyond the boundaries
of what it can do. (Basically, so long as you know the limits and you
don't require anything more than them, you'll be fine.)

If you required *absolute* accuracy, you'd need a type which
effectively remembered or composed every operation you performed on it
- whether that's multiplication, division, raising to powers, etc. For
instance, any floating point representation of the square root of 2 is
going to be inaccurate, unless it's in a base which is actually a
multiple or fraction of root 2, which is somewhat unlikely. Most
financial apps probably don't require roots, however.
 
Our apps mostly deal with currencies and operations include
(+-*/,^%abs,floor,RATE,PMT,)... Can Decimal handle that?
 
Param R. said:
Our apps mostly deal with currencies and operations include
(+-*/,^%abs,floor,RATE,PMT,)... Can Decimal handle that?

Well, it depends on exactly what you want to do. For instance, if you
divide 1 by 3, you won't get an exact answer, because you can't exactly
represent a third in decimal.

Anything you can represent in decimal (within the specified range)
should be accurately represented though.
 
Well most of my functions I end up wrapping with a round function anyways to
2 decimal places.... and that is why I chose Single to start off with

thanks!
 
Back
Top