Game Development Community

Calculator Bounty, Resolved, thanks everyone

by Fyodor -bank- Osokin · in Torque Game Engine · 08/23/2007 (6:51 am) · 8 replies

Hi all.

=========================
Resolved! Thanks all!
=========================

I'm ready to paypal $25 for a working solution of "Calculator" made in Torque (any version).
The problem is that TorqueScript have 6 digit precision, so you can't just write a calculator in TS (I've done it long time ago, and it's just BAD ;) ).

So, if someone develops c++ version of it, I'll pay for it and publish it as a free resource for the community.

How you do it - it's up to you. You can write custom consoleFunctions for that, or create c++-based (with gui controls), I'll accept any. The major point here - it should work! The player (in game) should be able to make any calculations and he needs to be sure, that values are correct.

Edit: is more than one solution will be presented, the creator of more powerful calculator will be paid.

#1
08/23/2007 (7:16 am)
I'll be watching this thread and see how it turns out.
#2
08/24/2007 (9:52 am)
Question: how many precision digits would be enough?
#3
08/24/2007 (9:55 am)
Use these function to manipulate large numbers in script:

ConsoleFunction( MathAdd, const char*, 3, 3, "Add 2 large numbers" )
{
   S32 v1 = dAtoi(argv[1]);
   S32 v2 = dAtoi(argv[2]);

   S32 res = v1 + v2;
   char* ret = Con::getReturnBuffer(64);
   dSprintf(ret, 64, "%i", res);

   return ret;
}

ConsoleFunction( MathSub, const char*, 3, 3, "Subtract 2 large numbers" )
{
   S32 v1 = dAtoi(argv[1]);
   S32 v2 = dAtoi(argv[2]);

   S32 res = v1 - v2;
   char* ret = Con::getReturnBuffer(64);
   dSprintf(ret, 64, "%i", res);

   return ret;
}

ConsoleFunction( MathMul, const char*, 3, 3, "Multiply 2 large numbers" )
{
   S32 v1 = dAtoi(argv[1]);
   S32 v2 = dAtoi(argv[2]);

   S32 res = v1 * v2;
   char* ret = Con::getReturnBuffer(64);
   dSprintf(ret, 64, "%i", res);

   return ret;
}

ConsoleFunction( MathDiv, const char*, 3, 3, "Divide 2 large numbers" )
{
   S32 v1 = dAtoi(argv[1]);
   S32 v2 = dAtoi(argv[2]);

   S32 res = v1 / v2;
   char* ret = Con::getReturnBuffer(64);
   dSprintf(ret, 64, "%i", res);

   return ret;
}
#4
08/24/2007 (10:58 am)
Those won't work with floating point numbers though.

I did a resource for Bank with long double precision, but that wasn't enough so I gave up. Keep that in mind if you try it.
#5
08/24/2007 (11:02 am)
Uh. So, what kind of precision is necessary? If long double isn't enough, I have to wonder what you're using this for :)

How many bits of precision are we talking here?
#6
08/24/2007 (11:29 am)
Yeah I wondered that too. I'm no expert, but long double was the biggest type I could think of.

I guess you could split the numbers up into two buffers for what, 18 digits precision? But that's more work than I can spend.
#7
08/24/2007 (11:35 am)
Here is a solution:

It allows for double floating point precision and includes the following functionality:
Arithmetic: + - * /
Trigonometry: cos() sin() tan() acos() asin() atan()
Powers: pow() log()

This does not cover the all mathematical functions but these are some of the basic ones.

Important note:
You must pass the parameters to these functions as strings not as numbers. Because if you pass them as numbers, they will be truncated to single precision in torque script (before they even reach the function).

eg:
m64Add(1, 1.123456789)
Second parameter above will be truncated to single precision, however the following will not!
m64Add("1", "1.123456789")

Issues:
Floating point operations can be slightly out by +/-0.0000000000000001. The unPad() function has been added to remove any extra trailing zeros, but doesn't work if the float point accuracy is off!

Download it here www.gabriel-notman.com/upload/m64.cc
or copy from below:
#include "console/simBase.h"
#include "platformWin32/platformWin32.h"
#include "math/mMathFn.h"

F64 dAtof64(const char *str)
{
   // Warning: metrowerks crashes when strange strings are passed in '0x [enter]' for example!
   return (F64)atof(str);
}

void unPad(char* str)
{
	S16 size=dStrlen(str);

	S16 newEnd=size;

	for (U16 i=size-1; i !=0; i--)
	{
		//if its not a zero(48) or a period(46)
		//break
		if ((str[i] != 48) && (str[i] != 46))
			break;

		newEnd=i;
	}

	str[newEnd]=0;
}

ConsoleFunctionGroupBegin(Math64, "Math functions with 64bit percission");

//Arithmetic
ConsoleFunction(m64Add, const char *, 3, 3, "(A,B)\n"
                "Returns A+B")
{
	F64 a;
	F64 b;

	a=dAtof64(argv[1]);
	b=dAtof64(argv[2]);
	
	F64 res=a+b;

	char* buff=Con::getReturnBuffer(64);

	dSprintf(buff, 256, "%.16f", res);

	unPad(buff);

	return buff;
}

ConsoleFunction(m64Sub, const char *, 3, 3, "(A,B)\n"
                "Returns A-B")
{
	F64 a;
	F64 b;

	a=dAtof64(argv[1]);
	b=dAtof64(argv[2]);
	
	F64 res=a-b;

	char* buff=Con::getReturnBuffer(64);

	dSprintf(buff, 256, "%.16f", res);

	unPad(buff);

	return buff;
}

ConsoleFunction(m64Mul, const char *, 3, 3, "(A,B)\n"
                "Returns A*B")
{
	F64 a;
	F64 b;

	a=dAtof64(argv[1]);
	b=dAtof64(argv[2]);
	
	F64 res=a*b;

	char* buff=Con::getReturnBuffer(64);

	dSprintf(buff, 256, "%.16f", res);

	unPad(buff);

	return buff;
}

ConsoleFunction(m64Div, const char *, 3, 3, "(A,B)\n"
                "Returns A/B")
{
	F64 a;
	F64 b;

	a=dAtof64(argv[1]);
	b=dAtof64(argv[2]);
	
	F64 res=a/b;

	char* buff=Con::getReturnBuffer(64);

	dSprintf(buff, 256, "%.16f", res);

	unPad(buff);

	return buff;
}
//Trigonometry 
ConsoleFunction(m64Cos, const char *, 2, 2, "(A)\n"
                "Returns the Cosine of A")
{
	F64 a;
	
	a=dAtof64(argv[1]);
	
	F64 res=mCos(a);

	char* buff=Con::getReturnBuffer(64);

	dSprintf(buff, 256, "%.16f", res);

	unPad(buff);

	return buff;
}

ConsoleFunction(m64Acos, const char *, 2, 2, "(A)\n"
                "Returns the Inverse Cosine of A")
{
	F64 a;
	
	a=dAtof64(argv[1]);
	
	F64 res=mAcos(a);

	char* buff=Con::getReturnBuffer(64);

	dSprintf(buff, 256, "%.16f", res);

	unPad(buff);

	return buff;
}


ConsoleFunction(m64Sin, const char *, 2, 2, "(A)\n"
                "Returns the Sine of A")
{
	F64 a;
	
	a=dAtof64(argv[1]);
	
	F64 res=mSin(a);

	char* buff=Con::getReturnBuffer(64);

	dSprintf(buff, 256, "%.16f", res);

	unPad(buff);

	return buff;
}


ConsoleFunction(m64Asin, const char *, 2, 2, "(A)\n"
                "Returns the Inverse Sine of A")
{
	F64 a;
	
	a=dAtof64(argv[1]);
	
	F64 res=mAsin(a);

	char* buff=Con::getReturnBuffer(64);

	dSprintf(buff, 256, "%.16f", res);

	unPad(buff);

	return buff;
}

ConsoleFunction(m64Tan, const char *, 2, 2, "(A)\n"
                "Returns the Tangent of A")
{
	F64 a;
	
	a=dAtof64(argv[1]);
	
	F64 res=mTan(a);

	char* buff=Con::getReturnBuffer(64);

	dSprintf(buff, 256, "%.16f", res);

	unPad(buff);

	return buff;
}

ConsoleFunction(m64ATan, const char *, 3, 3, "(A, B)\n"
                "Returns the Inverse Tangent of A/B (atan2(a,b))")
{
	F64 a;
	F64 b;
	
	a=dAtof64(argv[1]);
	b=dAtof64(argv[2]);
	
	F64 res=mAtan(a,b);

	char* buff=Con::getReturnBuffer(64);

	dSprintf(buff, 256, "%.16f", res);

	unPad(buff);

	return buff;
}


//Powers etc
ConsoleFunction(m64Pow, const char *, 3, 3, "(A,B)\n"
                "Returns A to the power of B")
{
	F64 a;
	F64 b;

	a=dAtof64(argv[1]);
	b=dAtof64(argv[2]);
	
	F64 res=mPow(a,b);

	char* buff=Con::getReturnBuffer(64);

	dSprintf(buff, 256, "%.16f", res);

	unPad(buff);

	return buff;
}


ConsoleFunction(m64Log, const char *, 2, 2, "(A)\n"
                "Returns the Logarithm of A")
{
	F64 a;
	
	a=dAtof64(argv[1]);
	
	F64 res=mLog(a);

	char* buff=Con::getReturnBuffer(64);

	dSprintf(buff, 256, "%.16f", res);

	unPad(buff);

	return buff;
}

ConsoleFunctionGroupEnd(Math64);

Only basic testing has been done on this, so there may still be some problems.

Gabriel
#8
08/24/2007 (4:29 pm)
Impresive work man.