Game Development Community

A simple function to round a number

by Alex Huck · 07/03/2006 (11:22 am) · 13 comments

function Round(%num) { 
         %point = strstr(%num, ".");
         %dec = getSubStr(%num, %point+1, 1);
         %numb = getSubStr(%num, 0, %point); 
         if(%dec>=5) {
           %dec = 1; }
         else if(%dec<=4) { 
           %dec = 0; } 
return %numb+%dec;
}

#1
05/20/2006 (2:51 pm)
Right now I'm having a lot of fun messing with the String functions, I will prolly release more as ideas come to me.
#2
07/03/2006 (1:04 pm)
Not really a need to use strings when you could use some quick math.
function Round(%num){
 if(%num - mFloor(%num) < 5)
  return mFloor(%num);
 else
  return mCeil(%num);
}
Your else if can just be an else, but anyways, fun stuff.
#3
07/03/2006 (1:20 pm)
mFloor(%num + 0.5);
#4
07/03/2006 (4:00 pm)
If you've got the engine source, just implement mRound() yourself the way William demonstrates. It'll save a tiny amount of CPU time.
#5
07/03/2006 (8:46 pm)
Yeah duh... of course it can be done in one line. Damn allergy meds makkin' my head sleepy. I doubt it'd even save anytime to do that in source... an addition in script versus source probably isn't a big deal.
#6
11/15/2006 (8:55 am)
Using William's method (Many thanks, it's an ingeniously simple function) I made a simple-ish function to round to a certain decimal place:

function mRound(%num, %dec){
         %multiplyNumByDecimalCount = %num*mPow(10, %dec);
         %RoundedNum = mFloor(%divideNumByDecimalCount+0.5);
         %divideRoundedNumByDecimalCount = %RoundedNum/mPow(10, %dec);
return %divideRoundedNumByDecimalCount;
}
-edit- changed variable names
#7
11/15/2006 (9:25 am)
If you're calling this function a lot, i highly recommend implementing this in C++
and replacing mPow with a lookup table or something.
mPow is among the most expensive math functions available.
at the very least, you could get rid of your second call to it.

also i think in your first use of "%divideNumByDecimalCount", you meant to use "%multiplyNumByDecimalCount" instead ?

edit: by "a lot" i mean more than say fifty times a second, or if you're processing a list of numbers, you may experience a hiccup if the list is larger than several hundred. implementing it in C will definitely speed it up. If you're only calling it every now and then, say as a result of a user-event like pressing a button, then script is fine.
#8
11/15/2006 (1:23 pm)
Many thanks for your comments and suggestions.

Yes, I was planning at some point porting this over to the C++ Side, I tend to avoid that :P I'm quite new to C++, but have been using TorqueScript since ye olde days of Tribes 1 (And through Tribes 2 up to TGE, and now TGEA :))

Hmm, never thought much about cost of mPow, yes this function will be used a lot.

Here goes my lame attempt at rewritting it has C++:
//Decimal Reference
#define decRef[1]=10;
#define decRef[2]=100;
#define decRef[3]=1000;
#define decRef[4]=10000;
#define decRef[5]=100000;
#define decRef[6]=1000000;
#define decRef[7]=10000000;
#define decRef[8]=100000000;
#define decRef[9]=1000000000;
#define decRef[10]=10000000000;

int mRound(int num*, int dec*)
{
    int mult num*decRef[dec];
    int rnd Floor(mult+0.5);
   return rnd/decRef[dec];
}
ConsoleMethod( mRound, int*, 2, 2, "(mRound(%number, %decimal) - Returns the %number rounded to the nearest %decimal place.")
{
 return mRound;
}
I wish C++ were as simple as TorqueScript, though I know a few people who would say the opposite.. I guess it all comes down to what you started with, TorqueScript was my first introduction to programming
#9
11/15/2006 (4:26 pm)
Hi Alex -

wow! way to give it a go!

i think there are some syntactical problems with your code,
here's some code which compiles and works, altho see caveat below.
F32 mRound(F32 num, S32 dec)
{
   //Decimal Reference
   static F32 decRef[12] = {  1.0f,
                              10.0f,
                              100.0f,
                              1000.0f,
                              10000.0f,
                              100000.0f,
                              1000000.0f,
                              10000000.0f,
                              100000000.0f,
                              1000000000.0f,
                              10000000000.0f,
                              100000000000.0f
                           };

   if (dec < 0 || dec > 11)
      return num;
      
   F32 mult = num * decRef[dec];
   F32 rnd  = mFloor(mult + 0.5f);
   return rnd/decRef[dec];
}

ConsoleFunction( mRound, F32, 3, 3, "mRound(%number, %decimal) - Returns the %number rounded to the nearest %decimal place.")
{
 return mRound(dAtof(argv[1]), dAtof(argv[2]));
}

caveat for some reason, when inside the console function, argv[1] has already been truncated at three decimal places. not sure what's up with that.
for example,
in echo(mRound(100.123456, 4));, by the time we get to dAtof(argv[1])), argv[1] is "100.123".

anyone got an idear about that one ?
#10
11/15/2006 (7:13 pm)
Many thanks, though I have a few questions:

S32 means signed, meaning whether it is negative or positive is significant, and U32 is unsigned, meaning it's positive, am I correct? Probably not, but if so: What's F32?
Also is "static F32 decRef[12] {1.0f, 10.0f, etc}" a quick way of saying make an array called decRef with 12 values -edit- Or maybe, is this the only way?

Another question: Is the decimal point there necessary? Could it be 1f, 10f, 100f, etc?

And yet another question; What does the f at the end of each number mean

Sorry about all my questions, engine coding is very intimidating. :)

Oh and what does the dAtoF(); function do?
#11
11/16/2006 (8:54 am)
Hiya! good questions.

S32 and U32 are both Integers, meaning like -5, 1234, or 0. F32 is Floating Point, meaning more or less real numbers such as 1.234 or -8.5. In script there's no distinction, but in C and most compiled languages there is.

So if you're working with a number which you want to round off, you probably want to be using floats.

the static F32[12] {....} thing is doing a few things.
yes, it's a quick way of making an array called decRef with 12 values, but the "static" in front means that the array is only going to be created & given values once during the whole time the program is running.
That way we're not re-creating the array and filling it with values every time the function is called.

I'm not sure if the ".0" or even the "f" are necessary, but some compilers will whine if one or both aren't there. I prefer to always put them there just to be clear that the value is being used as floating point raher than integer. "f" stands for "float", as you probably guessed.

dAtof() stands for "ascii to float", and converts from the string "1.2345" to the actual floating-point number 1.2345. there is also dAtoi(), which converts from string to integers, and would convert "1.2345" to just the integer 1.

Quote:Sorry about all my questions, engine coding is very intimidating. :)
yes indeed and you're taking a good approach at diving in there,
but there's really no way to learn all this C++ junk without a proper book.
i can't recommend a particular book, but i think there's several reviewed in the Books resources section of the GG site.

cheers,
ooo
#12
11/16/2006 (4:32 pm)
I have a few more question :) I kinda know some stuff about C++, for example 'void' is a type of function which doesn't return a value, but is needed for an after-effect (Like changing the value of some variables)

But F32 I would think would be a (What do they call it, datatype? [Ex U32, F32, S32]) of a viariable, but up there it's used to define the function. Does that mean the function will need to return a flaoting point.

Also, in ConsoleFunction(Is it consoleMethod?) I think the arguments go like this:

ConsoleFunction(Or method) ( NameOfScriptFunction, (Again what do they call it, datatype?), minArguments, maxArguments, UsageDescriptionSeenIfYouTypeTheArgumentsWrong );

If so, I notice your minArguments and maxArguments are both 3, even though it has only 2 args.

Finally, with the static F32 decRef[12] {} does the 12 start at 0, or 1, (0-12 or 1-12)?

It's amazing how many questions you can squeeze out of about 25 lines of code :P

Many, many thanks. I really need this kind of tutoring, though don't worry, I think I'm at the last of my questions for this problem :)
#13
11/16/2006 (4:50 pm)
Hiya -

F32 is a datatype, yeah,
and you got it, the function needs to return a floating point value.

ConsoleFunction and ConsoleMethod both exist; one is a raw function, one belongs to a class. (you can ask what the distinction is, but i may not have time to answer.. ;)

For ConsoleFunction, "minArguments" and "maxArguments" should really be "minArguments + 1" and "maxArguments + 1". that is, whatever the number is, subtract one from it and that's the real minArguments.

decRef[0] is the first entry in the array, and decRef[11] is the last. so it goes from 0-11.

cheers,
ooo