Game Development Community

Display large numbers in torquescript?

by Kevin · in Torque Game Engine · 06/22/2005 (4:00 pm) · 37 replies

Hi, I am having a little problem with my game right now.

I need to display large numbers in torquescript. But the script seems to change the value to the scientific notation after about 9 digits.

is there a good way to display a large number and not the scientific notation in the torquescript?

thanks,

Kevin
Page «Previous 1 2
#1
06/22/2005 (4:37 pm)
The core of TGE uses 32-bit numbers, if the C++ script interface uses a U32 then your max number would be: 4,294,967,295 (note the 10 digits)

with a S32 you are limited to displaying: -2,147,483,647 to 2,147,483,647

To get larger number precision you would need to edit the engine to add in S64 F64 and U64
#2
06/22/2005 (5:17 pm)
Nah Harold. It gets an overflow long before 2,147,483,647. Not home at the computer right now but I can post some info later tomorrow.
#3
06/22/2005 (6:50 pm)
Yeah, if I go:
echo(999999 + 100);

then I would get:
1.0001e+006

it is just 6 digits. if it in the range of -2,147,483,647 to 2,147,483,647 then I would be really happy right now.
#4
06/22/2005 (7:58 pm)
I had a game I wrote in Blitz BASIC which needed numbers exceeding signed 32-bit numbers. I eventually did everything with string manipulation using children's grade-school logic. Here was the code if anybody is interested:

; Arbitary Length Integer Arithmetic

; Adds together two integers.
Function BI_add$( a$, b$ )
	Local maxLen% = BI_UTIL_max( Len(a), Len(b) )
	a = BI_UTIL_zeroPad( a, maxLen )
	b = BI_UTIL_zeroPad( b, maxLen )
	Local carry% = 0
	Local sum% = 0
	Local ans$ = ""
	For i = maxLen To 1 Step -1
		sum = Int(Mid( a, i, 1 ))
		sum = sum + Int(Mid( b, i, 1 ))
		sum = sum + carry
		ans = Str(sum Mod 10) + ans
		carry = sum / 10
	Next
	If carry > 0 Then
		ans = Str(carry) + ans
	EndIf
	Return BI_UTIL_zeroTrim( ans )
End Function

; Subtracts the integer 'b' from the integer 'a'.
Function BI_subtract$( a$, b$ )
	Local maxLen% = BI_UTIL_Max( Len(a), Len(b) )
	a = BI_UTIL_zeroPad( a, maxLen )
	b = BI_UTIL_zeroPad( b, maxLen )
	Local carryNeed% = 0
	Local diff% = 0
	Local ans$ = ""
	For i = maxLen To 1 Step -1
		diff = Int(Mid( a, i, 1 )) - carryNeed
		diff = diff - Int(Mid( b, i, 1 ))
		If diff >= 0 Then
			ans = Str(diff) + ans
			carryNeed = 0
		Else
			ans = Str(diff + 10) + ans
			carryNeed = 1
		EndIf
	Next
	Return BI_UTIL_zeroTrim( ans )
End Function

; Multiplies two integers.
Function BI_multiply$( a$, b$ )
	Local ans$ = "0"
	Local zeros$ = ""
	Local bottomLen% = Len(b)
	Local multiplier% = 0
	Local simpleAns$ = ""
	For i = bottomLen To 1 Step -1
		multiplier = Int(Mid( b, i, 1 ))
		If multiplier <> 0 Then
			simpleAns = BI_UTIL_simpleMultiply( a, multiplier )
			simpleAns = simpleAns + zeros
			ans = BI_add( ans, simpleAns )
		EndIf
		zeros = zeros + "0"
	Next
	Return BI_UTIL_zeroTrim( ans )
End Function

; Divides the integer 'b' into the integer 'a'.
Function BI_divide$( a$, b$ )
	Local ans$ = ""
	Local currDividend$ = ""
	Local currQuotient% = 0
 	Local maxLen = Len(a)
 	For i = 1 To maxLen
		currQuotient = 0
		currDividend = currDividend + Mid( a, i, 1 )
		While Not BI_UTIL_lessThan( currDividend, b )
			currQuotient = currQuotient + 1
			currDividend = BI_subtract( currDividend, b )
		Wend
		ans = ans + Str(currQuotient)
		currDividend = BI_UTIL_zeroTrim( currDividend )
		If currDividend = "0" Then currDividend = ""
	Next
	Return BI_UTIL_zeroTrim( ans )
End Function

; Returns the maximum of two ints.
Function BI_UTIL_max%( a%, b% )
	If a > b Then Return a
	Return b
End Function

; Trims any unnecessary leading zeros.
Function BI_UTIL_zeroTrim$( a$ )
	maxLen% = Len( a )
	While Left( a, 1 ) = "0" And Len(a) > 1
		a = Mid( a, 2, maxLen )
	Wend
	Return a
End Function

; Pads an integer with zeros so that it is of length 'l'.
Function BI_UTIL_zeroPad$( a$, l )
	a = RSet( a, l )
	a = Replace( a, " ", "0" )
	Return a
End Function

; Multiplies an arbitrary length integer by a simple number 0 through 9.
Function BI_UTIL_simpleMultiply$( a$, b% )
	Local maxLen% = Len( a )
	Local ans$ = ""
	Local product% = 0
	Local carry% = 0
	For i = maxLen To 1 Step -1
		product = Int(Mid( a, i, 1 ))
		product = product * b
		product = product + carry
		ans = Str(product Mod 10) + ans
		carry = product / 10
	Next
	If carry > 0 Then
		ans = Str(carry) + ans
	EndIf
	Return BI_UTIL_zeroTrim( ans )
End Function

; Returns true or false as to whether 'a' is less than 'b'.
; This returns the same result as a normal 'a < b' comparison.
Function BI_UTIL_lessThan%( a$, b$ )
	If Len(a) < Len(b) Then
		Return True
	Else If Len(a) > Len(b) Then
		Return False
	Else
		Local maxLen% = Len(a)
		Local aDigit% = 0
		Local bDigit% = 0
		For i = 1 To maxLen
			aDigit = Int(Mid( a, i, 1 ))
			bDigit = Int(Mid( b, i, 1 ))
			If aDigit < bDigit Then
				Return True
			Else If aDigit > bDigit Then
				Return False
			EndIf
		Next
	EndIf
	Return False
End Function
#5
06/22/2005 (9:49 pm)
I just don't want the scientific notation to kick in so early with just 6 digits.

is there anyway I could change it in the source?

thanks William for the code. I'm just not fimiliar with Dark Basic.

What is Mid() function in the line sum = Int(Mid( a, i, 1 ))?

and the line: "ans = Str(sum Mod 10) + ans". is "Mod" mean modulus in the script?

Keivn
#6
06/22/2005 (10:11 pm)
MID = substr
#7
06/23/2005 (1:29 am)
That's basic, of course, so it won't work in Torque...

There are some key print statements which are used to convert a number to a string and back again. I'll see about upping them for 1.4; TorqueScript simply rarely needs to deal with large numbers, so I don't think it was something anyone ever tested. :)

Bug #112!
#8
06/23/2005 (7:49 am)
LabRat has it right: MID is substring. MID( a$, b, c ) gets a substring from a$, starting at the b-th character, getting c characters. MOD is modulus. STR converts a number into a string (automatically done in Torque script. INT converts strings to integers (also automatically done). LEFT gets the left-most characters. If anybody does care to convert this for some reason in the future, two things to keep in mind. First, adding strings in BlitzBasic is like the '@' operator in Torque script. Also, strings start at character 1 in Blitz, not 0 as in C/C++.

Of course, once Ben puts in a fix, your problem will be solved. And really, if you had enormous numbers, you could write ConoleFunctions that took in strings, converted them to long long, did the math, and then returned a string for your GUI. Orders of magnitude easier than what I posted above.
#9
06/23/2005 (3:06 pm)
Thanks for the help guys.

I would just use the console function for now.

Thanks

Kevin
#10
08/21/2005 (11:30 am)
In the event this isn't checked into 1.4 yet (or for those looking to gain this advantage in current T2D version) I was able to increase precision by changing the following in compiledEval.cc around line 144:

void setFloatValue(F64 v)
   {
      validateBufferSize(start + 32);
      [b]dSprintf(buffer + start, 32, "%.9g", v);[/b]
      len = dStrlen(buffer + start);
   }

around line 300 in compiledEval.cc:

char *getFloatArg(F64 arg)
{
   char *ret = STR.getArgBuffer(32);
   [b]dSprintf(ret, 32, "%.9g", arg);[/b]
   return ret;
}

around line 601 in compiler.cc:

U32 CompilerStringTable::addFloatString(F64 value)
{
   [b]dSprintf(buf, sizeof(buf), "%.9g", value);[/b]
   return add(buf);   
}

and around line 143 in consoleTypes.cc
static const char *getDataTypeF32(void *dptr, EnumTable *, BitSet32)
{
   char* returnBuffer = Con::getReturnBuffer(256);
   [b]dSprintf(returnBuffer, 256, "%.9g", *((F32 *) dptr) );[/b]
   return returnBuffer;
}


By default %g uses six digits of precision. Nine was sufficient for me and doesn't seem to adversely effect anything; your mileage may vary. :) Some of the changes above may be extraneous to achieve the desired behavior and/or there may be other %g formats that need to be converted, but the above works for me in T2D for the time being, until 1.4 is rolled in.
#11
08/21/2005 (12:26 pm)
Hehe, odd.. I can still only print out 6 digits but not 7.

Edit: Bah, your post wasn't that long when I posted :) I'll try again with the new changes.

Edit: Works like a charm! Cheers Luke! :)
#12
08/21/2005 (12:31 pm)
Yeah I snuck in a few other spots to change the format once I realized that my original fix only handled immediate calculations and not ones against stored variables. :)
#13
08/21/2005 (6:19 pm)
Did a comprehensive update to 1.4; now will support full precision all the way through.

Basically, always use %g when scanning/printing strings, and you'll be good.

Can lose a little, but is VASTLY improved, and of course all internal float math is done at 64 bit precision.

#112 resolved.
#14
08/23/2005 (3:36 am)
I can tell you guys that the changes suggested above does not work perfectly. I confirmed this by multiplying a number within 9 digits.. and it was wrong by quite alot.
#15
08/23/2005 (8:49 am)
Can you give an example Stefan? I tried a few dozen calculations that resulted in nine-digit integers and they were all exactly right. Adding a decimal to the mix just rounded up to the ninth digit, the whole number was always precise (unless there were nine digits in it and then there was a potential that the least significant digit gets rounded based on the truncated decimal value).
#16
08/23/2005 (9:04 am)
I just multiplied a number of 6 digits.. and then divided by the same amount to see if I would get back the same value, but I didnt. If I reverted from your fix, it worked again.

You can't see this behaviour?
#17
08/23/2005 (11:22 am)
No, I'm not, but there are different bits of code used depending on how you're running your test. For example you could be doing:

echo(123456 * 1234);

or

$test = (123456 * 1234) / 1234; 
echo($test);

which take different paths through the source.

I've tried it a bunch of different ways but none seem to suffer from the loss you describe. What commands are you doing exactly so I can observe the results (and trace/fix the code)? I'm guessing there's a conversion somewhere in the source I missed that your test used that my tests did not.
#18
08/23/2005 (11:24 am)
What numbers did you use?
#19
08/24/2005 (9:02 am)
Quote:
31313311 * 3
gives:
93939936

Which is not correct.

The syntax I used was:

%multiply = (31313311 * 3);
#20
08/24/2005 (9:12 am)
Thanks for adding the syntax, as my first test didn't show the flaw:

==>echo(31313311 *3);
93939933

But I tried a few others and got this:

==>$testvar = 31313311;
==>$testvar2 = 3;
==>$testvar3 = $testvar * $testvar2;
==>echo($testvar3);
93939936

So it is probably another %g format someplace that needs changing (or one that needs changing back), I'll poke at it the next time I'm in the source unless someone beats me to it.
Page «Previous 1 2