Bugs with Single

  • Thread starter Bill Ataras via .NET 247
  • Start date
B

Bill Ataras via .NET 247

I need to be able to take a dollars and cents amount stored in asingle, multiply it by 100 and store it in an Int32 as thenumber of pennies. Ie, I want to convert a Single of $1.23F intoan Int32 of 1230. I'm getting unreliable behavior from Singlesthough. Here is code to reproduce the problem:

Problem 1:

Single val = 0.01F; // Start with a penny
Int32 ival = (Int32)(val*100.0F);
Single sval = val * 100.0F;

In this problem, ival becomes 0 and sval becomes 1.0, yet valshows up as 0.01

Problem 2:

Single val = 0.53F;
Single sval = val * 100.0F;
Int32 ival = (Int32)sval;
Int32 ival2 = (Int32)(val*100.0F);

In this problem, ival and ival2 become 52 and sval becomes52.9999962, yet val shows up as 0.53

This looks like a bug to me. And no, I can't switch to doubles.And I can't use Convert.ToInt32 as it rounds and my original'val' may have a sub-penny value that I want truncated (ie1.2357F should convert to 1230 Int32).


thanks
 
N

Niki Estner

Double's wouldn't help you much either. Floating point numbers can't
represent every real number. The closest representable number to 0.01 might
actually be (something like) 0.0099999999999. Multiplying that with 100 and
truncating it will give 0 as result. (Don't get fooled by watch variables or
Double.Format: These do round!)

You'll have to use rounding, or switch to another data type.

Niki

I need to be able to take a dollars and cents amount stored in a single,
multiply it by 100 and store it in an Int32 as the number of pennies. Ie, I
want to convert a Single of $1.23F into an Int32 of 1230. I'm getting
unreliable behavior from Singles though. Here is code to reproduce the
problem:

Problem 1:

Single val = 0.01F; // Start with a penny
Int32 ival = (Int32)(val*100.0F);
Single sval = val * 100.0F;

In this problem, ival becomes 0 and sval becomes 1.0, yet val shows up as
0.01

Problem 2:

Single val = 0.53F;
Single sval = val * 100.0F;
Int32 ival = (Int32)sval;
Int32 ival2 = (Int32)(val*100.0F);

In this problem, ival and ival2 become 52 and sval becomes 52.9999962, yet
val shows up as 0.53

This looks like a bug to me. And no, I can't switch to doubles. And I can't
use Convert.ToInt32 as it rounds and my original 'val' may have a sub-penny
value that I want truncated (ie 1.2357F should convert to 1230 Int32).


thanks
 
N

Nick Malik

As others have pointed out, the value 0.01 in base 10 is not accurately
stored in binary. That's ok, because the fraction 1/3, which is a repeating
decimal in base 10 is exactly stored in binary... so it's a trade off.

The currency type of VB6 (gone now), was basically an int64 value that
stored the figure scaled by 1000.

The correct datatype to use is Decimal. This datatype does not store the
numeric value as a binary number. Instead, it stores each digit as a
seperate binary value (like a compressed numeric string) along with codes
for offset from the radix (powers of ten). This allows a highly accurate
representation of numbers of a particular size, and predictable mathematics.
You may be able to solve your problem simply by using the Decimal type
without resorting to converting it yourself to another representation (which
you appear to be doing).

This is not a new problem. I studied this on my college courses on binary
mathematics... in 1983. In 20 years, this fundamental aspect of programming
has not changed, and neither have the solutions.

Hope this helps,
--- Nick

I need to be able to take a dollars and cents amount stored in a single,
multiply it by 100 and store it in an Int32 as the number of pennies. Ie, I
want to convert a Single of $1.23F into an Int32 of 1230. I'm getting
unreliable behavior from Singles though. Here is code to reproduce the
problem:

Problem 1:

Single val = 0.01F; // Start with a penny
Int32 ival = (Int32)(val*100.0F);
Single sval = val * 100.0F;

In this problem, ival becomes 0 and sval becomes 1.0, yet val shows up as
0.01

Problem 2:

Single val = 0.53F;
Single sval = val * 100.0F;
Int32 ival = (Int32)sval;
Int32 ival2 = (Int32)(val*100.0F);

In this problem, ival and ival2 become 52 and sval becomes 52.9999962, yet
val shows up as 0.53

This looks like a bug to me. And no, I can't switch to doubles. And I can't
use Convert.ToInt32 as it rounds and my original 'val' may have a sub-penny
value that I want truncated (ie 1.2357F should convert to 1230 Int32).


thanks
 
J

Jon Skeet [C# MVP]

Nick Malik said:
As others have pointed out, the value 0.01 in base 10 is not accurately
stored in binary. That's ok, because the fraction 1/3, which is a repeating
decimal in base 10 is exactly stored in binary... so it's a trade off.

In what way is 1/3 exactly stored in binary? Anything with an exact
binary representation has an exact decimal representation, as 2 is a
factor of 10. (Take any number with an exact decimal representation and
halve it, and you'll always have an exact decimal representation still.
A binary representation is only a sum of such numbers, therefore any
number exactly representable in binary is exactly representable in
decimal.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Top