Cmd - Large number work around

Home built / K9a2 cf-f
January 16, 2009 at 23:26:40
Specs: XP Home - SP3, Athlon xp x2 64 5600 / 2gb
I have been working on a nt command script(though it will probably only work on 2k and later) to circumvent 32/64bit number limitations and the lack of floating point in regards to set /a. I have been writing/testing this on xp.

I am having some trouble in regards to division, the biggest problem being speed. I know if I can half split by tens, hundreds, thousands.... the division by subtraction speed will be increased except because if x <operator> x is limited as well, testing becomes difficult. At present the division is limited to numbers less than the limit (e.g. 2147483647 for 32bits) being the divisor. There is also an un-named bug in the division somewhere else, but that will be easily dealt with as this comes together.

To be honest I'm a little burnt out on this one and am after some fresh ideas and some input from other people. So if you can see a better/faster way to do things or spot any bugs please let me know.

A little background - The addition and subtraction parts are the heart, they perform their work in a similar fashion to the pen and paper method and do their job quite fast. They are both called internally for the multiplication and division.

For addition, subtraction and multiplication floating point is observed fully and division is limited to 10 places in and ten places out. This is achieved by normalising the numbers and removing the decimal place whilst a variable holds the number of decimal places. The actual work is performed on whole numbers and the decimal place is added after the operation is finished,

Please excuse the messy nature of the code,

@ECHO  Off
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO %~1|FIND "?"||IF NOT "%~2"=="" IF NOT "%~3"=="" GOTO BEGIN
:help
echo Usage:&echo.&echo %~nx0 number1 operator number2 [outputvariable]&echo.
echo Where numberx is your input numbers to be calculated and operator is a vaild operator
echo.&echo Valid operaters are:&echo.
echo - Minus.&echo + Plus.&echo * Multiply.&echo \ Divide.&echo.
echo Output variable is optional -  if present the output will be set to the variable name 
echo provided rather than be printed to screen.&echo.&echo.
pause&&endlocal&&goto :eof
:begin
set varout=%~4
set optr=%~2
if /i "%~4"=="/v" (set inpnum1=!%1!&set inputnum2=!%3!&set opvar=%~1) else set inpnum1=%1&set inpnum2=%3
set dplace=
if "%inpnum1:~0,1%"=="." set inpnum1=0%inpnum1%
if "%inpnum2:~0,1%"=="." set inpnum2=0%inpnum2%
if "%inpnum1:~-1%"=="." set inpnum1=%inpnum1%0
if "%inpnum2:~-1%"=="." set inpnum2=%inpnum2%0
if "%inpnum1%"=="%inpnum1:.=%" if "%inpnum2%"=="%inpnum2:.=%" goto wholenum
if "%inpnum1%"=="%inpnum1:.=%" set inpnum1=%inpnum1%.0
if "%inpnum2%"=="%inpnum2:.=%" set inpnum2=%inpnum2%.0
set fcnt1=0
set fcnt2=0
set float1=%inpnum1%
set float2=%inpnum2%

:f1
if not "%float1%"=="%float1:.=%" (
set /a fcnt1+=1
set float1=%float1:~0,-1%
goto f1
)
:f2
if not "%float2%"=="%float2:.=%" (
set /a fcnt2+=1
set float2=%float2:~0,-1%
goto f2
)
if defined fcnt1 (
if defined fcnt2 (
if %fcnt1% geq %fcnt2% (
set dplace=%fcnt1%
) else (
set dplace=%fcnt2%
)) else (
set dplace=%fcnt1%
)) else (
set dplace=%fcnt2%
)
:fapd1
if not "!inpnum1:~-%dplace%,1!"=="." set inpnum1=%inpnum1%0&&goto fapd1
:fapd2
if not "!inpnum2:~-%dplace%,1!"=="." set inpnum2=%inpnum2%0&&goto fapd2
set /a dplace-=1&set inpnum1=%inpnum1:.=%&set inpnum2=%inpnum2:.=%
:wholenum
:dpad1
if not defined inpnum1 set inpnum1=0&&goto zzskip
if "!inpnum1:~0,1!"=="0" set inpnum1=!inpnum1:~1!&&goto dpad1
:dpad2
if not defined inpnum2 set inpnum2=0&&goto zzskip
if "!inpnum2:~0,1!"=="0" set inpnum2=!inpnum2:~1!&&goto dpad2
:zzskip
if "!optr!"=="-" goto subtract
if "!optr!"=="+" goto add
if "!optr!"=="/" goto divide
if "!optr!"=="*" goto multiply
goto help


:subtract
SET SUB1=
SET SUB2=
set neg=
if "%~1%~2"=="internal" (
if defined %3 (set sub1=!%3!) else set sub1=%3
if defined %4 (set sub2=!%4!) else set sub2=%4
) else (
set sub1=!inpNUM1!
set sub2=!inpNUM2!
)
set stotal=
set stten=
set subsub1=!sub2!
set subsub2=!sub1!
:sloop
set sc1=
set sc2=
set sstrore=
if defined sub1 (
if defined sub2 (
set sc1=%sub1:~-1%
set sc2=%sub2:~-1%
set sub1=%sub1:~0,-1%
set sub2=%sub2:~0,-1%
) else (
if defined stten (
set sub2=!stten!
set stten=
set sc1=!sub1:~-1!
set sc2=!sub2:~-1!
set sub1=!sub1:~0,-1!
set sub2=!sub2:~0,-1!
) else (
set stotal=%sub1%%stotal%
call :finish stotal
goto soutput
)
)
) else (
if defined sub2 (
set sub1=%subsub1%
set sub2=%subsub2%
set neg=-
set stotal=
set stten=
goto sloop
) else (
if defined stten (
set sub1=%subsub1%
set sub2=%subsub2%
set neg=-
set stotal=
set stten=
goto sloop
) else (
call :finish stotal
goto soutput
)
)
)
set sazc=
set sazcnt=
:asttend
if !sc1!==0 if !sc2! gtr 0 if defined sub1 (
set sazc=!sub1:~-1!
set /a sazcnt+=1
set sub1=!sub1:~0,-1!
if !sazc!==0 goto asttend
set /a sazc-=1
set sc1=10
set sub1=!sub1!!sazc!
for /l %%a in (2,1,!sazcnt!) do set sub1=!sub1!9
)
if defined stten (
set /a sc1-=1
if !sc1! leq 0 (
set stten=+!sc1!
set /a sc1+=10
) else (
set stten=
)
)
set /a sstrore=%sc1%-%sc2%
if !sstrore! lss 0 (
set stten=1
set /a sstrore+=10
set stten=!stten:-=!
)
set stotal=%sstrore%%stotal%
goto sloop
:soutput
if "%~1%~2"=="internal" (
set %3=%stotal%
) else (
if not defined varout (
echo %stotal%
) else (
endlocal&set %varout%=%stotal%
))
goto :eof


:add
if "%~1%~2"=="internal" (
if defined %3 (set add1=!%3!) else set add1=%3
if defined %4 (set add2=!%4!) else set add2=%4
) else (
set add1=!inpNUM1!
set add2=!inpNUM2!
)
set atotal=
set astore=
set a carry=
:aloop
if not defined add1 (
if defined acarry (
set add1=%acarry:~1%
set acarry=
) else (
set atotal=%add2%%atotal%
call :finish atotal
goto aoutput
))
if not defined add2 (
if defined acarry (
set add2=%acarry:~1%
set acarry=
) else (
set atotal=%add1%%atotal%
call :finish atotal&&goto aoutput
))
set /a astore=%add1:~-1%+%add2:~-1%%acarry%
if %astore% lss 10 (
set acarry=
set atotal=%astore%%atotal%
) else (
set atotal=%astore:~-1%%atotal%
set acarry=+%astore:~0,-1%
)
set astore=
set add1=%add1:~0,-1%
set add2=%add2:~0,-1%
goto aloop
:aoutput
if "%~1%~2"=="internal" (
set %3=%atotal%
) else (
if not defined varout (
echo %atotal%
) else (
endlocal&set %varout%=%atotal%
))
goto :eof


:MULTIPLY
SET MTOTAL=0
set /a ph=dplace*2
set dplace=
set mult1=!inpnum1!
set mult2=!inpnum2!
set madup=!mult1!
IF %mult1% equ 0 set mtotal=0&&goto moutput
IF %mult2% equ 0 set mtotal=0&&goto moutput
IF %mult2% equ 1 (
set mtotal=%mult1%
set dplace=!ph!
call :finish mtotal
goto moutput
)
IF %mult1% equ 1 (
set mtotal=%mult2%
set dplace=!ph!
call :finish mtotal
goto moutput
)

call :add inte rnal mult2 1
:MPLY
if !mult2! equ 1 (
set dplace=!ph!
CALL :FINISH MTOTAL
goto moutput
)
if NOT "!mult2:~15,1!"=="" (
call :subtract inte rnal mult2 1000000000000000
SET mreduce2=%madup%000000000000000
) Else (
if NOT "!mult2:~14,1!"=="" (
call :subtract inte rnal mult2 100000000000000
SET mreduce2=%madup%00000000000000
) Else (
if NOT "!mult2:~13,1!"=="" (
call :subtract inte rnal mult2 10000000000000
SET mreduce2=%madup%0000000000000
) Else (
if NOT "!mult2:~12,1!"=="" (
call :subtract inte rnal mult2 1000000000000
SET mreduce2=%madup%000000000000
) Else (
if NOT "!mult2:~11,1!"=="" (
call :subtract inte rnal mult2 100000000000
SET mreduce2=%madup%00000000000
) Else (
if NOT "!mult2:~10,1!"=="" (
call :subtract inte rnal mult2 10000000000
SET mreduce2=%madup%0000000000
) Else (
if !mult2! gtr 1000000000 (
call :subtract inte rnal mult2 1000000000
SET mreduce2=%madup%000000000
) else (
if !mult2! gtr 100000000 (
call :subtract inte rnal mult2 100000000
SET mreduce2=%madup%00000000
) else (
if !mult2! gtr 10000000 (
call :subtract inte rnal mult2 10000000
SET mreduce2=%madup%0000000
) else (
if !mult2! gtr 1000000 (
call :subtract inte rnal mult2 1000000
SET mreduce2=%madup%000000
) else (
if !mult2! gtr 100000 (
call :subtract inte rnal mult2 100000
SET mreduce2=%madup%00000
) else (
if !mult2! gtr 10000 (
call :subtract inte rnal mult2 10000
SET mreduce2=%madup%0000
) else (
if !mult2! gtr 1000 (
call :subtract inte rnal mult2 1000
SET mreduce2=%madup%000
) else (
if !mult2! gtr 100 (
call :subtract inte rnal mult2 100
SET mreduce2=%madup%00
) else (
if !mult2! gtr 10 (
call :subtract inte rnal mult2 10
SET mreduce2=%madup%0
) else (
call :subtract inte rnal mult2 1
SET mreduce2=%madup%
)))))))))))))))
call :add inte rnal mtotal mreduce2
goto mply
:moutput
if not defined varout (echo %mtotal%) else endlocal&set %varout%=%mtotal%
goto :eof

:divide
SET DCNT=
set dtotal=0
if defined dplace if !dplace! gtr 11 (
set inpnum1=!inpnum1:~0,-1!
set inpnum2=!inpnum2:~0,-1!
set /a dplace-=1
goto divide
)
if defined dplace (set /a dplace-=1) else set dplace=0
set /a dnpl=10 - dplace
for /l %%a in (1,1,%dnpl%) do (
set inpnum1=!inpnum1!0
set /a dplace+=1
)
set div1=!inpnum1!
set div2=!inpnum2!
set ph=!dplace!
set dplace=
if !div2!==0 echo Divide by 0^^! >&2&&exit /b 2
:dsplit
if not defined div1 goto dloop
if %div1% gtr 99 (
set /a dcnt+=1
set dcnk!dcnt!=%div1:~-2%
set div1=%div1:~0,-2%
goto dsplit
) else (
set /a dcnt+=1
set dcnk!dcnt!=%div1%
)
:dloop
if defined dcnk%dcnt% (
if "!dcnk%dcnt%:~0,1!"=="0" (
set dcnk%dcnt%=!dcnk%dcnt%:~1!
goto dloop
)
) else (
set dcnk%dcnt%=0
goto dpad
)
set dvcnt=0
:dred

If !dcnk%dcnt%! geq !div2! (
If !dcnk%dcnt%! geq !div2!000 (
call :subtract inte rnal dcnk%dcnt% !div2!000
call :add inte rnal dvcnt 1000
goto dred
) else (
If !dcnk%dcnt%! geq !div2!00 (
call :subtract inte rnal dcnk%dcnt% !div2!00
call :add inte rnal dvcnt 100
goto dred
) else (
If !dcnk%dcnt%! geq !div2!0 (
call :subtract inte rnal dcnk%dcnt% !div2!0
call :add inte rnal dvcnt 10
goto dred
) else (
call :subtract inte rnal dcnk%dcnt% !div2!
call :add inte rnal dvcnt 1
goto dred
)
)
)
)
:dpad
if "!dvcnt:~1,1!"=="" set dvcnt=0!dvcnt!
set dtotal=%dtotal%%dvcnt%
set dvcnt=0
set dtmpcnt=%dcnt%
set /a dcnt-=1
if !dcnk%dtmpcnt%! gtr 0 (
set carry=!dcnk%dtmpcnt%!
set dcnk!dcnt!=!carry!!dcnk%dcnt%!
)
if %dcnt% neq 0 goto dloop
set dplace=!ph!
call :finish dtotal
:doutput
if not defined varout (echo %dtotal%) else endlocal&set %varout%=%dtotal%
goto :eof

:finish
if !dplace! equ 0 set dplace=
if defined dplace if "!%1:~%dplace%,1!"=="" set %1=0!%1!&&goto finish
if defined dplace set %1=!%1:~0,-%dplace%!.!%1:~-%dplace%!
:killzerodec
if defined dplace (
if "!%1:~-1!"=="0" (
set %1=!%1:~0,-1!
goto killzerodec
) else (
if "!%1:~-1!"=="." (
set %1=!%1:~0,-1!
)))
:killzerowhle
if "!%1:~0,1!"=="0" (
set %1=!%1:~1!
goto killzerowhle
) else (
if "!%1:~0,1!"=="." set %1=0!%1!
)
IF NOT DEFINED %1 SET %1=0
set %1=%neg%!%1!
goto :eof


See More: Cmd - Large number work around

Report •


#1
January 17, 2009 at 07:13:16
Other than the academic exercise of writing a batch script, what is the purpose of this script?

Your batch script is over 400 lines to do what could be done in a few lines with a more appropriate language. We (or I) could even write that as a GUI app in roughly 100 lines or less.


Report •

#2
January 17, 2009 at 09:03:50
the following site has a different approach of math in batch. it convert decimal to binary string.

http://student.vub.ac.be/~dvandeun/batcoll.all


Report •

#3
January 17, 2009 at 11:25:44
You're probably not interested in this but, for a taste of reality, here's a perl version.

It really only needs 3 lines but I added a little vertical whitespace for readability.
======================================

#!perl

use strict;
use warnings;

my $usage = "USAGE: $0 <number> [-+/*] <number>\n";

die $usage if ( @ARGV    != 3
             or $ARGV[0] !~ m!^\d+(\.\d?)?$!
             or $ARGV[1] !~ m!^[-+/*]$!
             or $ARGV[2] !~ m!^\d+(\.\d?)?$!
);
print eval "$ARGV[0] $ARGV[1] $ARGV[2]";

======================================

Caveat:
The regex that verifies that the input number is valid could be improved. As is it accepts an integer or a floating point number with 1 decimal.


Report •

Related Solutions

#4
January 17, 2009 at 14:17:50
Fishmonger,

"Other than the academic exercise of writing a batch script, what is the purpose of this script?"

That's pretty much it; I was just trying to see what I could get it to do. I do have other languages available to me and know it is a lot simpler in python, perl ect. Of course none of these languages have such inadequate arithmetic operations as that of set /a.

The original the idea came about to convert drive/file sizes in bytes to kilobytes, megabytes ect. I had a working version for this but ironically division is the one that gave me the most trouble in regards to large divisors. Another idea was to just paste it in to other peoples help requests where necessary, but as you point out at 400+ lines that won't be happening.

Reno,

Thanks for the link, I will definitely have a look at converting to binary and doing math on that.

To be honest it's been getting to the point where I get a headache every time I look at it and was afraid it would become another unfinished project and getting a fresh idea or two may help.....


Report •

#5
January 17, 2009 at 17:28:40
[edit fixes to the script]

Fishmonger,

I downloaded and install perl(first time I have used it) and ran your script. It seems to be limiting the output with notation, is there any larger data types that could be used to avoid this? How difficult do you think it may be to implement floating point, I doubt it would be as hard as the batch below but will it also be notated?

Obviously you script was just a quick example and probably more advice than anything else. I might trawl through the docs and try to write it in perl if I come into some spare time.....

For anyone who's interested I chased a couple of bugs out of the script, I'm forced to post the 459 lines again because I can't edit my post. I have given a limitation of 2147483646 for the divisor, the dividend can be much larger.

@ECHO Off
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO %~1|FIND "?"||IF NOT "%~2"=="" IF NOT "%~3"=="" GOTO BEGIN
:help
echo Usage:&echo.&echo %~nx0 number1 operator number2 [outputvariable]&echo.
echo Where numberx is your input numbers to be calculated and operator is a valid operator
echo.&echo Valid operators are:&echo.
echo - Minus.&echo + Plus.&echo * Multiply.&echo \ Divide.&echo.
echo Output variable is optional -  if present the output will be set to the variable name 
echo provided rather than be printed to screen.&echo.&echo.
echo.&echo Division has a limitation in regards to the divisor, the maximum divisor for whole numbers
echo is 2147483646 and numbers this large will be slow. If decimal places are present then the maximum 
echo size for the divisor will be considerably less. The dividend can be a very large number if needs be.
echo.&echo For best performance with multiplacation place the larger number to the left of the operator *.
pause&&endlocal&&goto :eof
:begin
set varout=%~4
set optr=%~2
set inpnum1=%1
set inpnum2=%3
set dplace=
if "%inpnum1:~0,1%"=="." set inpnum1=0%inpnum1%
if "%inpnum2:~0,1%"=="." set inpnum2=0%inpnum2%
if "%inpnum1:~-1%"=="." set inpnum1=%inpnum1%0
if "%inpnum2:~-1%"=="." set inpnum2=%inpnum2%0
if "%inpnum1%"=="%inpnum1:.=%" if "%inpnum2%"=="%inpnum2:.=%" goto dpad1
if "%inpnum1%"=="%inpnum1:.=%" set inpnum1=%inpnum1%.0
if "%inpnum2%"=="%inpnum2:.=%" set inpnum2=%inpnum2%.0
set fcnt1=0
set fcnt2=0
set float1=%inpnum1%
set float2=%inpnum2%

:f1
if not "%float1%"=="%float1:.=%" (
set /a fcnt1+=1
set float1=%float1:~0,-1%
goto f1
)
:f2
if not "%float2%"=="%float2:.=%" (
set /a fcnt2+=1
set float2=%float2:~0,-1%
goto f2
)
if defined fcnt1 (
if defined fcnt2 (
if %fcnt1% geq %fcnt2% (
set dplace=%fcnt1%
) else (
set dplace=%fcnt2%
)) else (
set dplace=%fcnt1%
)) else (
set dplace=%fcnt2%
)
:fapd1
if not "!inpnum1:~-%dplace%,1!"=="." set inpnum1=%inpnum1%0&&goto fapd1
:fapd2
if not "!inpnum2:~-%dplace%,1!"=="." set inpnum2=%inpnum2%0&&goto fapd2
set /a dplace-=1&set inpnum1=%inpnum1:.=%&set inpnum2=%inpnum2:.=%
:dpad1
if not defined inpnum1 set inpnum1=0&&goto zzskip
if "!inpnum1:~0,1!"=="0" set inpnum1=!inpnum1:~1!&&goto dpad1
:dpad2
if not defined inpnum2 set inpnum2=0&&goto zzskip
if "!inpnum2:~0,1!"=="0" set inpnum2=!inpnum2:~1!&&goto dpad2
:zzskip
if "!optr!"=="-" goto subtract
if "!optr!"=="+" goto add
if "!optr!"=="/" goto divide
if "!optr!"=="*" goto multiply
goto help

:subtract
SET SUB1=
SET SUB2=
set neg=
if "%~1%~2"=="internal" (
if defined %3 (set sub1=!%3!) else set sub1=%3
if defined %4 (set sub2=!%4!) else set sub2=%4
) else (
set sub1=!inpNUM1!
set sub2=!inpNUM2!
)
set stotal=
set stten=
set subsub1=!sub2!
set subsub2=!sub1!
:sloop
set sc1=
set sc2=
set sstrore=
if defined sub1 (
if defined sub2 (
set sc1=%sub1:~-1%
set sc2=%sub2:~-1%
set sub1=%sub1:~0,-1%
set sub2=%sub2:~0,-1%
) else (
if defined stten (
set sub2=!stten!
set stten=
set sc1=!sub1:~-1!
set sc2=!sub2:~-1!
set sub1=!sub1:~0,-1!
set sub2=!sub2:~0,-1!
) else (
set stotal=%sub1%%stotal%
call :finish stotal
goto soutput
)
)
) else (
if defined sub2 (
set sub1=%subsub1%
set sub2=%subsub2%
set neg=-
set stotal=
set stten=
goto sloop
) else (
if defined stten (
set sub1=%subsub1%
set sub2=%subsub2%
set neg=-
set stotal=
set stten=
goto sloop
) else (
call :finish stotal
goto soutput
)
)
)
set sazc=
set sazcnt=
:asttend
if !sc1!==0 if !sc2! gtr 0 if defined sub1 (
set sazc=!sub1:~-1!
set /a sazcnt+=1
set sub1=!sub1:~0,-1!
if !sazc!==0 goto asttend
set /a sazc-=1
set sc1=10
set sub1=!sub1!!sazc!
for /l %%a in (2,1,!sazcnt!) do set sub1=!sub1!9
)
if defined stten (
set /a sc1-=1
if !sc1! lss 0 (
set stten+=1
set /a sc1+=10
) else (
set stten=
)
)
set /a sstrore=%sc1%-%sc2%
if !sstrore! lss 0 (
set stten=1
set /a sstrore+=10
set stten=!stten:-=!
)
set stotal=%sstrore%%stotal%
goto sloop
:soutput
if "%~1%~2"=="internal" (
set %3=%stotal%
) else (
if not defined varout (
echo %stotal%
) else (
endlocal&set %varout%=%stotal%
))
goto :eof

:add
if "%~1%~2"=="internal" (
if defined %3 (set add1=!%3!) else set add1=%3
if defined %4 (set add2=!%4!) else set add2=%4
) else (
set add1=!inpNUM1!
set add2=!inpNUM2!
)
set atotal=
set astore=
set a carry=
:aloop
if not defined add1 (
if defined acarry (
set add1=%acarry%
set acarry=
) else (
set atotal=%add2%%atotal%
call :finish atotal
goto aoutput
))
if not defined add2 (
if defined acarry (
set add2=%acarry%
set acarry=
) else (
set atotal=%add1%%atotal%
call :finish atotal
goto aoutput
))
if not defined acarry (
set /a astore=%add1:~-1%+%add2:~-1%
) else (
set /a astore=%add1:~-1%+%add2:~-1%+%acarry%
set acarry=
)
if %astore% lss 10 (
set atotal=%astore%%atotal%
) else (
set atotal=%astore:~-1%%atotal%
set acarry=%astore:~0,-1%
)
set astore=
set add1=%add1:~0,-1%
set add2=%add2:~0,-1%
goto aloop
:aoutput
if "%~1%~2"=="internal" (
set %3=%atotal%
) else (
if not defined varout (
echo %atotal%
) else (
endlocal&set %varout%=%atotal%
))
goto :eof


:MULTIPLY
SET MTOTAL=0
set /a ph=dplace*2
set dplace=
set strore=
set mult1=!inpnum1!
set mult2=!inpnum2!
set madup=!mult1!
IF %mult1% equ 0 set mtotal=0&&goto moutput
IF %mult2% equ 0 set mtotal=0&&goto moutput
IF %mult2% equ 1 (
set mtotal=%mult1%
set dplace=!ph!
call :finish mtotal
goto moutput
)
IF %mult1% equ 1 (
set mtotal=%mult2%
set dplace=!ph!
call :finish mtotal
goto moutput
)

call :add inte rnal mult2 1
:MPLY
if !mult2! equ 1 (
set dplace=!ph!
CALL :FINISH MTOTAL
goto moutput
)
if NOT "!mult2:~15,1!"=="" (
call :subtract inte rnal mult2 1000000000000000
SET mreduce2=%madup%000000000000000
) Else (
if NOT "!mult2:~14,1!"=="" (
call :subtract inte rnal mult2 100000000000000
SET mreduce2=%madup%00000000000000
) Else (
if NOT "!mult2:~13,1!"=="" (
call :subtract inte rnal mult2 10000000000000
SET mreduce2=%madup%0000000000000
) Else (
if NOT "!mult2:~12,1!"=="" (
call :subtract inte rnal mult2 1000000000000
SET mreduce2=%madup%000000000000
) Else (
if NOT "!mult2:~11,1!"=="" (
call :subtract inte rnal mult2 100000000000
SET mreduce2=%madup%00000000000
) Else (
if NOT "!mult2:~10,1!"=="" (
call :subtract inte rnal mult2 10000000000
SET mreduce2=%madup%0000000000
) Else (
if !mult2! gtr 1000000000 (
call :subtract inte rnal mult2 1000000000
SET mreduce2=%madup%000000000
) else (
if !mult2! gtr 100000000 (
call :subtract inte rnal mult2 100000000
SET mreduce2=%madup%00000000
) else (
if !mult2! gtr 10000000 (
call :subtract inte rnal mult2 10000000
SET mreduce2=%madup%0000000
) else (
if !mult2! gtr 1000000 (
call :subtract inte rnal mult2 1000000
SET mreduce2=%madup%000000
) else (
if !mult2! gtr 100000 (
call :subtract inte rnal mult2 100000
SET mreduce2=%madup%00000
) else (
if !mult2! gtr 10000 (
call :subtract inte rnal mult2 10000
SET mreduce2=%madup%0000
) else (
if !mult2! gtr 1000 (
call :subtract inte rnal mult2 1000
SET mreduce2=%madup%000
) else (
if !mult2! gtr 100 (
call :subtract inte rnal mult2 100
SET mreduce2=%madup%00
) else (
if !mult2! gtr 10 (
call :subtract inte rnal mult2 10
SET mreduce2=%madup%0
) else (
call :subtract inte rnal mult2 1
SET mreduce2=%madup%
)))))))))))))))
call :add inte rnal mtotal mreduce2
goto mply
:moutput
if not defined varout (echo %mtotal%) else endlocal&set %varout%=%mtotal%
goto :eof

:divide
SET DCNT=
set dtotal=0
if defined dplace if !dplace! gtr 11 (
set inpnum1=!inpnum1:~0,-1!
set inpnum2=!inpnum2:~0,-1!
set /a dplace-=1
goto divide
)
if defined dplace (set /a dplace-=1) else set dplace=0
set /a dnpl=10 - dplace
for /l %%a in (1,1,%dnpl%) do (
set inpnum1=!inpnum1!0
set /a dplace+=1
)
set div1=!inpnum1!
set div2=!inpnum2!
set ph=!dplace!
set dplace=
if !div2!==0 echo Divide by 0^^!>&2&&exit /b 2
:dsplit
if not defined div1 goto dloop
if %div1% gtr 99 (
set /a dcnt+=1
set dcnk!dcnt!=%div1:~-2%
set div1=%div1:~0,-2%
goto dsplit
) else (
set /a dcnt+=1
set dcnk!dcnt!=%div1%
)
:dloop
if defined dcnk%dcnt% (
if "!dcnk%dcnt%:~0,1!"=="0" (
set dcnk%dcnt%=!dcnk%dcnt%:~1!
goto dloop
)
) else (
set dcnk%dcnt%=0
goto dpad
)
set dvcnt=0
:dred
If !dcnk%dcnt%! geq !div2! (
If !dcnk%dcnt%! gtr !div2!000000000 (
call :subtract inte rnal dcnk%dcnt% !div2!000000000
call :add inte rnal dvcnt 1000000000
goto dred
) else (
If !dcnk%dcnt%! gtr !div2!00000000 (
call :subtract inte rnal dcnk%dcnt% !div2!00000000
call :add inte rnal dvcnt 100000000
goto dred
) else (
If !dcnk%dcnt%! gtr !div2!0000000 (
call :subtract inte rnal dcnk%dcnt% !div2!0000000
call :add inte rnal dvcnt 10000000
goto dred
) else (
If !dcnk%dcnt%! gtr !div2!000000 (
call :subtract inte rnal dcnk%dcnt% !div2!000000
call :add inte rnal dvcnt 1000000
goto dred
) else (
If !dcnk%dcnt%! gtr !div2!00000 (
call :subtract inte rnal dcnk%dcnt% !div2!00000
call :add inte rnal dvcnt 100000
goto dred
) else (
If !dcnk%dcnt%! gtr !div2!0000 (
call :subtract inte rnal dcnk%dcnt% !div2!0000
call :add inte rnal dvcnt 10000
goto dred
) else (
If !dcnk%dcnt%! gtr !div2!000 (
call :subtract inte rnal dcnk%dcnt% !div2!000
call :add inte rnal dvcnt 1000
goto dred
) else (
If !dcnk%dcnt%! gtr !div2!00 (
call :subtract inte rnal dcnk%dcnt% !div2!00
call :add inte rnal dvcnt 100
goto dred
) else (
If !dcnk%dcnt%! gtr !div2!0 (
call :subtract inte rnal dcnk%dcnt% !div2!0
call :add inte rnal dvcnt 10
goto dred
) else (
call :subtract inte rnal dcnk%dcnt% !div2!
call :add inte rnal dvcnt 1
goto dred
))))))))))
:dpad
if "!dvcnt:~1,1!"=="" set dvcnt=0!dvcnt!
set dtotal=%dtotal%%dvcnt%
set dvcnt=0
set dtmpcnt=%dcnt%
set /a dcnt-=1
if !dcnk%dtmpcnt%! gtr 0 (
set carry=!dcnk%dtmpcnt%!
set dcnk!dcnt!=!carry!!dcnk%dcnt%!
)
if %dcnt% neq 0 goto dloop
set dplace=!ph!
call :finish dtotal
:doutput
if not defined varout (echo %dtotal%) else endlocal&set %varout%=%dtotal%
goto :eof

:finish
if !dplace! equ 0 set dplace=
if defined dplace if "!%1:~%dplace%,1!"=="" set %1=0!%1!&&goto finish
if defined dplace set %1=!%1:~0,-%dplace%!.!%1:~-%dplace%!
:killzerodec
if defined dplace (
if "!%1:~-1!"=="0" (
set %1=!%1:~0,-1!
goto killzerodec
) else (
if "!%1:~-1!"=="." (
set %1=!%1:~0,-1!
)))
:killzerowhle
if "!%1:~0,1!"=="0" (
set %1=!%1:~1!
goto killzerowhle
) else (
if "!%1:~0,1!"=="." set %1=0!%1!
)
IF NOT DEFINED %1 SET %1=0
set %1=%neg%!%1!
goto :eof


Report •

#6
January 17, 2009 at 18:37:40
Your script is giving me the following error for most numbers I used.

Divide by zero error.
10 was unexpected at this time.

I adjusted the regex in my script and reversed the logic on the if block which might make it a little easier to understand.

#!perl

use strict;
use warnings;

my $usage = "USAGE: $0 <number> [-+/*] <number>\n";

die $usage unless ( 
                    @ARGV == 3
                and $ARGV[0] =~ /^\d+\.?(\d+?)?$/
                and $ARGV[1] =~ /^[-+\/*]$/
                and $ARGV[2] =~ /^\d+\.?(\d+?)?$/
);

print eval "$ARGV[0] $ARGV[1] $ARGV[2]", "\n";

================================

Here's the output from a few test runs.

C:\test>fishmonger.pl
USAGE: C:\test\fishmonger.pl <number> [-+/*] <number>

C:\test>fishmonger.pl 21474836465455.16561 * 2147483646544541.165651516
4.61168601217833e+028

C:\test>fishmonger.pl 21474836465455.16561 / 2147483646544541.165651516
0.0100000000000045

C:\test>fishmonger.pl 21474836465455.16561 + 2147483646544541.165651516
2.16895848301e+015

C:\test>fishmonger.pl 21474836465455.16561 - 2147483646544541.165651516
-2.12600881007909e+015

================================

If need be, we can easily format the number in a variety of ways.


Report •

#7
January 17, 2009 at 19:00:00
You can read about the different formats you can use by running this command.

C:\>perldoc -f sprintf

or on the web
http://perldoc.perl.org/functions/s...


Report •

#8
January 17, 2009 at 19:29:33
Thanks for your help, could you by any chance post the numbers that were giving you errors and your os?

I will give the number formatting a look into..

[edit]
My powers of deduction tell me that you were either doing addition or multiplication to get divide but zero.


Report •

#9
January 17, 2009 at 19:39:28
C:\test>ver

Microsoft Windows 2000 [Version 5.00.2195]

C:\test>judago.bat 564156.166 * 6516
Divide by zero error.
10 was unexpected at this time.

C:\test>judago.bat 564156 * 6516
Divide by zero error.
10 was unexpected at this time.

C:\test>judago.bat 564156 / 6516
Divide by zero error.
10 was unexpected at this time.

C:\test>judago.bat 564 / 616655
Divide by zero error.
10 was unexpected at this time.

C:\test>judago.bat 564156 / 65
Divide by zero error.
10 was unexpected at this time.


Report •

#10
January 17, 2009 at 19:45:21
I suspect this problem is caused by inconsistencies between win2k and xp batch:

When I said it will probably only work on 2k+ I was refering to delayed expansion.

Microsoft Windows XP [Version 5.1.2600]

D:\Home\DATA\32bitwa>MATH.CMD 64156.166 * 6516
3676041577.656

D:\Home\DATA\32bitwa>MATH.CMD 564156 * 6516
3676040496

D:\Home\DATA\32bitwa>MATH.CMD 564156 / 6516
86.5801104972

D:\Home\DATA\32bitwa>MATH.CMD 564 / 616655
0.0009146118

D:\Home\DATA\32bitwa>MATH.CMD 564156 / 65
8679.323076923

Unfortunately I don't have a copy of win2k to test on...

[edit that being said one of the numbers is still wrong...]


Report •

#11
January 17, 2009 at 19:57:03
IMO W2k was their best OS, but I'll probably have to upgrade one of these days.

The Perl script will work on NT 3.5 and up, and possibly Win98. And if we correct the shebang line, which is the first line in the script, it would run on Linux and Mac.


Report •

#12
January 17, 2009 at 20:38:55
Yep, cross compatibility is very important these days. As for Win2k being the best, I wouldn't know, went straight from 98 to xp.

It'll take me a while to throw regex together that quickly and effectively in perl. Might just start with the tutorials...

In the mean time if any one can spot a fix/the problem in with the script let me know. The fact that "divide by zero error" is one of the errors means set /a must be involved.

As for:
MATH.CMD 64156.166 * 6516
3676041577.656

I think I had used ^c too many times, avoiding endlocal, a fresh shell and:
MATH.CMD 64156.166 * 6516
418041577.656


Report •

#13
January 18, 2009 at 01:38:01
C:\batch>math 21 * 7
Divide by zero error.
10 was unexpected at this time.

C:\batch>find /n "lss 10 (" math.bat

---------- MATH.BAT
[206]if %astore% lss 10 (

C:\batch>ver

Microsoft Windows XP [Version 5.1.2600]

astore is empty/not defined, thus causing error.
if <EMPTY> lss 10 (
tracing line before if statement (LINE 205).
set /a astore=%add1:~-1%+%add2:~-1%%acarry%

the add loop debugging info:
on the last loop add2 becomes empty.

add1=7  add1lastchar=7
add2=1  add2lastchar=1
acarry=  
add1=0  add1lastchar=0
add2=21  add2lastchar=1
acarry=  
add1=21  add1lastchar=1
add2=21  add2lastchar=1
acarry=  
add1=2  add1lastchar=2
add2=2  add2lastchar=2
acarry=  
add1=42  add1lastchar=2
add2=21  add2lastchar=1
acarry=  
add1=4  add1lastchar=4
add2=2  add2lastchar=2
acarry=  
add1=63  add1lastchar=3
add2=21  add2lastchar=1
acarry=  
add1=6  add1lastchar=6
add2=2  add2lastchar=2
acarry=  
add1=84  add1lastchar=4
add2=21  add2lastchar=1
acarry=  
add1=8  add1lastchar=8
add2=2  add2lastchar=2
acarry=  
add1=1  add1lastchar=1
add2=  add2lastchar=~-1
acarry=  

i cant trace back from here, because i dont quite understand how it works and what the each var(s) do. so i will leave it to you to fix it.


Report •

#14
January 18, 2009 at 02:38:05
Reno,

Thanks for pointing that out, I don't belive it was the actual numbers that were the problem(21*7), as it worked just fine for me(147). I think I found the real issue, a missing endlocal at the end of the multiply subroutine, as more sums are tested that stack of setlocal builds up and vars that should be undefined are retaining there value. You can check this by running a multiplication and typing in set afterwards.

%astore% should never be empty at that point because a few lines before hand add1 and add2 are both check for definition, if there not defined and acarry isn't defined it calls the finish section and goes to aoutput. If acarry is defined and add2 or add1 isn't then add1 or add2 will become part of acarry. If if they are defined then there is at least 1 character for "set /a astore=%add1:~-1%+%add2:~-1%%acarry%" when defined acarry will contain a + infront of it's number.

I have edited the script in response number 5 with the fix, please try again as I am sure it will work properly this time(hopefully)...

[edit]
Perhaps this is the same problem that was present on fishmongers machine?? It has the same error messages. I would be glade to here that one simple bit of house keeping was the only problem and that it isn't an issue of non-compatibility. After all they are all internal commands.


Report •

#15
January 18, 2009 at 03:30:50
I'v been playing with that perl script, with a slight modification, the results are a little of on some numbers, there not even to the crazy side of things when it comes to decimals...

#!perl

use strict;
use warnings;

my $usage = "USAGE: $0 <number> [-+/*] <number>\n";

die $usage unless ( 
                    @ARGV == 3
                and $ARGV[0] =~ /^\d+\.?(\d+?)?$/
                and $ARGV[1] =~ /^[-+\/*]$/
                and $ARGV[2] =~ /^\d+\.?(\d+?)?$/
);
printf '%.20f', eval "$ARGV[0] $ARGV[1] $ARGV[2]";
print "\n"

An example:

D:\Home\DATA\32bitwa>perl fishmonger.pl 0.322545 * 0.5564214
0.17947094046299999000

D:\Home\DATA\32bitwa>math 0.322545 * 0.5564214
0.179470940463

Windows calc concurs that the result is indeed 0.179470940463, and if that's not enough consider that in multiplication the maximum number of decimal places in the product is equal to the sum of decimal places from both factors .

Can anyone confirm that this is a result of having non-ecc ram? If not it suprises me that it takes the sum to more decimal places than nessacery....


[edit]
I just gave it another look and it only seems to do this when using printf 'f.20%',. I though that only specified the number of decimal places it goes to, unless rounding comes into play....


Report •

#16
January 18, 2009 at 06:26:16
Part of the answer is in this Perl FAQ.

perldoc -q round

There are numerous discussions about this rounding/truncating issue and it's not limited to Perl.

Here are some of the discussions that pertain to Perl.
http://groups.google.com/group/comp...


Report •

#17
January 19, 2009 at 02:11:03
judago, thats a powerful 64bit floating point batch. i try to do some modifation on the batch but failed. can you help me?

::code after begin label

::Create string of zero(s) and store in var 0 - 15
set 0= &set b=
for /L %%a in (1,1,15) do set %%a=!b!0& set b=!%%a!& echo %%a=!%%a!

::start timer of calculation
for /f "tokens=3,4 delims=:, " %%a in ('echo %time%') do set start=%%a%%b0

::code when output result

::check timer for elapsed time
for /f "tokens=3,4 delims=:, " %%a in ('echo %time%') do set /a elapsed=1%%a%%b0-1!start!
if !elapsed! lss 0 (set /a elapsed+=60000)
Echo %~nx0 Elapsed Time: %elapsed% ms

::set/a comparison in time elapsed
echo %1%3|find ".">nul && (echo can't compare floating point) || (
	for /f "tokens=3,4 delims=:, " %%a in ('echo %time%') do set start=%%a%%b0
	set/a set_a=%1%2%3 & set set_a
	for /f "tokens=3,4 delims=:, " %%a in ('echo %time%') do set /a elapsed=1%%a%%b0-1!start!
	if !elapsed! lss 0 (set /a elapsed+=60000)
	Echo SET/A Elapsed Time: !elapsed! ms
)

::code replace in section of if else if else if else statement

FOR /L %%a in (15,-1,1) do (
	if NOT "!mult2:~%%a,1!"=="" (
		call :subtract inte rnal mult2 1!%%a!
		SET mreduce2=!madup!!%%a!
		goto :breakloop
	)
)
call :subtract inte rnal mult2 1
SET mreduce2=!madup!
:breakloop

after i change the code in the multiply subroutine, it goes into infinite loop.
i am trying to grab the idea behind the code, and i need help from you, if possible, please indent the nested loop code and put some comment all over the code. thank you.


Report •

#18
January 19, 2009 at 13:31:57
[edit]
Reno I just realised what you are trying to achieve, remove the hideous redundant if statement. I think I have and idea to completely change the method used to multiply.

1. add the multiplier to itself 9 times making 9 variables, one at each stage.

2. cut the factor up from end to beginning adding a extra zero to a ten multiplier after a digit is parsed. The last digit will be a number 0-9 find the appropriate variable from step 1 and add the ten multiplier, then add it to the total. Remove the last digit and start again until the factor is undefined.

It may take a little time for me to implement and could even prove to be slower....

With the code you are trying to replace I was choosing speed over code size.
[/edit]


Reno,

What exactly are you trying to achieve?

I might get some time to comment the code later, got to go to work now.

Oh and it's not 64bit, it can go larger(except for division) but at the moment it's only practical on addition and subtraction due to speed.

D:\Home\DATA\32bitwa>MATH.CMD 18446744073709551616 + 18446744073709551616
36893488147419103232

D:\Home\DATA\32bitwa>MATH.CMD 18446744073709551617 - 18446744073709551616
1

Oh and if anyone's interested I edited the script if post#5 with an attempt to avoid these "divide by zero" errors. I did it the day before last but forgot to mention it.


Report •

#19
January 19, 2009 at 23:44:04
Sorry Reno, it was just so much easier to fix the problem compared to commenting and indenting so I fixed it instead. I may at some stage comment it.......

Here is the much improved version, multiplication is now much faster and is made up of fewer lines. This was completed a few minutes ago so it is not fully tested, please report any bugs. If anyone has any ideas on how to improve the division I am still very interested.

@ECHO Off
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO %~1|FIND "?"||IF NOT "%~2"=="" IF NOT "%~3"=="" GOTO BEGIN
:help
echo Usage:&echo.&echo %~nx0 number1 operator number2 [outputvariable]&echo.
echo Where numberx is your input numbers to be calculated and operator is a valid operator
echo.&echo Valid operators are:&echo.
echo - Minus.&echo + Plus.&echo * Multiply.&echo \ Divide.&echo.
echo Output variable is optional -  if present the output will be set to the variable name 
echo provided rather than be printed to screen.&echo.&echo.
echo.&echo Division has a limitation in regards to the divisor, the maximum divisor for whole numbers
echo is 2147483646 and numbers this large will be slow. If decimal places are present then the maximum 
echo size for the divisor will be considerably less. The dividend can be a very large number if needs be.&echo.
pause&&endlocal&&goto :eof
:begin
set varout=%~4
set optr=%~2
set inpnum1=%1
set inpnum2=%3
set dplace=
if "%inpnum1:~0,1%"=="." set inpnum1=0%inpnum1%
if "%inpnum2:~0,1%"=="." set inpnum2=0%inpnum2%
if "%inpnum1:~-1%"=="." set inpnum1=%inpnum1%0
if "%inpnum2:~-1%"=="." set inpnum2=%inpnum2%0
if "%inpnum1%"=="%inpnum1:.=%" if "%inpnum2%"=="%inpnum2:.=%" goto dpad1
if "%inpnum1%"=="%inpnum1:.=%" set inpnum1=%inpnum1%.0
if "%inpnum2%"=="%inpnum2:.=%" set inpnum2=%inpnum2%.0
set fcnt1=0
set fcnt2=0
set float1=%inpnum1%
set float2=%inpnum2%

:f1
if not "%float1%"=="%float1:.=%" (
set /a fcnt1+=1
set float1=%float1:~0,-1%
goto f1
)
:f2
if not "%float2%"=="%float2:.=%" (
set /a fcnt2+=1
set float2=%float2:~0,-1%
goto f2
)
if defined fcnt1 (
if defined fcnt2 (
if %fcnt1% geq %fcnt2% (
set dplace=%fcnt1%
) else (
set dplace=%fcnt2%
)) else (
set dplace=%fcnt1%
)) else (
set dplace=%fcnt2%
)
:fapd1
if not "!inpnum1:~-%dplace%,1!"=="." set inpnum1=%inpnum1%0&&goto fapd1
:fapd2
if not "!inpnum2:~-%dplace%,1!"=="." set inpnum2=%inpnum2%0&&goto fapd2
set /a dplace-=1&set inpnum1=%inpnum1:.=%&set inpnum2=%inpnum2:.=%
:dpad1
if not defined inpnum1 set inpnum1=0&&goto zzskip
if "!inpnum1:~0,1!"=="0" set inpnum1=!inpnum1:~1!&&goto dpad1
:dpad2
if not defined inpnum2 set inpnum2=0&&goto zzskip
if "!inpnum2:~0,1!"=="0" set inpnum2=!inpnum2:~1!&&goto dpad2
:zzskip
if "!optr!"=="-" goto subtract
if "!optr!"=="+" goto add
if "!optr!"=="/" goto divide
if "!optr!"=="*" goto multiply
goto help

:subtract
SET SUB1=
SET SUB2=
set neg=
if "%~1%~2"=="internal" (
if defined %3 (set sub1=!%3!) else set sub1=%3
if defined %4 (set sub2=!%4!) else set sub2=%4
) else (
set sub1=!inpNUM1!
set sub2=!inpNUM2!
)
set stotal=
set stten=
set subsub1=!sub2!
set subsub2=!sub1!
:sloop
set sc1=
set sc2=
set sstrore=
if defined sub1 (
if defined sub2 (
set sc1=%sub1:~-1%
set sc2=%sub2:~-1%
set sub1=%sub1:~0,-1%
set sub2=%sub2:~0,-1%
) else (
if defined stten (
set sub2=!stten!
set stten=
set sc1=!sub1:~-1!
set sc2=!sub2:~-1!
set sub1=!sub1:~0,-1!
set sub2=!sub2:~0,-1!
) else (
set stotal=%sub1%%stotal%
call :finish stotal
goto soutput
)
)
) else (
if defined sub2 (
set sub1=%subsub1%
set sub2=%subsub2%
set neg=-
set stotal=
set stten=
goto sloop
) else (
if defined stten (
set sub1=%subsub1%
set sub2=%subsub2%
set neg=-
set stotal=
set stten=
goto sloop
) else (
call :finish stotal
goto soutput
)
)
)
set sazc=
set sazcnt=
:asttend
if !sc1!==0 if !sc2! gtr 0 if defined sub1 (
set sazc=!sub1:~-1!
set /a sazcnt+=1
set sub1=!sub1:~0,-1!
if !sazc!==0 goto asttend
set /a sazc-=1
set sc1=10
set sub1=!sub1!!sazc!
for /l %%a in (2,1,!sazcnt!) do set sub1=!sub1!9
)
if defined stten (
set /a sc1-=1
if !sc1! lss 0 (
set stten+=1
set /a sc1+=10
) else (
set stten=
)
)
set /a sstrore=%sc1%-%sc2%
if !sstrore! lss 0 (
set stten=1
set /a sstrore+=10
set stten=!stten:-=!
)
set stotal=%sstrore%%stotal%
goto sloop
:soutput
if "%~1%~2"=="internal" (
set %3=%stotal%
) else (
if not defined varout (
echo %stotal%
) else (
endlocal&set %varout%=%stotal%
))
goto :eof

:add
if "%~1%~2"=="internal" (
if defined %3 (set add1=!%3!) else set add1=%3
if defined %4 (set add2=!%4!) else set add2=%4
) else (
set add1=!inpNUM1!
set add2=!inpNUM2!
)
set atotal=
set astore=
set a carry=
:aloop
if not defined add1 (
if defined acarry (
set add1=%acarry%
set acarry=
) else (
set atotal=%add2%%atotal%
call :finish atotal
goto aoutput
))
if not defined add2 (
if defined acarry (
set add2=%acarry%
set acarry=
) else (
set atotal=%add1%%atotal%
call :finish atotal
goto aoutput
))
if not defined acarry (
set /a astore=%add1:~-1%+%add2:~-1%
) else (
set /a astore=%add1:~-1%+%add2:~-1%+%acarry%
set acarry=
)
if %astore% lss 10 (
set atotal=%astore%%atotal%
) else (
set atotal=%astore:~-1%%atotal%
set acarry=%astore:~0,-1%
)
set astore=
set add1=%add1:~0,-1%
set add2=%add2:~0,-1%
goto aloop
:aoutput
if "%~1%~2"=="internal" (
set %3=%atotal%
) else (
if not defined varout (
echo %atotal%
) else (
endlocal&set %varout%=%atotal%
))
goto :eof


:MULTIPLY
SET MTOTAL=0
set /a ph=dplace*2
set dplace=
set mten=
set mult1=!inpnum1!
set mult2=!inpnum2!
IF %mult1% equ 0 set mtotal=0&&goto moutput
IF %mult2% equ 0 set mtotal=0&&goto moutput
IF %mult2% equ 1 (
set mtotal=%mult1%
set dplace=!ph!
call :finish mtotal
goto moutput
) else (
IF %mult1% equ 1 (
set mtotal=%mult2%
set dplace=!ph!
call :finish mtotal
goto moutput
))
set mcnt=!mult1!
set m1=!mult1!
for /l %%a in (2,1,9) do (
call :add inte rnal mcnt %mult1% 
set m%%a=!mcnt!
)
set mcnt=
:MPLY
if defined mult2 (
set mby=!mult2:~-1!
set mult2=!mult2:~0,-1!
) else (
set dplace=!ph!
call :finish mtotal
goto moutput
)
if !mby!==0 (
set mten=%mten%0
goto mply
)
call :add inte rnal mtotal !m%mby%!%mten%
set mten=%mten%0
goto mply
:moutput
if not defined varout (echo %mtotal%) else endlocal&set %varout%=%mtotal%
goto :eof

:divide
SET DCNT=
set dtotal=0
if defined dplace if !dplace! gtr 11 (
set inpnum1=!inpnum1:~0,-1!
set inpnum2=!inpnum2:~0,-1!
set /a dplace-=1
goto divide
)
if defined dplace (set /a dplace-=1) else set dplace=0
set /a dnpl=10 - dplace
for /l %%a in (1,1,%dnpl%) do (
set inpnum1=!inpnum1!0
set /a dplace+=1
)
set div1=!inpnum1!
set div2=!inpnum2!
set ph=!dplace!
set dplace=
if !div2!==0 echo Divide by 0^^!>&2&&exit /b 2
:dsplit
if not defined div1 goto dloop
if %div1% gtr 99 (
set /a dcnt+=1
set dcnk!dcnt!=%div1:~-2%
set div1=%div1:~0,-2%
goto dsplit
) else (
set /a dcnt+=1
set dcnk!dcnt!=%div1%
)
:dloop
if defined dcnk%dcnt% (
if "!dcnk%dcnt%:~0,1!"=="0" (
set dcnk%dcnt%=!dcnk%dcnt%:~1!
goto dloop
)
) else (
set dcnk%dcnt%=0
goto dpad
)
set dvcnt=0
:dred
If !dcnk%dcnt%! geq !div2! (
If !dcnk%dcnt%! gtr !div2!000000000 (
call :subtract inte rnal dcnk%dcnt% !div2!000000000
call :add inte rnal dvcnt 1000000000
goto dred
) else (
If !dcnk%dcnt%! gtr !div2!00000000 (
call :subtract inte rnal dcnk%dcnt% !div2!00000000
call :add inte rnal dvcnt 100000000
goto dred
) else (
If !dcnk%dcnt%! gtr !div2!0000000 (
call :subtract inte rnal dcnk%dcnt% !div2!0000000
call :add inte rnal dvcnt 10000000
goto dred
) else (
If !dcnk%dcnt%! gtr !div2!000000 (
call :subtract inte rnal dcnk%dcnt% !div2!000000
call :add inte rnal dvcnt 1000000
goto dred
) else (
If !dcnk%dcnt%! gtr !div2!00000 (
call :subtract inte rnal dcnk%dcnt% !div2!00000
call :add inte rnal dvcnt 100000
goto dred
) else (
If !dcnk%dcnt%! gtr !div2!0000 (
call :subtract inte rnal dcnk%dcnt% !div2!0000
call :add inte rnal dvcnt 10000
goto dred
) else (
If !dcnk%dcnt%! gtr !div2!000 (
call :subtract inte rnal dcnk%dcnt% !div2!000
call :add inte rnal dvcnt 1000
goto dred
) else (
If !dcnk%dcnt%! gtr !div2!00 (
call :subtract inte rnal dcnk%dcnt% !div2!00
call :add inte rnal dvcnt 100
goto dred
) else (
If !dcnk%dcnt%! gtr !div2!0 (
call :subtract inte rnal dcnk%dcnt% !div2!0
call :add inte rnal dvcnt 10
goto dred
) else (
call :subtract inte rnal dcnk%dcnt% !div2!
call :add inte rnal dvcnt 1
goto dred
))))))))))
:dpad
if "!dvcnt:~1,1!"=="" set dvcnt=0!dvcnt!
set dtotal=%dtotal%%dvcnt%
set dvcnt=0
set dtmpcnt=%dcnt%
set /a dcnt-=1
if !dcnk%dtmpcnt%! gtr 0 (
set carry=!dcnk%dtmpcnt%!
set dcnk!dcnt!=!carry!!dcnk%dcnt%!
)
if %dcnt% neq 0 goto dloop
set dplace=!ph!
call :finish dtotal
:doutput
if not defined varout (echo %dtotal%) else endlocal&set %varout%=%dtotal%
goto :eof

:finish
if !dplace! equ 0 set dplace=
if defined dplace if "!%1:~%dplace%,1!"=="" set %1=0!%1!&&goto finish
if defined dplace set %1=!%1:~0,-%dplace%!.!%1:~-%dplace%!
:killzerodec
if defined dplace (
if "!%1:~-1!"=="0" (
set %1=!%1:~0,-1!
goto killzerodec
) else (
if "!%1:~-1!"=="." (
set %1=!%1:~0,-1!
)))
:killzerowhle
if "!%1:~0,1!"=="0" (
set %1=!%1:~1!
goto killzerowhle
) else (
if "!%1:~0,1!"=="." set %1=0!%1!
)
IF NOT DEFINED %1 SET %1=0
set %1=%neg%!%1!
goto :eof


Report •

#20
January 21, 2009 at 09:15:29
SHEESH! I thought I was a hard case.


=====================================
If at first you don't succeed, you're about average.

M2


Report •

#21
January 21, 2009 at 12:51:42
Hi M2,

"SHEESH! I thought I was a hard case."

What do you mean by that?


Did you try it/does it work in win2k now?


Report •

#22
January 22, 2009 at 00:49:24
Baby steps...

Division is now unlimited but slower, maybe I will find a tweak...

@ECHO Off
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO %~1|FIND "?"||IF NOT "%~2"=="" IF NOT "%~3"=="" GOTO BEGIN
:help
echo Usage:&echo.&echo %~nx0 number1 operator number2 [outputvariable]&echo.
echo Where numberx is your input numbers to be calculated and operator is a valid operator
echo.&echo Valid operators are:&echo.
echo - Subtract.&echo + Add.&echo * Multiply.&echo \ Divide.&echo.
echo Output variable is optional -  if present the output will be set to the variable name 
echo provided rather than be printed to screen.&echo.&echo.
pause&&endlocal&&goto :eof
:begin
set varout=%~4
set optr=%~2
set inpnum1=%1
set inpnum2=%3
set dplace=
if "%inpnum1:~0,1%"=="." set inpnum1=0%inpnum1%
if "%inpnum2:~0,1%"=="." set inpnum2=0%inpnum2%
if "%inpnum1:~-1%"=="." set inpnum1=%inpnum1%0
if "%inpnum2:~-1%"=="." set inpnum2=%inpnum2%0
if "%inpnum1%"=="%inpnum1:.=%" if "%inpnum2%"=="%inpnum2:.=%" goto dpad1
if "%inpnum1%"=="%inpnum1:.=%" set inpnum1=%inpnum1%.0
if "%inpnum2%"=="%inpnum2:.=%" set inpnum2=%inpnum2%.0
set fcnt1=0
set fcnt2=0
set float1=%inpnum1%
set float2=%inpnum2%
:f1
if not "%float1%"=="%float1:.=%" (
set /a fcnt1+=1
set float1=%float1:~0,-1%
goto f1
)
:f2
if not "%float2%"=="%float2:.=%" (
set /a fcnt2+=1
set float2=%float2:~0,-1%
goto f2
)
if defined fcnt1 (
if defined fcnt2 (
if !fcnt1! geq !fcnt2! (
set dplace=%fcnt1%
) else (
set dplace=%fcnt2%
)) else (
set dplace=%fcnt1%
)) else (
set dplace=%fcnt2%
)
:fapd1
if not "!inpnum1:~-%dplace%,1!"=="." set inpnum1=%inpnum1%0&&goto fapd1
:fapd2
if not "!inpnum2:~-%dplace%,1!"=="." set inpnum2=%inpnum2%0&&goto fapd2
set /a dplace-=1&set inpnum1=%inpnum1:.=%&set inpnum2=%inpnum2:.=%
:dpad1
if not defined inpnum1 set inpnum1=0&&goto zzskip
if "!inpnum1:~0,1!"=="0" set inpnum1=!inpnum1:~1!&&goto dpad1
:dpad2
if not defined inpnum2 set inpnum2=0&&goto zzskip
if "!inpnum2:~0,1!"=="0" set inpnum2=!inpnum2:~1!&&goto dpad2
:zzskip
if "!optr!"=="-" goto subtract
if "!optr!"=="+" goto add
if "!optr!"=="/" goto divide
if "!optr!"=="*" goto multiply
goto help

:subtract
for %%a in (SUB1 SUB2 neg) do set %%a=
if "%~1%~2"=="internal" (
if defined %3 (set sub1=!%3!) else set sub1=%3
if defined %4 (set sub2=!%4!) else set sub2=%4
) else (
set sub1=!inpNUM1!
set sub2=!inpNUM2!
)
set stotal=
set stten=
set subsub1=!sub2!
set subsub2=!sub1!
:sloop
set sc1=
set sc2=
set sstrore=
if defined sub1 (
if defined sub2 (
set sc1=%sub1:~-1%
set sc2=%sub2:~-1%
set sub1=%sub1:~0,-1%
set sub2=%sub2:~0,-1%
) else (
if defined stten (
set sub2=!stten!
set stten=
set sc1=!sub1:~-1!
set sc2=!sub2:~-1!
set sub1=!sub1:~0,-1!
set sub2=!sub2:~0,-1!
) else (
set stotal=%sub1%%stotal%
call :finish stotal
goto soutput
)
)
) else (
if defined sub2 (
set sub1=%subsub1%
set sub2=%subsub2%
set neg=-
set stotal=
set stten=
goto sloop
) else (
if defined stten (
set sub1=%subsub1%
set sub2=%subsub2%
set neg=-
set stotal=
set stten=
goto sloop
) else (
call :finish stotal
goto soutput
)
)
)
set sazc=
set sazcnt=
:asttend
if !sc1!==0 if !sc2! gtr 0 if defined sub1 (
set sazc=!sub1:~-1!
set /a sazcnt+=1
set sub1=!sub1:~0,-1!
if !sazc!==0 goto asttend
set /a sazc-=1
set sc1=10
set sub1=!sub1!!sazc!
for /l %%a in (2,1,!sazcnt!) do set sub1=!sub1!9
)
if defined stten (
set /a sc1-=1
if !sc1! lss 0 (
set stten+=1
set /a sc1+=10
) else (
set stten=
)
)
set /a sstrore=%sc1%-%sc2%
if !sstrore! lss 0 (
set stten=1
set /a sstrore+=10
set stten=!stten:-=!
)
set stotal=%sstrore%%stotal%
goto sloop
:soutput
if "%~1%~2"=="internal" (
set %3=%stotal%
) else (
if not defined varout (
echo %stotal%
) else (
endlocal&set %varout%=%stotal%
))
goto :eof

:add
if "%~1%~2"=="internal" (
if defined %3 (set add1=!%3!) else set add1=%3
if defined %4 (set add2=!%4!) else set add2=%4
) else (
set add1=!inpNUM1!
set add2=!inpNUM2!
)
set atotal=
set astore=
set a carry=
:aloop
if not defined add1 (
if defined acarry (
set add1=%acarry%
set acarry=
) else (
set atotal=%add2%%atotal%
call :finish atotal
goto aoutput
))
if not defined add2 (
if defined acarry (
set add2=%acarry%
set acarry=
) else (
set atotal=%add1%%atotal%
call :finish atotal
goto aoutput
))
if not defined acarry (
set /a astore=%add1:~-1%+%add2:~-1%
) else (
set /a astore=%add1:~-1%+%add2:~-1%+%acarry%
set acarry=
)
if !astore! lss 10 (
set atotal=%astore%%atotal%
) else (
set atotal=%astore:~-1%%atotal%
set acarry=%astore:~0,-1%
)
set astore=
set add1=%add1:~0,-1%
set add2=%add2:~0,-1%
goto aloop
:aoutput
if "%~1%~2"=="internal" (
set %3=%atotal%
) else (
if not defined varout (
echo %atotal%
) else (
endlocal&set %varout%=%atotal%
))
goto :eof


:MULTIPLY
SET MTOTAL=0
set /a ph=dplace*2
set dplace=
set mten=
set mult1=!inpnum1!
set mult2=!inpnum2!
IF !mult1! equ 0 set mtotal=0&&goto moutput
IF !mult2! equ 0 set mtotal=0&&goto moutput
IF !mult2! equ 1 (
set mtotal=%mult1%
set dplace=!ph!
call :finish mtotal
goto moutput
) else (
IF !mult1! equ 1 (
set mtotal=%mult2%
set dplace=!ph!
call :finish mtotal
goto moutput
))
set m1=!mult1!
for /l %%a in (2,1,9) do (
call :add inte rnal m1 %mult1% 
set m%%a=!m1!
)
set m1=!mult1!
:MPLY
if defined mult2 (
set mby=!mult2:~-1!
set mult2=!mult2:~0,-1!
) else (
set dplace=!ph!
call :finish mtotal
goto moutput
)
if !mby!==0 (
set mten=%mten%0
goto mply
)
call :add inte rnal mtotal !m%mby%!%mten%
set mten=%mten%0
goto mply
:moutput
if not defined varout (echo %mtotal%) else endlocal&set %varout%=%mtotal%
goto :eof

:divide
for %%a in (din1 din2 diff dten DCNT) do set %%a=
set dtotal=0
set dplace=10
set inpnum1=!inpnum1!0000000000
set div1=!inpnum1!
set div2=!inpnum2!
if !div2!==0 echo Divide by 0^^!>&2&&exit /b 2
:din1
if defined inpnum1 (
set /a din1+=1
set inpnum1=%inpnum1:~1%
goto din1
)
:din2
if defined inpnum2 (
set /a din2+=1
set inpnum2=%inpnum2:~1%
goto din2
)
if !din2! gtr !din1! (
set dtotal=0
goto doutput
)
set /a diff=din1-din2
for /l %%a in (1,1,%diff%) do set dten=!dten!0
set ph=!dplace!
set dplace=
:div
set dtmp=%div1%
call :subtract inte rnal div1 %div2%%dten%
if defined neg (
set div1=!dtmp!
set neg=
if defined dten (
set dten=!dten:~1!
goto div
) else (
set dplace=!ph!
call :finish dtotal
goto doutput
)
) else (
call :add inte rnal dtotal 1%dten%
goto div
)
:doutput
if not defined varout (echo %dtotal%) else endlocal&set %varout%=%dtotal%
goto :eof

:finish
if !dplace! equ 0 set dplace=
if defined dplace if "!%1:~%dplace%,1!"=="" set %1=0!%1!&&goto finish
if defined dplace set %1=!%1:~0,-%dplace%!.!%1:~-%dplace%!
:killzerodec
if defined dplace (
if "!%1:~-1!"=="0" (
set %1=!%1:~0,-1!
goto killzerodec
) else (
if "!%1:~-1!"=="." (
set %1=!%1:~0,-1!
)))
:killzerowhle
if "!%1:~0,1!"=="0" (
set %1=!%1:~1!
goto killzerowhle
) else (
if "!%1:~0,1!"=="." set %1=0!%1!
)
IF NOT DEFINED %1 SET %1=0
set %1=%neg%!%1!
goto :eof


Report •

#23
January 23, 2009 at 02:36:48
I Judago,

I mean I sometimes spend great deal deal of time and effort on things that probably aren't worth it in any practical sense.

And no, I didn't mess with this.


=====================================
If at first you don't succeed, you're about average.

M2


Report •

#24
January 23, 2009 at 02:54:06
"I mean I sometimes spend great deal deal of time and effort on things that probably aren't worth it in any practical sense."

I have quite a few unfinished projects testament to this. Even so I have come to realise that these impractical efforts lead to practical knowledge and skills that in the long run make gains rather than the perceived loss.

I think I'm finished with this project, at least for now. It does what I wanted it to do, and, with the exception of division, does it in good time.

Thanks to anyone that had a look into this, I appreciate your effort.


Report •


Ask Question