7 Replies - 850 Views - Last Post: 30 July 2012 - 01:11 PM Rate Topic: -----

#1 chris.whitley  Icon User is offline

  • New D.I.C Head
  • member icon

Reputation: 10
  • View blog
  • Posts: 39
  • Joined: 26-October 10

Float value not subtracting gracefully

Posted 30 July 2012 - 08:11 AM

Maybe I have a lack in understandign float values, but I can't seem to get one variable to subtract gracefully. This is what's happening:

I have one float variable, fValue, that initilizes at 1.0f. Then in the coding, during an event, i want that value to decrease by 0.01f each time the even occurs, but not go below 0.10f. It's a simple concept, so I wrote a small Console script that will reflect this. Here is my code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace testingFloat
{
    
    class Program
    {
        

        static void Main(string[] args)
        {
            float fValue = 1.0f;
            do
            {
                Console.WriteLine(fValue);
                fValue -= 0.01f;
            } while (fValue > 0.10f);

        }
    }
}



When i run this, the following is my output

1
0.99
0.98
0.97
0.96
0.95
0.9400001
0.9300001
0.9200001
0.9100001
0.9000001
0.8900001
0.8800001
0.8700001
0.8600001
0.8500001
0.8400002
0.8300002
0.8200002
0.8100002
0.8000002
0.7900002
0.7800002
0.7700002
0.7600002
0.7500002
0.7400002
0.7300003
0.7200003
0.7100003
0.7000003
0.6900003
0.6800003
0.6700003
0.6600003
0.6500003
0.6400003
0.6300004
0.6200004
0.6100004
0.6000004
0.5900004
0.5800004
0.5700004
0.5600004
0.5500004
0.5400004
0.5300004
0.5200005
0.5100005
0.5000005
0.4900005
0.4800005
0.4700005
0.4600005
0.4500005
0.4400005
0.4300005
0.4200006
0.4100006
0.4000006
0.3900006
0.3800006
0.3700006
0.3600006
0.3500006
0.3400006
0.3300006
0.3200006
0.3100007
0.3000007
0.2900007
0.2800007
0.2700007
0.2600007
0.2500007
0.2400007
0.2300007
0.2200007
0.2100007
0.2000007
0.1900007
0.1800007
0.1700007
0.1600007
0.1500007
0.1400007
0.1300007
0.1200007
0.1100007
0.1000007
Press any key to continue . . .



Everytime, when it reaches 0.94 something seems to be going wrong with the subtraction. I have no idea what this is. Can anyone explain why this is happening and/or a way to resolve it?

Is This A Good Question/Topic? 0
  • +

Replies To: Float value not subtracting gracefully

#2 Curtis Rutland  Icon User is online

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4453
  • View blog
  • Posts: 7,755
  • Joined: 08-June 10

Re: Float value not subtracting gracefully

Posted 30 July 2012 - 08:28 AM

I'm just going to throw this link out there:

http://docs.oracle.c...g_goldberg.html

I know it's a lot of information, but it's important to understand how floating point math works.

Basically, you can't accurately represent values like .1 in binary. So, you're going to see things like rounding errors.

You could try rounding yourself, or you could use a decimal

decimal fValue = 1.0m;
do
{
    Console.WriteLine(fValue);
    fValue -= 0.01m;
} while (fValue > 0.10m);
Console.ReadKey();



Decimals are stored as base 10 floating points, so no accuracy is lost.
Was This Post Helpful? 2
  • +
  • -

#3 jon.kiparsky  Icon User is online

  • Pancakes!
  • member icon


Reputation: 7624
  • View blog
  • Posts: 12,854
  • Joined: 19-March 11

Re: Float value not subtracting gracefully

Posted 30 July 2012 - 09:01 AM

Now that you know what's causing the problem, the easiest thing is to format that number to 2 decimal places.

By the way - and I don't know if this is covered in the linked page - it's also not good to expect floats to provide exact equality. Instead, if you need to compare equality of f1 and f2, you can do something like:

|f1 - f2| < TOLERANCE

where TOLERANCE is a constant greater than the maximum error you want to allow for a single operation.

EDIT: You might also like to take a look at Guy Steele's paper called "How To Print Floating-Point Numbers Accurately" - there's some math in there, but it's a really interesting read.

This post has been edited by jon.kiparsky: 30 July 2012 - 09:06 AM

Was This Post Helpful? 3
  • +
  • -

#4 Curtis Rutland  Icon User is online

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4453
  • View blog
  • Posts: 7,755
  • Joined: 08-June 10

Re: Float value not subtracting gracefully

Posted 30 July 2012 - 09:28 AM

Actually, the easiest thing to do is to switch to the decimal type. It takes four times the memory of a float, but it has no accuracy or rounding issues, since the number is stored as a decimal rather than binary. I say easiest because it involves no logical changes, just a change of type. You also have to use the literal postfix "m" instead of "f".
Was This Post Helpful? 1
  • +
  • -

#5 chris.whitley  Icon User is offline

  • New D.I.C Head
  • member icon

Reputation: 10
  • View blog
  • Posts: 39
  • Joined: 26-October 10

Re: Float value not subtracting gracefully

Posted 30 July 2012 - 09:44 AM

View PostCurtis Rutland, on 30 July 2012 - 09:28 AM, said:

Actually, the easiest thing to do is to switch to the decimal type. It takes four times the memory of a float, but it has no accuracy or rounding issues, since the number is stored as a decimal rather than binary. I say easiest because it involves no logical changes, just a change of type. You also have to use the literal postfix "m" instead of "f".


The increase in memory size is one of the things I was worried about. In the situation where the float is being used both in my original post as well as in my actual script, there isn't much in the way of calculations, blocks of code, etc. so the increase in memory would be fine.

I am however working on a game using the XNA 4.0 framework and do get worried that on a much larger scale, this increase in memory to use double vs float could cause slowness due to calculations using more memory.

What I think I'll do is try using both for a bit, one script using one and a copy using the other other. Once it gets to a point where the memory differences may cause issues, I'll benchmark them. I'd rather not sacrifice accuracy for speed. Either way, I'm still new to some things like, so it's proving to be a great learning experience.

I think you both for your insite and references.
Was This Post Helpful? 0
  • +
  • -

#6 Curtis Rutland  Icon User is online

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4453
  • View blog
  • Posts: 7,755
  • Joined: 08-June 10

Re: Float value not subtracting gracefully

Posted 30 July 2012 - 10:32 AM

Well, for games, accuracy is sacrificed all the time. To be honest, a lot of floating point calculations don't have to be exact, since you don't care about rounding errors in the 10-6 range. But when you're repeatedly performing calculations on the result of calculations, the errors will get more and more significant.

True accuracy usually doesn't usually matter, unless you actually need it, like when you're dealing with money.

By the way, floats are fairly inaccurate just by themselves. They only have 7-8 digits of precision.

Edit: I found some relevant information:

http://gregs-blog.co...-vs-float-type/

Quote

Since Decimal types are perfectly accurate and float’s are not, why would we still want to use the intrinsic float/double types? Short answer – performance. In my speed tests Decimal types ran over 20 times slower than their float counterparts.

So if you’re writing a financial application for a bank that has to be 100% accurate and performance is not a consideration, use the Decimal type. On the other hand, if you need performance and extremely small floating point variations don’t affect your program, stick with the float and double types.

Was This Post Helpful? 0
  • +
  • -

#7 jon.kiparsky  Icon User is online

  • Pancakes!
  • member icon


Reputation: 7624
  • View blog
  • Posts: 12,854
  • Joined: 19-March 11

Re: Float value not subtracting gracefully

Posted 30 July 2012 - 12:04 PM

Quote

Since Decimal types are perfectly accurate and float’s are not, why would we still want to use the intrinsic float/double types?


There's an interesting conception of "perfectly accurate" here. Floats are as accurate as you could ask for, given the allotted space. Like any finite representation of a number, they can only represent what they have room to represent, and as a programmer part of your job is to decide how much accuracy is needed to represent what you're computing. Computation with floats certainly does not introduce error, as long as you stay within the allowable ranges of computation. What's not necessarily accurate is the conversion from binary to decimal, since the representations do not overlay perfectly.
But you'll notice that in the original question, the actual effect of this "error" was purely cosmetic, since we were only interested in the first and second decimal places.

The consequences of this are interesting from a mathematical point of view but the main take-home lesson for me is: know the edges of your computations, and understand how inaccuracies combine (when do they add, and when do they cancel?), and don't play near the edges. If you need more precision, use a double. If that's not enough, use a specialized big number class. And don't use floats to represent money, particularly not if there's any chance you'll ever be audited.

This post has been edited by jon.kiparsky: 30 July 2012 - 12:06 PM

Was This Post Helpful? 2
  • +
  • -

#8 Skydiver  Icon User is online

  • Code herder
  • member icon

Reputation: 3534
  • View blog
  • Posts: 10,941
  • Joined: 05-May 12

Re: Float value not subtracting gracefully

Posted 30 July 2012 - 01:11 PM

One of the tricks taught to us in a game development class was a "periodic reset" done by the game engine. Basically, use a running computation to keep mangling the rotation matrices, velocities, what have you. After X hundred or thousand cycles, recompute the rotation matrices, velocities, etc., from known good values like angles, thrust, time, etc. This keep the rounding errors from drifting too far away, but at the same time you keep the higher performance during most of the cycles.
Was This Post Helpful? 1
  • +
  • -

Page 1 of 1