| 04-25-2004, 06:46 PM | #1 |
This function requires strings. It will treat negative values ("-43") as positive. The reason it uses strings is because the game doesn't support integers or reals greater than 2^24 as far as I know (if somebody can prove me wrong, do so to my great pleasure). The reason I wrote this is because I was having a great deal of difficulty generating 32 bit integers, until I realized that in a function WC3 will not return an integer that large, to my dismay. Add32("2147483647","53") returns string "2147483700" I realize I could have used larger chunk sizes than single-digit, but I wrote this on the fly. If anybody wants to speed up the math by making it multiple-digit, be my guest. I wrote this, also, so that it could be later adapted into a multiplication, subtraction, division, and power function. All I request is that any use of this be made openly known, and any modification to it be posted in this thread. Thank you. Its name is add32 because previously I just wanted it to manipulate 32 bit integers, but some hashing programs produce 64-bit data so I left out any modular arithmatic. If you are curious how to make it n-bit, I believe the easiest way would be to convert the result to a binary string, and then use the last (right-most) n-bits. Then convert back to decimal. That's unsigned though, if you know what signed is then you probably don't need my help converting it. Code:
function add32 takes string operand1, string operand2 returns string local string array operandone local string array operandtwo local string str = "" local integer oper1 = StringLength(operand1) local integer oper2 = StringLength(operand2) local integer i = 0 local integer carry = 0 local integer val = 0 local integer j = oper1 call DisplayTextToForce( GetPlayersAll(), "j " + I2S(j)) if ( j < oper2 ) then set j = oper2 endif call DisplayTextToForce( GetPlayersAll(), "j after ifstatement " + I2S(j)) loop exitwhen i == oper1 set operandone[oper1-i] = SubString(operand1,oper1-i-1,oper1-i) call DisplayTextToForce( GetPlayersAll(), operandone[oper1-i]) set i = i + 1 endloop set i = 0 loop exitwhen i == oper2 set operandtwo[oper2-i] = SubString(operand2,oper2-i-1,oper2-i) call DisplayTextToForce( GetPlayersAll(), operandtwo[oper2-i]) set i = i + 1 endloop set i = 0 loop exitwhen i == j if ( oper1 == j) then call DisplayTextToForce( GetPlayersAll(), "oper1 is equal to j" + I2S(oper1)) if ( operandtwo[oper2-i] == "" ) then call DisplayTextToForce( GetPlayersAll(), "operand2 is equal to 0" + operandtwo[oper2-i]) set val = S2I(operandone[oper1-i]) call DisplayTextToForce( GetPlayersAll(), "val set to " + I2S(val)) else call DisplayTextToForce( GetPlayersAll(), "operand2 is not equal to 0" + operandtwo[oper2-i]) set val = S2I(operandone[oper1-i]) + S2I(operandtwo[oper2-i]) call DisplayTextToForce( GetPlayersAll(), "val set to " + I2S(val)) endif else call DisplayTextToForce( GetPlayersAll(), "oper1 is not equal to j" + I2S(oper1)) if (operandone[oper1-i] == "" ) then call DisplayTextToForce( GetPlayersAll(), "operand1 is equal to 0" + operandone[oper1-i]) set val = S2I(operandtwo[oper2-i]) call DisplayTextToForce( GetPlayersAll(), "val set to " + I2S(val)) else call DisplayTextToForce( GetPlayersAll(), "operand1 is not equal to 0" + operandone[oper1-i]) set val = S2I(operandone[oper1-i]) + S2I(operandtwo[oper2-i]) call DisplayTextToForce( GetPlayersAll(), "val set to " + I2S(val)) endif endif set val = val + carry call DisplayTextToForce( GetPlayersAll(), "val after carry " + I2S(val)) if ( StringLength(I2S(val)) > 1 ) then set carry = S2I(SubString(I2S(val),0,1)) set val = val - (carry * 10) if ( i + 1 == j ) then set j = j + 1 endif else set carry = 0 endif call DisplayTextToForce( GetPlayersAll(), "carry " + I2S(carry)) call DisplayTextToForce( GetPlayersAll(), "final val " + I2S(val)) set i = i + 1 set str = SubString(I2S(val),StringLength(I2S(val))-1,StringLength(I2S(val))) + str endloop return str endfunction Oh yeah, I left the debug text displays in, feel free to remove those without posting about it. Those are in just in case somebody wants to run it and see what happens in-game. That and I had some problems with it earlier ^^ |
| 04-25-2004, 06:53 PM | #2 |
Um what the hell does this do? wouldn't this work just as fine function add takes string x, takes string y returns string return I2S(S2I(x)+S2I(y)) endfunction The game supports 32 Bit integers and IEEE standard 32 bit floats. 0x7FFFFFFF is the highest postive value it will support, and 0x80000000 is the biggest negative value it supports. The R2S function is slightly screwy and shouldn't be used. Use the R2SW function. |
| 04-25-2004, 07:10 PM | #3 |
Weaaddar, I'm using addition in a hash in which data will be manipulated repeatedly, and then returned. When a function returns an integer, the integer is never 32 bit, AFAIK. And if you want a 64 bit integer... heh, give up now. And Weaadar, I need 32 bit unsigned, as well. Why 0x7FFFFFF to 0x8000000 just say 32 bit signed, way easier. Signed long int, or signed double word/dword. |
| 04-25-2004, 08:29 PM | #4 |
Umm... also, there is the JASS Vault made by KaTTana for this type of thing. So I would suggest you submit all of your 'free functions' there. |
| 04-25-2004, 08:36 PM | #5 |
Free as in one doesn't have to wait until my map is completed and steal my .j. All for naught I guess, I found out that the game (likely) supports reals as high as 2^128-1.. but I wasnt able to get that to work because 2^128 returns "inf" Oh well, I guess this function can disappear now. Edit: Actually, I call the bulls*** card. WC3 cannot properly display reals as strings, and thus cannot properly display positive integers over 2^31-1, which must become reals because integers in wc3 are signed double words. Thus if you want to do 32 bit integer math, you must do that in real form. But if you want to display that real you must use R2S or R2SW... which dont work right. For example, R2S(2147483647) kept returning 2147483520 or some similar oddity. Repeatedly, if I used a function which used R2S or R2SW it would fail miserably. Thusly, the only proper way to operate at a 32 or 64 bit level is through basic level arithmatic which must be conducted through large functions such as the one above. Edit 2: R2S or R2SW of 2147483647 produces string 2147483520 WHAT THE ****? thank you, g'night. My long function > blizzard natives |
| 04-25-2004, 10:18 PM | #6 |
Thats part of the goofy ness of the floating point format. Count the number of digits you have there? Its much more then your mantissa natively supports. A four bit floating point number will ussually only be accurate to 6-7 places and then start "floating" to the next place it can display. Integers are more precise but we all knew that. You want a double, which has such a high accuracy (13-14 places) that the floating isn't noticable until you reach an absurd level of accuracy (in which case you pray to god your langauge supports tripples, or quadroples). Jass types are all four bytes. So it can be expected that you have such error. Also this is true of java, and C# as well. Why don't you actually look at the Floating Point format and understand how its made it up before pointing fingers at blizzard. |
| 04-25-2004, 11:41 PM | #7 |
The problem isn't the floating point format, it's the fact that it doesnt support anything more accurate than 2^31-1 positively. I need exact 32 bit addition. Which is provided by what I did. Period. I'm not pointing fingers, I'm saying point-blank JASS doesn't provide the accuracy I want. That, and a Real 2147483648 'floats' to a negative. The hashing algorithm I'm using doesn't use signed numbers and I dont want to do extra conversion. If it means I have to manually write multiplication, power, and bitwise functions so be it. The easiest part will be the bitwise, anyways. So please, if you're going to say my function is crappy or ineffective do so right now, it'll save me the effort of trying to weed out the true point you're making. Is it that it's not blizzard's fault or is it that my function is unnecessary? For the calculations I'm doing, my function is absolutely necessary, integers in wc3 are signed. I need unsigned doubleword integers to perform my hashing calculation. |
| 04-26-2004, 03:21 AM | #8 |
Instead of typing 214748368 try adding a . after the last digit, it should fix your problem about flipping signs, ANy function that takes real will take integer as well and will try to convert it to float first (your passing something that would be a negative int value). Also again, you don't understand the floating point format if you think the accuracy is limited to 2^31-1. |
| 04-26-2004, 04:09 AM | #9 |
No, Integers are limited in the positive range to 2^31-1 and to the negative range at -2^31. It's called Signed Long Integer. Floating Point is inaccurate so I refuse to use it. Period. And it's well beyond proven the accuracy of floating point diminishes well before it reaches 2^30. The simple fact of the matter is this will add two integers to n-bit math, n being the maximum length of a string in terms of decimal point accuracy. Considering that a string can be 1048 characters, from what I heard, this can add up any two 1027 length decimal numbers. and produce a number of over 99 googles. Accuracy my friend, and the fact that the game doesn't handle unsigned long integers. Oh, and I tested the R2S 2147483648 in gui too, with a .00 or .41 or basically .anything... it still results in a negative string. So even though it should be 2^32... it results in a value closer to negative 2^32. |
| 04-26-2004, 10:02 AM | #10 |
Hmm, This is a pretty cool function, ...but just the only thing I have to wonder about is...what is it useful for? I mean...it's fine if you just want to display these values as a string somewhere....but if you indeed have to work with these big values, then you have to work with them as strings "everywhere", and...they're useless to natives that take integers too, so there you would meet up with alot of other problems. And then ofcourse there is the String Leakage.. Normally I don't ever worry about it, as i'm most of the time working with either just in-game messages that are worth being permanent, or semi temporary strings that are small and reused in all my sring-handling functions. But here, you are creating alot of unique n-size strings. And while not being really big, if you have your complete map count on them, they will continue to build up more and more unique strings that leak and in the end may start to be noticable. Anyways, this is just something you should be concerned with. If you're using this fairly little, then you don't really have to worry, but...yeah. Cubasis oh, and...I'm just interested, what do you need this big values for? cause in my long experience of WC3 map-developing, I have never ever run into the limitations of the integer type...just becouse i've never needed to work with this big values. |
| 04-26-2004, 12:25 PM | #11 |
I'm using this function at the beginning and end of my map, and only 32 bit math will be used. I'm hashing. I'm going to release an API that does to-the-letter SHA-1 if possible. SHA-1 is the most secure of the "little" digest hashes, even compared to MD4 and MD5. For the hashing operation, I'll be using way more strings than this addition. And I will also have to custom make other functions, multiplication, subtraction, powers. I don't want to get into the hairball that is division, though. I could probably approach it from the standpoint of long division, but I run the risk of running two large numbers through (2147483645 and 3489660927 for example) and then when I run an integer operation it will die and I will be very sad. *tear* |
| 04-26-2004, 11:36 PM | #12 |
Just one question and one comment: Are you sure there are no version of the SHA-1 algoritm that operates on signed numbers? Wheter it is possible or not to make this in another way, your Jass skills should have improved by implementing this 32bit unsigned algorithm. ;) |
| 04-27-2004, 12:24 AM | #13 |
When you add signed integers, part of what usually makes it possible is the fact that it wraps around so that in bit form it makes sense. Ergo: 2147483647 + 1 = -2147483648 but in hex that's 0x7FFFFFFF and 0x80000000... so as you can see it really is a +1 operation which returns a hex or binary value that is literally one unit larger. In WC3 when you add integers, instead of wrapping around at 2^31-1 and negative 2^31, it doesn't. If you set an integer to a number larger than 2^31-1, it becomes 2^31-1. If you set an integer lower than -2^31, it becomes -2^31. There is no wrapping so any integer math must be truncated to fewer bits, or bit math must be used, or in any case... it involves strings. There really is no simple way to do it, unfortunately. Edited in note: The purpose of the above was to illustrate that, once again, due to Blizzard's foresight (see: foresight, lack of) they decided to make it so that you can't force an integer negative. That would be 'helpful' because a newbie might accidentally set an integer too high, and produce a negative value which could mess up an equation. Well, that helpfulness also ends up screwing up any possibility at 32 bit math, because they erected an iron wall around 2^31-1 and -2^31. No wrapping = no 32bit math. Imagine if I tried to do SHA-384 or SHA-512 which use 64 bit math! Oh yes, writing this function helped significantly with my jass abilities, that and several other functions which I've been writing to try and get the hang of this before I tackle SHA-1 en masse. The problems I've encountered so far are that in addition to specific requirements on integer and output types, SHA-1 uses the bitwise operators: Not or Complement Xor Or And Rotate Left (Do not confuse with shift left... rotate means it goes like 1234 4123 3412 2341 and then back to 1234. Shift goes like 1234, 0123, 0012, 0001, 0000) I had to write a decimal-to-binary function, which must be rewritten due to the constraints on the integer handle, and a base 64 letter-to-binary function. I wrote a Rotate Left (usage: ROL("string",places)) which can, due to usage of strings, rotate any other text. Uhm.. That's about it right now. And this is my first map, too! I'm probably going way over my head with this SHA-1 function but since most of the core parts of my map are already layed out, I can afford to spend time on this. I just hope 1.15 doesn't undo all of this, but seeing as how simple the update is (not very many new functions, no new handles) I don't see a problem arising in the near future, particularly if I stay with JASS. I might have to update my map header though when WEU is updated. (eegad, that's a lot of text parsing) Edit: Added a bit, fixed grammatical mistake. |
| 04-27-2004, 01:31 PM | #14 |
I guess the easier way to implement 32 bit or more math would have been to use a gamecache based class that uses more than 1 integer to store the data (probably way faster due to no text parsing too). |
| 04-27-2004, 02:27 PM | #15 |
uhuh :) For a 32-bit int, you can probably use the native integer. You'd need to write functions to do the math; just remember a negative integer is actually a positive + 2^31 Something like this: Code:
function add32 takes integer a, integer b returns integer
local integer add = 0 // adds add*2^31
local result = 0
if a < 0 then
set a = -a
set add = add + 1
endif
if b < 0 then
set b = -b
set add = add + 1
endif
if 2^31 - a < b then // (a + b > 2^31)
set result = 2^31 - a - b
else
set result = a + b
endif
if add == 1 then
set result = -result
endif
return result
endfunctionNote: function doesn't handle result > 2^32 very well (result will be mod 2^32). |
