
Joined: Mar 2006
Posts: 13
Pikka bird

OP
Pikka bird
Joined: Mar 2006
Posts: 13 
Well, I would appreciate if anyone could tell me a way to accurately perform a large calculation, as in (for example) 437289478942343890483 / 2 without worrying about it being rounded.
I know very little about how the calculations are actually made, aside from the use of binary files (though I could be wrong about that, too) so I lack the ability to really make something that could do the job.
Thanks for any help.




Joined: Oct 2005
Posts: 1,741
Hoopy frood

Hoopy frood
Joined: Oct 2005
Posts: 1,741 
mIRC's calculation ability is limited. That cannot be changed (by you). However, you should be able to perform larger calculations by passing arguments to a dll that is written in a language that supports large calculations.
genius_ar_work




Joined: Aug 2005
Posts: 1,052
Hoopy frood

Hoopy frood
Joined: Aug 2005
Posts: 1,052 
Well, I would appreciate if anyone could tell me a way to accurately perform a large calculation, as in (for example) 437289478942343890483 / 2 without worrying about it being rounded.
I know very little about how the calculations are actually made, aside from the use of binary files (though I could be wrong about that, too) so I lack the ability to really make something that could do the job.
Thanks for any help. Im not sure what your asking for because the calc 437289478942343890483 / 2 returns the value not being rounded, and in my experience is the correct return value however if your gonna use something like 437289478942343890483 / 42442424 then it will return a value.xxx < if you want that removed at all times I suggest using something like $left($round($calc(caculations here),2),3)
if $reality > $fiction { set %sanity Sane }
Else { echo a *voices* }




Joined: Mar 2006
Posts: 13
Pikka bird

OP
Pikka bird
Joined: Mar 2006
Posts: 13 
Im not sure what your asking for because the calc 437289478942343890483 / 2 returns the value not being rounded, and in my experience is the correct return value however if your gonna use something like 437289478942343890483 / 42442424 then it will return a value.xxx < if you want that removed at all times I suggest using something like $left($round($calc(caculations here),2),3) That's strange, because for me, $calc(437289478942343890483 / 2) returns 218644739471171940000. The four zeros at the end represent the rounding present. Note I'm using the most recent version of mIRC, version 6.3. mIRC's calculation ability is limited. That cannot be changed (by you). However, you should be able to perform larger calculations by passing arguments to a dll that is written in a language that supports large calculations. I had thought of trying this, but after a quick search on Google and a few mIRC script/dll sites, I couldn't find anything of the sort. I'm afraid that I don't possess the ability to write such a thing, so that's out of the question. Thanks for your input.




Joined: Aug 2006
Posts: 183
Vogon poet

Vogon poet
Joined: Aug 2006
Posts: 183 
Actually, its fairly easy to "cheat" at doing this.
Lets take the number 42. it s a 4 and a 2. Divide 4 by 2 you get 2. Then divide 2 by 2 and you get 1. Stick them together and you get you answer: 21
Let's try 456.
4/2 = 2 5/2 = 2.5 6/2 =3
200+25+3= 228 = 456/2
See where I'm going with this?
So basically, you have to divide the fist number by 2 and store it to a variable. IF it isn't even divide by to you'll have to add 5 to the next step. Divide the next number by 2 (add 5 if the previous on3 was odd) then apply that to the end of the variable. Continue doing this until you run out of digits.
As above... It'd end up being 2 $+ 2 $+ $calc(3+5)
The same can be done for subtraction, addition and multiplication. I'd write out the code, but I'm dead tired and on my way to bed. Perhaps later on today I'll get around to it. Though, hopefully this is enough pseudocode to make something work for you. In theory, you should be able to use mirc to divide HUGE numbers by at least 8 digits worth of numbers. With more tinkering, you should be able to divide a 900 digit number by another 900 digit number and get an exact answer.
Last edited by Thrull; 07/09/07 11:53 AM.
Yar




Joined: Oct 2005
Posts: 1,741
Hoopy frood

Hoopy frood
Joined: Oct 2005
Posts: 1,741 
I think the problem still exists using the method you have shown. Sure you can take each digit and divide it by a number, but in the end you are left with a whole pile of individual place values that still need to be added up. If the numbers are large, that act of adding will likely result in the same rounding error. Ex: //echo a $calc(7700000000000000000000000 / 2) = $calc(3500000000000000000000000 + 350000000000000000000000)
The only way I can see this possibly working is to use loops to basically do true long division. Take portions of the original value, perform the division on those portions, and then gradually add the individual results together to get the final answer. genius_at_work




Joined: Aug 2005
Posts: 1,052
Hoopy frood

Hoopy frood
Joined: Aug 2005
Posts: 1,052 
Fine then... here you go, you can figure out how and where I go by this to properly calc, I can even make the script smaller but heres a way to do it.. SYNTAX: //echo a $pcalc(valuethatislarge,+/*,valuesmaller)DO NOTE: However, you see i see $1 has the large entry and $3 has the smaller and $2 has the +/* Functions. In this script you can add if/elseif/else statements to make it "better" and the script can be written a tad longer to make multi calculations in one time. Remeber though that variables have abilitys to perform calculations without the $calc command. I would also put a $matchtok sequence to verify if dividend it should match if multiplied etc... ALOT if statements lolHere you go, but first ill show you what I calculated and what my response was.. $pcalc(24984284092428940492049049,/,2) returns 12492142046214470246024524.5
while before $calc(24984284092428940492049049/2) would return 12492142046214470000000000Even if you add my first return togheter it brings you back to the original result.Small,ugly,but it works this way lol.. heres your workaround. alias Pcalc {
if ($len($1) > 17) && ($len($3) < 17) {
%pcalc.a = $left($1,+17) $2 $3  %pcalc.b = $mid($1,17) $2 $3  return $+(%pcalc.a,%pcalc.b)
}
}
if $reality > $fiction { set %sanity Sane }
Else { echo a *voices* }




Joined: Mar 2006
Posts: 13
Pikka bird

OP
Pikka bird
Joined: Mar 2006
Posts: 13 
That's a good idea, thank you. It seems to work quite nicely up to a point, as in, 34 digits. But after that, it appears to start rounding.. but it's a great proof of concept. I'll tweak it a bit and get it to do right (using a while loop, of course). Thanks for your help, it's very much appreciated. EDIT: One issue with this approach is how it handles zeros when they're at the start of a 17character "block". I'm currently making a way to work around this, though, and I'll post what I come up with in here when I think I'm done in case anyone else wants the script. EDIT AGAIN: Here's the code I came up with. It seems to perform well under my tests.. I haven't found a flaw with it. At least with division, which is all I tested it with. [EDIT: it only works with division..][Another EDIT: it has a flaw involving ones at the start of 17character blocks.] I'm also including an identifier I wrote, since it makes the script itself look much more.. clean, without having to do that in the main script. alias Lcalc {
;SYNTAX: $Lcalc(number,operator,smallernumber)
;Example, $Lcalc(64,/,2) returns 32.
if ($len($3) < 17) {
var %step = 1
while ($mid($1,$calc((%step  1) * 17)) != $null) { var %cur = $mid($1,$calc((%step  1) * 17 + 1),17)  if ((!$remove(%cur,0)) && ($len(%cur > 1))) { var %lcalc.b = %cur }  else { var %lcalc.b = %cur $2 $3  var %lcalc.b = $str(0,$countleft(%cur,0)) $+ %lcalc.b }  var %lcalc.t = %lcalc.t $+ %lcalc.b  inc %step }
return %lcalc.t
}
}
alias countleft {
;SYNTAX: $countleft(text,character)
;The number of "character" on the left side of text is counted and returned.
;Example: $countleft(hhhithere,h) would return 3.
;You can put a  next to 'character' to count from the right. Example, $countleft(hhhithere,e) would return 1.
var %step = 1 , %ident = $iif($left($2,1) == ,$iif($len($2) == 2,right),left) $+ $chr(40) $+ z $+ $chr(41) , %2 = $iif($len($2) == 2,$right($2,1),$left($2,1))
while ($ [ $+ [ $replace(%ident,z,$1 $+ $chr(44) $+ %step) ] ] == $str(%2,%step)) inc %step
return $calc(%step  1)
}
Note I changed it from Pcalc to Lcalc, to avoid confusion and because "loop" starts with "L". Since the script appears full of holes, anyone who wants to try to fix it (or provide their own script as a replacement) can feel free. :P Thank you.
Last edited by ZorgonX; 07/09/07 10:53 PM.




Joined: Aug 2005
Posts: 1,052
Hoopy frood

Hoopy frood
Joined: Aug 2005
Posts: 1,052 
That's a good idea, thank you. It seems to work quite nicely up to a point, as in, 34 digits. But after that, it appears to start rounding.. but it's a great proof of concept. I'll tweak it a bit and get it to do right (using a while loop, of course). Thanks for your help, it's very much appreciated. EDIT: One issue with this approach is how it handles zeros when they're at the start of a 17character "block". I'm currently making a way to work around this, though, and I'll post what I come up with in here when I think I'm done in case anyone else wants the script. EDIT AGAIN: Here's the code I came up with. It seems to perform well under my tests.. I haven't found a flaw with it. At least with division, which is all I tested it with. [EDIT: it only works with division..][Another EDIT: it has a flaw involving ones at the start of 17character blocks.] I'm also including an identifier I wrote, since it makes the script itself look much more.. clean, without having to do that in the main script. alias Lcalc {
;SYNTAX: $Lcalc(number,operator,smallernumber)
;Example, $Lcalc(64,/,2) returns 32.
if ($len($3) < 17) {
var %step = 1
while ($mid($1,$calc((%step  1) * 17)) != $null) { var %cur = $mid($1,$calc((%step  1) * 17 + 1),17)  if ((!$remove(%cur,0)) && ($len(%cur > 1))) { var %lcalc.b = %cur }  else { var %lcalc.b = %cur $2 $3  var %lcalc.b = $str(0,$countleft(%cur,0)) $+ %lcalc.b }  var %lcalc.t = %lcalc.t $+ %lcalc.b  inc %step }
return %lcalc.t
}
}
alias countleft {
;SYNTAX: $countleft(text,character)
;The number of "character" on the left side of text is counted and returned.
;Example: $countleft(hhhithere,h) would return 3.
;You can put a  next to 'character' to count from the right. Example, $countleft(hhhithere,e) would return 1.
var %step = 1 , %ident = $iif($left($2,1) == ,$iif($len($2) == 2,right),left) $+ $chr(40) $+ z $+ $chr(41) , %2 = $iif($len($2) == 2,$right($2,1),$left($2,1))
while ($ [ $+ [ $replace(%ident,z,$1 $+ $chr(44) $+ %step) ] ] == $str(%2,%step)) inc %step
return $calc(%step  1)
}
Note I changed it from Pcalc to Lcalc, to avoid confusion and because "loop" starts with "L". Since the script appears full of holes, anyone who wants to try to fix it (or provide their own script as a replacement) can feel free. :P Thank you. Listen to this lol <<< btw not mean way I would write the whole script which would be lenghty the reason why I say lenghty is because studying the blocks of 17 max calcs per operation would require this method a division script alone, multiplication,Substraction and addition script alone, therefore there would be 4 Operators that would need to be scripted individual why I say this.. EX:... this is a short recode i did so that the lenght of $1 works weither it be over 34 chars MAX: 52 for this script. Also it wont work if charges are less then 34 due to my IF (%lc.c) check meaning only if %lc.c is present.. ""More if statement can be added" alias newc {
if ($len($1)) { %lc.a = $left($1,+17)  %lc.b = $left($remove($1,%lc.a),+17)  %ts.a = $+(%lc.a,%lc.b)  %lc.c = $left($remove($1,%ts.a),+17) }
IF (!%lc.c) { unset %lc.c }
if (!%lc.b) { unset %lc.b }
}
alias lcalc {
newc $1
if (%lc.c) { %lc.a = %lc.a $2 $3  %lc.b = %lc.b $2 $3  %lc.c = %lc.c $2 $3  return $+(%lc.a,%lc.b,%lc.c) }
} Here we go Dividing by 2 would make the script rather easy hwoever what happens when we divide by 100? $lcalc(1396424641746417249012204916221048172117162676176,/,100) returns 139642464174641.72490122049162210.51721171626761.76 Notice all the decimal points, now my method of approach to remove the decimal points would be to remove and store them to a temp var example .72 < i would "$remove(x,.72)" and store it in var I would do the same for all decimal points. this way in the end you can calc the decimal points and readd them to the end of the valued return. if example I would put $calc(.72+.51+.76) which the result would be 1.99 so at the end of this result in question it would be 6762.99 in theory right? See my scenario if not ill try to explain it again. There's a requirement for * / +  in each of their own scenarios that cannot be made by a single written script for all four vars, I mean if ($2 == /) for example if you use that method then it will be in "one" script but I mean you need 4 seperate events. Really if you got alot of time on your hands knock yourself out. You seem to know and understand what I mean so hope this helps out for you. Ill check back later if you have a question I like math to an extent...
if $reality > $fiction { set %sanity Sane }
Else { echo a *voices* }




Joined: Mar 2006
Posts: 13
Pikka bird

OP
Pikka bird
Joined: Mar 2006
Posts: 13 
I've become convinced that I could more easily learn to write a DLL, even if I only have extremely limited experience with C++, than to write an mIRC script to do this.
Thanks for your help, and I think I have a better understanding of how this sort of thing works. If I fail at the DLL, I'll just work more on the script..
If you were wondering why I needed this, I was writing a simple encryption algorithm using mIRC scripting. When I think about it, it really isn't all that great.. so I'm not sure if it's worth the effort.




Joined: Oct 2005
Posts: 1,741
Hoopy frood

Hoopy frood
Joined: Oct 2005
Posts: 1,741 
If you can find a tutorial on how to compile a dll, the actual code for the dll would be quite simple. Pseudocode: function longdivision return $1 / $2
There are likely extension files that would need to be included in the dll to allow large math operations. genius_at_work




Joined: Aug 2005
Posts: 1,052
Hoopy frood

Hoopy frood
Joined: Aug 2005
Posts: 1,052 
In theory the dll would be the better approach but if your like me and strive on mIRC nothing could stop you
if $reality > $fiction { set %sanity Sane }
Else { echo a *voices* }




Joined: Oct 2005
Posts: 1,741
Hoopy frood

Hoopy frood
Joined: Oct 2005
Posts: 1,741 
I wonder if it would be possible to use some kind of COM object to perform the calculations..
genius_at_work




Joined: Aug 2005
Posts: 1,052
Hoopy frood

Hoopy frood
Joined: Aug 2005
Posts: 1,052 
I wonder if it would be possible to use some kind of COM object to perform the calculations..
genius_at_work Im not sure how it works, just by looking at it im thinking you could call? windows calculator but how is the result sent back.. LOL see I don't know nothing about $com
if $reality > $fiction { set %sanity Sane }
Else { echo a *voices* }




Joined: Oct 2004
Posts: 8,330
Hoopy frood

Hoopy frood
Joined: Oct 2004
Posts: 8,330 
Well, you always have the option of using the clipboard with the Windows calculator if you could put the calculations through there. Of course, if you can put calculations through there in the first place, I'm sure you can also retrieve the results without needing to use the clipboard.
Invision Support #Invision on irc.irchighway.net




Joined: Oct 2005
Posts: 1,741
Hoopy frood

Hoopy frood
Joined: Oct 2005
Posts: 1,741 
I was thinking more of calling a WSH script of some sort. Again, I don't know how com calls work, so I can't be of any help there.
genius_at_work




Joined: Apr 2004
Posts: 759
Hoopy frood

Hoopy frood
Joined: Apr 2004
Posts: 759 
Getting WSH to perform and return calculations is rather easy. Your still going to run into some problems however. To the best of my knowledge each of the possible script languages you can call with WSH wont handle 64bit signed integers (properly) let alone even higher.
Last edited by Mpdreamz; 09/09/07 09:24 PM.
$maybe




Joined: Aug 2005
Posts: 1,052
Hoopy frood

Hoopy frood
Joined: Aug 2005
Posts: 1,052 
I've become convinced that I could more easily learn to write a DLL, even if I only have extremely limited experience with C++, than to write an mIRC script to do this.
Thanks for your help, and I think I have a better understanding of how this sort of thing works. If I fail at the DLL, I'll just work more on the script..
If you were wondering why I needed this, I was writing a simple encryption algorithm using mIRC scripting. When I think about it, it really isn't all that great.. so I'm not sure if it's worth the effort. I got questions A) Why would one need an encryption algorhitm B) Why use Num over alpha/num? EX:. $base() functions.
if $reality > $fiction { set %sanity Sane }
Else { echo a *voices* }




Joined: Aug 2005
Posts: 1,052
Hoopy frood

Hoopy frood
Joined: Aug 2005
Posts: 1,052 
Well i was bored a bit wrote a bit of stuff, theres multi Lenght checks for up to 52 chrs operations. alias newc {
if ($len($1)) { %lc.a = $left($1,+17)  %lc.b = $left($remove($1,%lc.a),+17)  %ts.a = $+(%lc.a,%lc.b)  %lc.c = $left($remove($1,%ts.a),+17) }
IF (!%lc.c) { unset %lc.c }
if (!%lc.b) { unset %lc.b }
} Here's the lcalc alias that goes with the new calc lenght check. Needs work on both scripts but its an advancement if you will call it that. alias lcalc {
newc $1
if (%lc.c) {
%lc.a = %lc.a $2 $3
%lc.b = %lc.b $2 $3
%lc.c = %lc.c $2 $3
if ($chr(46) isin %lc.a)  ($chr(46) isin %lc.b)  ($chr(46) isin %lc.c) {
%lc.a = $round(%lc.a,1)  %lc.a = $left(%lc.a,$+(+,$calc($len(%lc.a)3)))
%lc.b = $round(%lc.b,1)  %lc.b = $left(%lc.b,$+(+,$calc($len(%lc.b)3)))
%lc.c = $round(%lc.c,1)  %lc.c = $left(%lc.c,$+(+,$calc($len(%lc.c)3)))
}
return $+(%lc.a,%lc.b,%lc.c)
}
elseif (%lc.b) {
%lc.a = %lc.a $2 $3
%lc.b = %lc.b $2 $3
if ($chr(46) isin %lc.a)  ($chr(46) isin %lc.b) {
%lc.a = $round(%lc.a,1)  %lc.a = $left(%lc.a,$+(+,$calc($len(%lc.a)3)))
%lc.b = $round(%lc.b,1)  %lc.b = $left(%lc.b,$+(+,$calc($len(%lc.b)3)))
}
return $+(%lc.a,%lc.b)
}
elseif (%lc.a) {
%lc.a = %lc.a $2 $3
if ($chr(46) isin %lc.a) {
%lc.a = $round(%lc.a,1)  %lc.a = $left(%lc.a,$+(+,$calc($len(%lc.a)3)))
}
return $+(%lc.a)
}
}
if $reality > $fiction { set %sanity Sane }
Else { echo a *voices* }




Joined: Oct 2005
Posts: 1,741
Hoopy frood

Hoopy frood
Joined: Oct 2005
Posts: 1,741 
Here is my first long math code. It is for addition because I figured I would start with the easiest operator first. Also, the long addition operator may be needed for the other long operations. alias math+ {
;$1=A, $2=B
; A+B=C
var %a = $gettok($1,1,46), %b = $gettok($2,1,46)
var %y = $gettok($1,2,46), %z = $gettok($2,2,46)
var %c = $null, %r = 0, %w = 0
if ($len(%a) < $len(%b)) %a = $str(0,$calc($v2  $v1)) $+ %a
elseif ($len(%b) < $len(%a)) %b = $str(0,$calc($v2  $v1)) $+ %b
if ($len(%y) < $len(%z)) %y = %y $+ $str(0,$calc($v2  $v1))
elseif ($len(%z) < $len(%y)) %z = %z $+ $str(0,$calc($v2  $v1))
var %i = $len(%y), %ii = 0
while (%i > %ii) {
%w = $calc($mid(%y,%i,1) + $mid(%z,%i,1) + %r)
%c = $+($right(%w,1),%c)
%r = $left(%w,1)
dec %i
}
if (%c > 0) %c = $+(.,%c)
var %i = $len(%a), %ii = 0
while (%i > %ii) {
%w = $calc($mid(%a,%i,1) + $mid(%b,%i,1) + %r)
%c = $+($right(%w,1),%c)
%r = $left(%w,1)
dec %i
}
if (%r > 0) %c = $+(%r,%c)
return %c
}
//echo a $math+(<long number>,<long number>) Note: Supports decimals Note: Does NOT support negative numbers (yet). genius_at_work




