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
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
#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
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.
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
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
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
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!
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
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.
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
I would just use the console function for now.
Thanks
Kevin
06/23/2005 (3:06 pm)
Thanks for the help guys.I would just use the console function for now.
Thanks
Kevin
#10
around line 300 in compiledEval.cc:
around line 601 in compiler.cc:
and around line 143 in consoleTypes.cc
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.
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
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! :)
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
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.
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
You can't see this behaviour?
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
or
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.
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
Which is not correct.
The syntax I used was:
08/24/2005 (9:02 am)
Quote:
31313311 * 3
gives:
93939936
Which is not correct.
The syntax I used was:
%multiply = (31313311 * 3);
#20
But I tried a few others and got this:
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.
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.
Torque Owner Harold "LabRat" Brown
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