## The Unofficial Macro Scheduler Puzzler #11

Anything Really. Just keep it clean!

Moderators: Dorian (MJT support), JRL

JRL
Automation Wizard
Posts: 3233
Joined: Mon Jan 10, 2005 6:22 pm
Location: Iowa

### The Unofficial Macro Scheduler Puzzler #11

I am puzzled. I want to multiply two numbers and get back the result that I see if I do the math using my trusty no.2 yellow pencil.

This code:

Code: Select all

``````Let>num_1=12345678987654321234567898765432123456789876543212345678987654321
Let>num_2=98765432123456789876543212345678987654321234567898765432123456789
Let>ans=%num_1%*%num_2%
MDL>ans``````
Gives me an answer that looks like:
"1.21932632007316E129". I want an answer that displays all 130 digits rather than an answer in scientific notation.

The goals for this Puzzler? Write a script that completes the math presented in the script code above and displays all digits of the answer. The multiplication must be accurate and error free. Second the fastest process as determined by my quad core Win7 with 8 gig RAM is the winner. If there is a tie we'll resort to the old standby "fewest lines of code". Hopefully we'll have a winning entry on or before Friday, August 29, 2014. I will test your code with other number combinations. So submitting a formula that somehow presents the correct answer to this particular problem but claims that 2x2 is 57 will negate the accuracy requirement.

What will you win????

Nothing. Only my sincere admiration and possibly a bit of knowledge you didn't have before you started.

I'll present my code next week. As a point of reference mine uses only Macro Scheduler functions and completes the above math in about 10 seconds. Excluding the dialog it is 119 lines of code. I'm guessing this is easily surpassable.

Have fun... good luck.

P.S. Yes Marcus. You can play too.

Meryl
Staff
Posts: 115
Joined: Wed Sep 19, 2012 1:53 pm
Location: Texas
Contact:

### Re: The Unofficial Macro Scheduler Puzzler #11

Is everyone stumped???

hagchr
Macro Veteran
Posts: 264
Joined: Mon Jul 05, 2010 7:53 am
Location: Stockholm, Sweden

### Re: The Unofficial Macro Scheduler Puzzler #11

Hi, thanks for a great puzzle. I answered the last one too quickly before people had the chance to think it through, which kind of "ruined" the discussion, so will not do that mistake again. I will post my solution (if still worthy) on Thursday. Let's see if I am the only one using PI to solve it.

JRL
Automation Wizard
Posts: 3233
Joined: Mon Jan 10, 2005 6:22 pm
Location: Iowa

### Re: The Unofficial Macro Scheduler Puzzler #11

Using PI? You're going to need to share that no matter what. I have resolve PI to xxxxx places on the list of future puzzlers. If you're already doing that you might be getting extra credit.

hagchr
Macro Veteran
Posts: 264
Joined: Mon Jul 05, 2010 7:53 am
Location: Stockholm, Sweden

### Re: The Unofficial Macro Scheduler Puzzler #11

I think you fellow puzzlers have had enough time so here is my attempt for a solution. Without comments etc around 100 or so lines of code. Can get it down to around 60 but then it will be around 1s slower.

Hopefully I did not mislead anyone with my comment about PI. I did use it but maybe not in the way expected. I needed an array to contain the build-up of the result and a fast way to create and initiate an array in MS is to have a string of 0s and use RegEx to create the array. So, to reduce looping, I needed a long string and tried to find any predefined constants in MS and found PI which is defined with 14 decimals, ie 16 characters in total. So to create the string I concatenated PI several times which gives a garbage string but then used RegEx to replace ANY character with a zero. Then use RegEx to get the right number of characters and create the array with the right number of elements, all initiated with zeroes, ready for action.

Another thing I used was that as long as you have control of the size of the numbers you multiply, you don't really have to do it digit by digit but can group them together and do the calculation on the groups.

It gives the right result for 2x2 so hopefully also for the larger numbers.

Any other solutions? Is there a secret MLN (Multiply Large Numbers) function in MS?

Code: Select all

``````Timer>time0

//Define numbers to multiply
Let>num_1=12345678987654321234567898765432123456789876543212345678987654321
Let>num_2=98765432123456789876543212345678987654321234567898765432123456789

//Create arrays for num_1 and num_2(MA_x, MB_x), and result (MRes_x). Then multiply individual
//numbers, clean MRes, and finally concatenate back to a string/number.
GoSub>Create_Array_for_Numbers
Gosub>Create_Array_for_Result
GoSub>Multiply_individual_Numbers
GoSub>Finalize_Result_Array

Timer>time1
Let>time={%time1%-%time0%}
Mdl>Result: %Res%%CRLF%Time: %time% ms

SRT>Create_Array_for_Numbers
//One array for each number, MA and MB, each with total elements NMA and NMB
//Factor determines how many digits are grouped together for the calculation,
//it is set to 1 for long numbers to avoid size problems for large numbers.
Length>num_1,NMA
Length>num_2,NMB
Let>factor=6
If>{(%NMA%>1000) or (%NMB%>1000)}
Let>factor=1
Else
If>{(%NMA%>100) or (%NMB%>100)}
Let>factor=5
Else
Let>factor=6
Endif
Endif

//Place 0s to the left of numbers 1&2 to fit an even number of groups,
//then extract/parse groups.
Let>x={%NMA% mod %factor%}
If>%x%<>0
Let>x=%factor% - %x%
Let>ct=0
Let>tmp=
While>ct<x
Let>tmp=%tmp%0
EndWhile
Let>num_1=%tmp%%num_1%
Endif
RegEx>\d{%factor%},num_1,0,MA,NMA,0

Let>x={%NMB% mod %factor%}
If>%x%<>0
Let>x=%factor% - %x%
Let>ct=0
Let>tmp=
While>ct<x
Let>tmp=%tmp%0
EndWhile
Let>num_2=%tmp%%num_2%
Endif
RegEx>\d{%factor%},num_2,0,MB,NMB,0

//Calculate maximum total number of individual digits in the Result
Let>ResLength={(%NMA%+%NMB%)*%factor%}
END>Create_Array_for_Numbers
SRT>Create_Array_for_Result
//Concatenate the constant PI several times to create dummy string
//and then use RegEx to replace characters with 0s and finally extract
//a string and an array, MRes, with the right number of elements.
Let>HelpString=%{Pi}%%{Pi}%%{Pi}%%{Pi}%%{Pi}%
Length>HelpString,nLength
Let>tmp=ResLength/nLength
Let>tmp={Int(%tmp%)}+1
//So if one concatenates HelpString tmp times then the string will long enough
Let>ct=0
Let>RefString=
While>ct<tmp
Let>RefString=%RefString%%HelpString%
EndWhile
RegEx>.,RefString,0,M,NM,1,0,RefString
RegEx>(?s)^0{%ResLength%},RefString,0,MRes,NMRes,0
RegEx>\d,MRes_1,0,MRes,NMRes,0
END>Create_Array_for_Result
SRT>Multiply_individual_Numbers
//Multiply by group (size given by factor) and feed into the array, MRes.

Let>ctB={%NMB%+1}
While>ctB>1
Sub>ctB,1
Let>Ref={(%NMRes%-(%NMB%-%ctB%)*%factor%)}
Let>ctA={%NMA%+1}
While>ctA>1
Sub>ctA,1
Let>tmpA=MA_%ctA%
Let>tmpB=MB_%ctB%
Let>tmpRes=MRes_%Ref%
Let>MRes_%Ref%=%tmpRes%+{%tmpA%*%tmpB%}
Let>Ref=%Ref%-%factor%
EndWhile
EndWhile

END>Multiply_individual_Numbers
SRT>Finalize_Result_Array
//If any element in MRes contains a number with more than one digit then
//leave the final digit and move/add any non-final digits to the array element on the left.
//Finally concatenate array elements into a string and remove any initial 0s.
Let>Ref={%NMRes%+1}
While>Ref>1
Sub>Ref,1
//Check the number in the MRes element given by Ref
Let>tmpRes=MRes_%Ref%
RegEx>\d,%tmpRes%,0,M,NM,0
If>{%NM%>=2}
//Separate the number in a final digit and anything to the left
RegEx>(\d+)\d,tmpRes,0,M,NM,1,\$1,str_non_final_digits
RegEx>\d+(\d),tmpRes,0,M,NM,1,\$1,str_final_digit
Let>Ref_Left=%Ref%-1
Let>Restmp=MRes_%Ref_Left%
//Put the final digit into the position Ref in MRes, add any non-final
//digits to the position left of Ref.
Let>MRes_%Ref%=str_final_digit
Let>MRes_%Ref_Left%=%Restmp%+%str_non_final_digits%
Else
//Just one digit, ie already ok.
Endif
Endwhile
//Concatenate the elements in MRes into a string, Res. and remove any initial 0s.
Let>Res=
Let>Ref=%NMRes%+1
While>Ref>1
Sub>Ref,1
Let>tmp=MRes_%Ref%
Let>Res=%tmp%%Res%
EndWhile
RegEx>^0+,Res,0,M,NM,1,,Res
END>Finalize_Result_Array``````

hagchr
Macro Veteran
Posts: 264
Joined: Mon Jul 05, 2010 7:53 am
Location: Stockholm, Sweden

### Re: The Unofficial Macro Scheduler Puzzler #11

Just to avoid confusion for anyone new to MS, to initiate an array I usually use RegEx or a loop. Involving PI was just for this particular problem to increase the speed.

Also, for anyone new to RegEx, the command:

Code: Select all

``RegEx>0,0000000000,0,M,NM,0``
will search for the first string (0) in the second string (0000000000) and if it finds any, will put each one found into
an array (M) and the total number of items found into a variable (NM). So all in all just one line of code will produce an array, here called M with 10 elements (M_1, M_2, … M_10), all initiated to zero.

If you have any string you can convert it to a string with eg. zeroes with:

Code: Select all

``RegEx>.,asdfhkjeuf,0,M,NM,1,0,Result``
which will search for any (.=dot in RegEx language) character in the second string (asdfhkjeuf) and replace it with a zero. The array M will contain garbage but the variable Result will contain the string after replacements i.e. (0000000000).

MS help file has all details of the various RegEx parameters.

JRL
Automation Wizard
Posts: 3233
Joined: Mon Jan 10, 2005 6:22 pm
Location: Iowa

### Re: The Unofficial Macro Scheduler Puzzler #11

hagchr,

Looking like you've got the only entry this time and it is amazingly fast. I think it would have been difficult for anyone to write a faster script. My script (which, much to my embarrassment, I will post) performs the prescribed calculation in about 10 seconds. Your script does the calculation in 2 to 3 tenths of a second. My script does the math exactly the way one would do it with a pencil and paper. I have not yet taken the time to study your script to ascertain what mathematical magic you're using.

I am impressed.

My script:

Code: Select all

``````
Dialog>Dialog1
object Dialog1: TForm
Left = 644
Top = 113
HelpContext = 5000
Caption = 'Multiply Long Numbers'
ClientHeight = 397
ClientWidth = 1056
Color = clBtnFace
Position = poScreenCenter
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = True
ShowHint = True
DesignSize = (
1056
397)
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 40
Top = 8
Width = 59
Height = 13
Caption = 'First Number'
end
object Label2: TLabel
Left = 40
Top = 56
Width = 77
Height = 13
Caption = 'Second Number'
end
object Label3: TLabel
Left = 40
Top = 200
Width = 37
Height = 13
Caption = 'Product'
end
object Label4: TLabel
Left = 368
Top = 128
Width = 63
Height = 13
Caption = 'Product Time'
end
object Label5: TLabel
Left = 976
Top = 128
Width = 77
Height = 13
Caption = 'Character Count'
end
object Label6: TLabel
Left = 376
Top = 152
Width = 6
Height = 13
Caption = '0'
end
object Label7: TLabel
Left = 984
Top = 152
Width = 6
Height = 13
Caption = '0'
end
object Label8: TLabel
Left = 840
Top = 128
Width = 47
Height = 13
Caption = 'Sum Time'
end
object Label9: TLabel
Left = 848
Top = 152
Width = 6
Height = 13
Caption = '0'
end
object Label10: TLabel
Left = 904
Top = 128
Width = 47
Height = 13
Caption = 'TotalTime'
end
object Label11: TLabel
Left = 912
Top = 152
Width = 6
Height = 13
Caption = '0'
end
object Edit1: TEdit
Left = 14
Top = 28
Width = 1034
Height = 21
TabOrder = 0
end
object Edit2: TEdit
Left = 14
Top = 74
Width = 1030
Height = 21
TabOrder = 1
end
object MSButton1: tMSButton
Left = 476
Top = 361
Width = 75
Height = 25
Anchors = [akLeft, akBottom]
Caption = 'Multiply'
TabOrder = 2
DoBrowse = False
BrowseStyle = fbOpen
end
object MSMemo1: tMSMemo
Left = 14
Top = 216
Width = 1027
Height = 130
WordWrap = True
VertScrollBarStyles.ButtonSize = 16
HorzScrollBarStyles.ButtonSize = 16
Anchors = [akLeft, akTop, akBottom]
TabOrder = 3
end
object ProgressBar1: TProgressBar
Left = 128
Top = 177
Width = 785
Height = 16
TabOrder = 4
end
end
EndDialog>Dialog1

Show>Dialog1,
Exit>

SRT>Multiply
Timer>StartTime
SetDialogProperty>Dialog1,Label9,Caption,0
SetDialogProperty>Dialog1,Label7,Caption,0
SetDialogProperty>Dialog1,Label6,Caption,0
SetDialogProperty>Dialog1,Label11,Caption,0
SetDialogProperty>Dialog1,MSMemo1,Text,

GetDialogProperty>Dialog1,Edit1,Text,no1
GetDialogProperty>Dialog1,Edit2,Text,no2

GoSub>Works
Timer>EndTime
Let>ProdTime={(%EndTime%-%StartTime%)/1000}
SetDialogProperty>Dialog1,Label6,Caption,ProdTime

Timer>StartTime
Let>CycleCount=0

Let>dotpos=%CharCount%-%DecimalPlaces%
If>decimal=
Else
EndIf

Timer>EndTime
Let>SumTime={(%EndTime%-%StartTime%)/1000}
Let>TotalTime=%SumTime%+%ProdTime%

SetDialogProperty>Dialog1,Label9,Caption,SumTime
SetDialogProperty>Dialog1,Label7,Caption,CharCount
SetDialogProperty>Dialog1,Label11,Caption,TotalTime

END>Multiply

SRT>Works
Position>.,no1,1,dotpos1
If>dotpos1>0
StringReplace>no1,.,,no1
RegEx>.,No1,0,Digit_1,Digit_1_count,0
Let>decimalPlaces1={%Digit_1_Count%-%dotpos1%+1}
Else
Let>decimalplaces1=0
EndIf
Position>.,no2,1,dotpos2
If>Dotpos2>0
StringReplace>no2,.,,no2
RegEx>.,No2,0,Digit_2,Digit_2_count,0
Let>decimalPlaces2={%Digit_2_Count%-%dotpos2%+1}
Else
Let>decimalplaces2=0
EndIf

Let>DecimalPlaces=%decimalPlaces1%+%decimalPlaces2%

RegEx>.,No1,0,Digit_1,Digit_1_count,0
RegEx>.,No2,0,Digit_2,Digit_2_count,0
Let>kk1={%Digit_1_count%+1}
Let>Cycles=digit_1_count
Repeat>kk1
Sub>kk1,1
Let>PrevStr=
Let>CarryOver=0
Let>kk2={%Digit_2_count%+1}
Repeat>kk2
Sub>kk2,1
If>kk2=0
If>CarryOver<>0
EndIf
Else
Let>product=Digit_1_%kk1%*Digit_2_%kk2%
If>Product>9
RegEx>.,Product,0,Char,Char_count,0
Let>CarryOver=%Char_1%
Else
Let>CarryOver=0
EndIf
EndIf
Until>kk2=0
Let>Places={%Digit_1_count%-%kk1%}
If>Places>0
Let>kkp=0
Repeat>kkp
Let>Value=%value%0
Until>kkp=Places
EndIf
SetDialogProperty>Dialog1,ProgressBar1,Position,Progress
Until>kk1=1
Let>Progress=30
SetDialogProperty>Dialog1,ProgressBar1,Position,Progress
END>Works

Repeat>CycleCount
If>CycleCount=1
If>Cycles=1
Else
EndIf
Else
EndIf
VBEval>StrReverse("%Term_1%"),Term_1
VBEval>StrReverse("%Term_2%"),Term_2
RegEx>.,Term_1,0,Digit_1,Digit_1_count,0
RegEx>.,Term_2,0,Digit_2,Digit_2_count,0
If>{%Digit_1_Count%>=%digit_2_Count%}
Let>MaxLength=Digit_1_Count
If>{%Digit_1_Count%=%digit_2_Count%}
Else
Let>Places=%Digit_2_count%
If>Places>0
Repeat>Places
Let>Digit_2_%Places%=0
Until>Places=Digit_1_Count
EndIf
EndIf
Else
Let>MaxLength=Digit_2_Count
Let>Places=%Digit_1_count%
If>Places>0
Repeat>Places
Let>Digit_1_%Places%=0
Until>Places=Digit_2_Count
EndIf
EndIf
Let>CarryOver=0
Let>DD=0
Repeat>DD
Let>Sum_%DD%=Digit_1_%DD%+Digit_2_%DD%
Let>Sum_%DD%=Sum_%DD%+%CarryOver%
If>Sum_%DD%>9
RegEx>.,Sum_%DD%,0,Char,Char_count,0
Let>Sum_%DD%=Char_2
Let>CarryOver=Char_1
Else
Let>CarryOver=0
EndIf
Until>DD=%MaxLength%
If>CarryOver>0
Let>Sum_%DD%=CarryOver
EndIf
Let>FF=0
Repeat>FF
Let>Value=Sum_%FF%
Until>FF=DD
SetDialogProperty>Dialog1,ProgressBar1,Position,Progress
Until>CycleCount=Cycles
Let>Progress=100
SetDialogProperty>Dialog1,ProgressBar1,Position,Progress

ABIVEN
Pro Scripter
Posts: 67
Joined: Sun Aug 07, 2005 7:22 pm
Location: PARIS

### Re: Puzzler #11 MULTIPLICATION

I just discovered this post.
Some years ago I had to make out a routine for AxB ; Lot slower than hagchr !
But , in fact what I needed was mostly B(Unltd) x A(<= 14 digits)
So I did a "lite" routine [ 80 lines] five time faster than the first one

Code: Select all

``````Let>DECIMAL_SEPARATOR=.
let>MSG_HEIGHT=600
let>MSG_WIDTH=900

let>A=12345678987654
let>B=9876543212345678987654321234567898765432123456789876543212345678956789

len>A,lenA
len>B,lenB
let>B°=B
Timer>startTime
GoSub>BxA-14Digits
let>B=B°
Timer>endTime
Let>elapsed_seconds={(%endTime%-%startTime%)}
mdl>%CRLF% A = %A%              lenA= %lenA%%CRLF% B = %B%       lenB= %lenB%%CRLF% Result P°= %P°%%CRLF%     Time:  --- %elapsed_seconds% ms ---
//------------********SRT B(Unltd)*A(<= 14 Digits)********------------
SRT>BxA-14Digits
let>mlennn=15-lenA
if>{(%lenA%+%lenB%)<16}
let>P°=A*B
// If A*B compatible with Macro Scheduler (little numbers)
goto>BxA-14Digits fin
else
endif
MidStr>000000000000000,1,{(%mlennn%)},FOR1
concat>B,FOR1
len>B,newlenB
let>newlenB={(Trunc(%newlenB%/%mlennn%)*%mlennn%)}
MidStr>B,1,newlenB,B
let>lensupp=newlenB-lenB
let>newlenB={(%newlenB%/%mlennn%)}
//[1]Gives number of blocks - so gives start j
//*************------------*****
let>j=newlenB
let>FIR1=FOR1
midStr>B,{(%mlennn%*%j%-(%mlennn%-1))},mlennn,Bj
let>Pj=%Bj%*A
LEN>Pj,lenPj
concat>FIR1,Pj
let>Pj=FIR1
midStr>Pj,{(%lenPj%+1)},mlennn,Pj
let>P°=Pj
len>P°,lenP°
let>j=newlenB-1
//*************------------*****
//start j decreasing to j=2
While>j>1
let>FIR1=FOR1
midStr>B,{(%mlennn%*%j%-(%mlennn%-1))},mlennn,Bj
let>Pj=%Bj%*A
LEN>Pj,lenPj
// Works out step by step P° from start j to 2 (with perhaps some 0s added)
concat>FIR1,Pj
let>Pj=FIR1
midStr>Pj,{(%lenPj%+1)},mlennn,Pj
concat>Pj,P°
let>P°=Pj
let>j=j-1
Endwhile
//*************------------*****
// last with j=1
midStr>B,{(%mlennn%*%j%-(%mlennn%-1))},mlennn,Bj
let>Pj=%Bj%*A
LEN>Pj,lenPj
concat>Pj,P°
let>P°=Pj
len>P°,lenP°
let>lenresultat=lenP°-lensupp
MidStr>P°,1,lenresultat,P°
//[3] 0s added are now deleted
label>BxA-14Digits fin
END>BxA-14Digits
//------------********SRT B(Unltd)*A(<= 14 Digits)********------------
``````
Hagchr's routine [with A = 12345678987654] gives on my computer 90 ms
What about a hagchr similar "lite"routine ? !

Regards

Djek
Pro Scripter
Posts: 135
Joined: Sat Feb 05, 2005 11:35 pm
Location: Holland
Contact:

### Re: The Unofficial Macro Scheduler Puzzler #11

Thanks for the puzzle, JRL

i just saw it, and i do not think i can do it faster then Hagchr solution.

But i guess i could go for the most simple solution?
I know, im a bit cheating but it does supply you the answer:

Code: Select all

``````Let>num_1=12345678987654321234567898765432123456789876543212345678987654321
Let>num_2=98765432123456789876543212345678987654321234567898765432123456789
Timer>startTime
HTTPRequest>http://apfloat.appspot.com,,POST,input=%num_1%*%num_2%,result,,,,
Separate>result,#10;,answ
Separate>answ_2,%LF%,ans
Timer>endTime
Let>elapsed_seconds={(%endTime%-%startTime%)}
MessageModal>elapsed_seconds
MessageModal>ans_1
``````
and it shows how MS gives the possibilities to solve this puzzle, without having the brains of Hagchr...

kind regards,
Djek