Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Very low floating point precision error?

Discussion in 'Editor & General Support' started by Tomnnn, Sep 14, 2014.

  1. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    I know floating points are precise to a point, but how come I'm having issues at only 4 places? Since ParticleSystem.Particle particles cannot be tracked or have components added to them I'm tracking them by size differences of 0.001f.

    I'm printing the results and I see x.xx1 for most of them but a handful of them are x.xx0999999f. Is there a way to stop this rounding error? And why am I even having this error at such a low precision? Any help would be appreciated, thanks.

    In case it matters, I'm using something like Number - (int)(Number) to grab just the decimal for comparisons. Is that giving me the producing the rounding error? Either way please let me know how to stop this. I can't just round the value because I'm using that place and the one next to it for particle tracking purposes.

    --edit

    It looks like when I go to 0.001f to 0.0012f the precision issue is consistent so I should be able to round without problems, nevermind. I'm still curious if there is a way to stop 1.2f- 0.2f from becoming 0.999999999f.
     
    Last edited: Sep 14, 2014
    User10101 likes this.
  2. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,500
    You're having the error because floating points don't store exact numbers - they store approximations. Some specific numbers happen to be stored exactly, but most are not. When you're working with floats you have to just accept that and deal with it. For this reason you should pretty much never check for equality (==) with floating point numbers, regardless of precision, and when checking inequality you need to be mindful as well.

    If you do actually require exact discreet values I suggest considering the use of a fixed-precision data format instead. I've not done that in C# myself, but here's a discussion that may be a handy starting point.
     
    npsf3000 likes this.
  3. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    A quicker and easier way to handle decimal numbers might be to use the decimal class.
     
  4. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,500
    That's discussed in either the thread I linked or another I found in my quick search. Apparently it's still based on floating points behind the scenes, so it's pretty good but still not perfect. I didn't look into why, so it could well be worth some time to check out.
     
  5. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    I came up with this. If the other solutions are better, please let me know. I'm not familiar with performance for things like this. Basically this code checks for 0-9, 11-19, 21-29 etc etc 91-99. I'm not going to have to track that many particles but so far so good. I'm a little worried about running this code a few hundred times every 0.1f seconds. Would other solutions perform better?

    Code (CSharp):
    1. float source = ((pts[i].size - (int)(pts[i].size) + 0.00005f) * 1000);
    2.             if((int)(source*10) % 10 != 0)
    3.             {
    4.                 source *= 10;
    5.             }
    6.             source = (int)source;
    Entity 1 emits particles with size 1.001f
    Entity 2 emits particles with size 1.002f
    Entity 3 emits particles with size 1.0012f

    The code above would get me 1, 2, and 12 for the outputs. And the particles can then be manipulated separately based on what entity they belong to. I thought this might save on performance or memory for not using multiple particle systems per entity. If all of the operations to achieve this will become more expensive than just having a few particle systems per entity, please let me know.

    --edit

    This solution is getting so complicated I think by the time it's done I'll be using a lot more memory and cpu than I would by just using like 20 emitters. Unless someone can tell me that particle systems give such a performance hit that any ridiculous workaround is worth it, I think I give up now lol. Thanks for the help until this point.
     
    Last edited: Sep 14, 2014
  6. cannon

    cannon

    Joined:
    Jun 5, 2009
    Posts:
    751
    Don't worry about the performance of that; if it's called just a couple of thousand times per second then that uses almost nothing in terms of CPU power, even for very old mobile devices.
     
  7. Dabeh

    Dabeh

    Joined:
    Oct 26, 2011
    Posts:
    1,614
    It's not that simple, I would suggest a double over a decimal when it comes to working with Unity for numerous reasons. It would actually be quicker and easier to use a decimal.
     
  8. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    That was just the beginning of the code to determine what group the particle belongs to. The next problem to solve would be dynamically assigning IDs to a static array to keep track of which entity is casting what particles and then I would need another system to apply that entity's behavior to those particles.

    I'm sure I would run into other problems too. Do you think all of that code controlling particles from 1-4 particle systems will be less expensive than like 20 particle systems?

    If particle systems aren't that bad it would be a lot easier to have an entity emit them and own the entire array for that system instead of multiple entities sharing a particle array. The only issue really is particles that do something other than travel with their starting velocity.

    The code was turning into something like...

    source = ... (the line you've seen already);
    Code (CSharp):
    1. for(int i = 0;i < entList.Count;i++)
    2. {
    3.     if(entList[i].id == currentParticle.size)
    4.     {
    5.         currentParticle.position = entList[i].movementTick();
    6.     }
    7. }
    So for particles that need to follow a wavy pattern or track another entity or something like that, the code would turn into something like that. Now that I've taken a break from all of this it seems I'll need to do the expensive parts of this either way to move the particles in a specific pattern or toward an entity...

    Looks like this project needs to be thought over again. Damn. Still, can someone tell me the difference between something like 1 particle system emitting and controller 5000 particles vs 5 particle systems emitting and controlling 1000 particles each?
     
  9. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    Oh it'd also be nice if I could have an entity manage an array of it's own particles and have some function join all arrays into one that I could give to a particle system with setParticles.

    Would that be inexpensive? That just may be the best solution here. I know some experienced programmer will say get the idea working first before worrying about optimization but I'm also curious about which of these 3 methods will perform the best anyway since they each have their own difficulties in even making the solution work.

    solution 1: having arrays to associate entities and their particles so 1 system can track and manipulate particles

    solution 2: having multiple particle systems so each entity can control it's own array of particles to be manipulated without doing any of the checks needed for 1 system to own them all

    solution 3: having each entity own and modify an array of particles and all particle arrays from each entity will be combined into 1 array and having a particle system use that.

    Solution 3 is feeling obvious to me right now. Still open to suggestions and would like that 1 question answered.

    --edit

    1 more small thing: why does ParticleSystem.Emit(ParticleSystem.Particle) not do anything?
     
    Last edited: Sep 15, 2014
  10. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    I "hate" floating point and often think "why is this still being used? You'd think by this point CPUs would have fixed point math support internally."

    Anyway, so I use integers to implement fixed point numbers.

    You can use either int or long depending on your needs.
    int has a range of -2,147,483,648 to 2,147,483,647
    long has a range of –9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

    Basically, you can store the values as integers and when dealing with Unity specific stuff (Vector3, etc) that requires floats you do the conversion at that time.

    If you need a precision of 2 decimal places you can go with an int and divide by 100 for conversion to a float.
    This will give you a range of -21,474,836.48 to 21,474,836.47

    If you need a precision of 4 decimal places divide by 10,000 for conversion to a float.
    With an int, this will give you a range of -214,748.3648 to 214,748.3647

    If you need to represent values less than -214,748 or greater than 214,748 you can use longs.
    The long will give you a range of –922,337,203,685,477.5808 to 922,337,203,685,477.5807

    I don't see any issues with speed because internally you just code everything using the integers and you drop to the floats only when necessary (positioning in Unity, etc).

    If you are really interested in maximizing raw speed than you can use bit shifting.
    For this, instead of dividing by 100 you divide by 128. Being a power of two a simple bit shift can be performed.
    I do not use this because I prefer to have a 1 to 1 meaning between the integer and the float.

    If your code is scripted directly to a game object and using the Unity data types for everything it may be a bit more hassle to use integer value approach.

    I always have 2 code objects for every GameObject.

    For example, the player has a PlayerGameObjectScript. This is the main script set right inside the Unity Editor. It contains ("has a") PlayerBehavior object.

    The PlayerBehavior class actually implements all of the logic. It has an Init() method and an Update() method.
    Init is called from the PlayerGameObjectScript during Start() (or sometimes Awake()) and Update is called from the PlayerGameObject's Update method. The PlayerGameObjectScript has a Vector3 Position variable which is loaded each frame with a call to a property in PlayerBehavior. The transform.Position is set to that variable.

    Doing this keeps all of the Unity specific stuff separate from the actual game logic stuff. And it makes it much simpler to do stuff like the fixed point math because you have a finite number of very few conversion points perhaps only 1.
     
  11. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    The decimal class is decimal... it represents decimals accurately while double is binary and only approximates decimal numbers. The particular error the OP is showing is likely because he's thinking in decimal but working with binary numbers.

    Not necessarily the best answer, but double is probably worse.. as in many ways is behaviour is exactly the same as float.
     
  12. Dabeh

    Dabeh

    Joined:
    Oct 26, 2011
    Posts:
    1,614
    Considering your answer was "quicker and easier", doubles are both quicker and easier because:

    A: You don't have to cast it every time you use it(quicker in both time spent programming & just raw performance).

    B: They will "just work" with Unity and not give an illusion of precision(which could lead to issues if you're using decimals since unity representation won't match your own).

    C: If you really need that much precision, you'll probably be writing your own representation of the game and using unity as a rendering engine(in which case, quicker and easier are no longer factors).

    D: Doubles are more precise than floats (if you need anything more, you're either dealing with some serious issues probably related to a networked large scale RTS in Unity or a financial application).
     
    Last edited: Sep 15, 2014
  13. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    Thanks for all of the answers everyone. I decided 'screw it' after checking out the shuriken magic demo. I ran over 100 effects at once and there was no performance hit even though the guy's assets create like 6 prefabs each with it's own ParticleSystem and several scripts with update functions running at once.

    I didn't realize how well unity / computers could handle particle systems. So I'm no longer trying to save performance by tracking particles based on them being 0.0001f different in size. By the time this is an issue I assume there will be a better solution in the future.
     
  14. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,500
    Well, what kind of computer are you running and what are the particle systems doing?

    To quote a programmer from a high-end studio working on PSP games a few years ago "Sure, you can have as many particle systems as you want... as long as they don't emit anything!"

    Having said that, the main issue new developers have with particle systems is overdraw. You want to achieve your desired effect with the fewest, smallest particles as possible, not so much to minimise CPU work in handling the particles as to reduce the amount of pixels your GPU has to touch, multiple times, to draw the effect.
     
  15. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    I ran the demo project for 'shuriken magic' and saw mass prefab instantiation with lots of particle systems haha. I'm not going to be doing anything as crazy as what I observed there. I already made a fire from an emitter that can only emit 10 particles.The particles are big, the transition from red to yellow and low alpha, they have a y velocity of -3 and that's it.

    The more I look into it, the more I see things similar to what you've just said. "The particle system overhead is negligible just make sure to use fewer, larger particles where you can."

    I'm sure at some point in the next few years I'll actually learn from what people are saying.