Game Development Community

Adding very small or large numbers results in accuracy errors

by Ezra · in Torque Game Builder · 03/26/2006 (8:13 pm) · 3 replies

If I do this in the console: echo( 0.000001 + 1.0 ); I would expect to have it return 1.000001 but it returns 1.

How do I fix this? The same type of behavior occurs when adding large numbers also...

#1
03/26/2006 (9:25 pm)
You can't
0.000001 is below float accuracy and thus does not change the value.
When adding large numbers you will see a similar behavior as the smaller value is ruled out once again by the large (the larger the float, the larger the add part must be to change it as the gaps between floats become larger the larger the value is)
#2
03/27/2006 (12:06 pm)
Hm ok :\ Thanks for the info, I kind of thought it was related to that, when a number is below float accuracy is it classed as a double in C?

I really only need the large number accuracy, so that I can easily add to the player's score, which has a max of 999,999,999 It's a bit frustrating because my little pocket calculator can do addition no problem but Torque is limited, although I can't really think of any other reasons for someone neededing numbers with more than 6 digits unless maybe they are doing Unix time stamp format or something weird like that.

I guess I can just break the score apart into groups of 3's though, and when one rolls over 999 it adds 1 to the next group of 3.. etc. Although there may be some extra checks needed incase amounts larger than 999 are added at one time.


one thing that is confusing though, I can get numbers with more accuracy by using mFloatLength(), but I have no way of using these numbers for anything useful??
It seems that I'd want to use mFloatLength() when wanting to do math on numbers that require greater accuracy, but it doesn't work like that.
#3
03/27/2006 (10:01 pm)
I'll just post this here also, I had a related post in T2D scripting, and I ended up coming up with this solution to handling my 9-digit scores, and also handling them as a 9-character string etc..

Doesn't relate to the accuracy stuff though!

- - - -
to add to the score you just would do $playerScore1.add += amount; (or $playerScore2 for player 2..) The score doesn't change instantly, it has the effect of quickly accellerating up to the target score, also this handles keeping the score as a 9 character string for bitmap text...


function setupHud()
{
   //score!
   $highscore = new ScriptObject() {
      //scenegraph = $hud;
   };
   $playerScore1 = new ScriptObject() {
      //scenegraph = $hud;
   };
   $playerScore2 = new ScriptObject() {
      //scenegraph = $hud;
   };
   
   $highscore = "3000000";
   $highscore.million = "300";
   $highscore.thousand = "000";
   $highscore.hundred = "000";
   $playerScore1.million = "000";
   $playerScore1.thousand = "000";
   $playerScore1.hundred = "000";
   $playerScore1.queue = 0;
   $playerScore2.million = "000";
   $playerScore2.thousand = "000";
   $playerScore2.hundred = "000";
   $playerScore2.queue = 0;
}

function updateScores()
{
   for ( %i=1; %i<3; %i++)
   {
      if ( $playerScore[%i].add > 0 )
      {
         if ( $playerScore[%i].add > 10 )
         {
            %amt = mCeil($playerScore[%i].add / 10);
         } else {
            %amt = 1;
         }
         $playerScore[%i].add-=%amt;
         $playerScore[%i].queue+=%amt;
      }
      if ( $playerScore[%i].queue > 0 )
      {
         %qhundred = 0;
         %qthousand = 0;
         %qmillion = 0;
         //this is for my purposes
         if ( $playerScore[%i].queue > 999999 )
         {
            echo("-----------------------------SCORE QUEUE TOO LARGE------------");
            $playerScore[%i].queue = 999999;
         }
         
         if ( $playerScore[%i].queue > 999 )
         {
            %qlen = strlen($playerScore[%i].queue);
            %qthousand = getsubstr($playerScore[%i].queue, 0, %qlen-3);
            %qhundred = getsubstr($playerScore[%i].queue, %qlen-3, %qlen);
         } else {
            %qhundred = $playerScore[%i].queue;
         }
         //empty the queue
         $playerScore[%i].queue = 0;
         
         //checking the hundred range
         %hundred = $playerScore[%i].hundred + %qhundred;
         if ( %hundred > 999 )
         {
             %hlen = strlen(%hundred);
             %qthousand = %qthousand + getsubstr(%hundred, 0, %hlen-3);
             %hundred = getsubstr(%hundred, %hlen-3, %hlen);
         }
         
         //checking the thousand range
         %thousand = $playerScore[%i].thousand + %qthousand;
         if ( %thousand > 999 )
         {
             %tlen = strlen(%thousand);
             %qmillion = %qmillion + getsubstr(%thousand, 0, %tlen-3);
             %thousand = getsubstr(%thousand, %tlen-3, %tlen);
         }
         
         //check the million range, if it's over 999 we just do a counter stop :D 
         %million = $playerScore[%i].million + %qmillion;
         if ( %million > 999 )
         {
            %million = 999;
            %thousand = 999;
            %hundred = 999;
            echo("-----------COUNTER STOP------------");
         }
         
         //add final values
         $playerScore[%i].hundred = %hundred;
         $playerScore[%i].thousand = %thousand;
         $playerScore[%i].million = %million;
         
         %score = "";
         %mscore = "";
         %tscore = "";
         %hscore = "";
         
//millions!!!
// if the million range has numbers, add it to our score, otherwise its blank
         if ( $playerScore[%i].million > 0 )
         {
            for ( %m=0; %m<(3-strlen( $playerScore[%i].million )); %m++)
            {
               %mscore = %mscore@" ";
            }
            %score = %score@%mscore@$playerScore[%i].million;
         } else {
            %score = "   ";
         }
         
//thousands!!
//check to see if we should make 0's or spaces if the string is less than 3
         for ( %t=0; %t<(3-strlen( $playerScore[%i].thousand )); %t++)
         {
            if ( $playerScore[%i].million > 0 )
            {
               %tscore = %tscore@"0";
            } else {
               %tscore = %tscore@" ";
            }
         }
//check if we have numbers in millions / thousands
         if ( $playerScore[%i].million > 0 || $playerScore[%i].thousand > 0 )
         {
            %end = $playerScore[%i].thousand;
         } else {
            %end = " ";
         }
         //peice together the score so far
         %score = %score@%tscore@%end;
         
//hundreds!
//same checks as above, but for the hundreds range.
         for ( %h=0; %h<(3-strlen( $playerScore[%i].hundred )); %h++)
         {
            if ( $playerScore[%i].thousand > 0 )
            {
               %hscore = %hscore@"0";
            } else {
               %hscore = %hscore@" ";
            }
         }
//
         if ( $playerScore[%i].million > 0 || $playerScore[%i].thousand > 0 || $playerScore[%i].hundred > 0 )
         {
            %end = $playerScore[%i].hundred;
         } else {
            
            %end = " ";
         }
         %score = %score@%hscore@%end;
         

//our score is complete, we could add commas and stuff if we wanted.


//set the correct number images (bitmap font)
         for ( %c=0; %c<9; %c++ )
         {
            %let = $playerScoreObj[%i].letters[%c];
            %chr = getsubstr(%score, %c, 1);
            %val = strpos($testStr, %chr)+1;
            %let.setimagemap(character_set,%val);
         }
         
      //oh, is our queue less than 0? set it to 0.
      } else if ( $playerScore[%i].queue < 0 )
      {
         $playerScore[%i].queue = 0;
      }
   }
}