Routines for very large numbers.

Got a LiveCode personal license? Are you a beginner, hobbyist or educator that's new to LiveCode? This forum is the place to go for help getting started. Welcome!

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller

istech
Posts: 211
Joined: Thu Sep 19, 2013 10:08 am

Routines for very large numbers.

Post by istech » Mon Aug 24, 2015 9:31 am

Hi all,

I have a test project that needs to calculate very large numbers (30-50 digit plus). I have been running into problems with the accuracy of LC manipulating these numbers as they do not come out correctly

calculated.

After much research I found out from a few posts LC's built in function does not work correctly over 15 digits and would need to use custom functions to get the accuracy I need. Below is one of the functions I have

found. I need to now create the divide-subtract and add routines. Can any one give me some pointers or pseudocode to play with many thanks.




function bigTimesN7 X,Y
if char 1 of X is "-" then
put "-" into leadChar
delete char 1 of X
end if
if char 1 of Y is "-" then
if leadChar is "-" then
put empty into leadChar else put "-" into leadChar
delete char 1 of Y
end if
put (6 + length(X)) div 7 * 7 into XL
put char 1 to XL - length(X) of "000000" before X
put (6 + length(Y)) div 7 * 7 into YL
put char 1 to YL - length(y) of "000000" before y
repeat with N = XL + YL down to 15 step -7
repeat with M = max(7,N - YL) to min(XL,N - 7) step 7
add (char M - 6 to M of X) * (char N - M - 6 to N - M of Y) to S
if S > 900000019999997 then
add char -20 to -8 of S to Scarry
delete char -20 to -8 of S
end if
end repeat
put char -7 to -1 of ("0000000" & S) before R
add char -20 to -8 of S to Scarry
put char -7 to -1 of Scarry into S
delete char -7 to -1 of Scarry
end repeat
put Scarry & S before R
repeat with i = 1 to 15
if char i of R is not "0" then exit repeat
end repeat
if i > 1 then delete char 1 to i - 1 of R
return leadChar & R
end bigTimesN7

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10305
Joined: Wed May 06, 2009 2:28 pm

Re: Routines for very large numbers.

Post by dunbarx » Mon Aug 24, 2015 1:57 pm

Hi.

I found this from an old Hypercard function I wrote decades ago:

Code: Select all

function longAdd arg1,arg2
   put 0 into carry
   put abs(the length of arg1-the length of arg2) into numzeros
   repeat numzeros
      put "0" after leadingZeros
   end repeat
   
   if the length of arg1 >= the length of arg2 then
      put the length of arg1 into index
      put leadingZeros before arg2
   else
      put the length of arg2 into index
      put leadingZeros before arg1
   end if
   repeat with y = index down to 1
      put char y of arg1 + char y of arg2 + carry into temp
      if char y of arg1 + char y of arg2 + carry > 9 then put 1 into carry else put 0 into carry
      put last char of temp before accum
   end repeat
   if carry = 1 then put "1" before accum
   return accum
end longAdd
I wrote one for multiplication as well. I will see if I can find it.

Craig Newman

istech
Posts: 211
Joined: Thu Sep 19, 2013 10:08 am

Re: Routines for very large numbers.

Post by istech » Mon Aug 24, 2015 7:21 pm

Thanks Craig, much appreciated.

golive
Posts: 98
Joined: Wed Jul 01, 2015 5:16 am

Re: Routines for very large numbers.

Post by golive » Tue Aug 25, 2015 1:14 am

I wasn't aware of this.

I work with numbers that have:

Code: Select all

a) 18 digits (includes 2 decimal points) eg: 123456789012345.12
b) 19 digits (includes 6 decimal points) eg: 123456789012.123456
Do I need to use your special routines to manipulate these mathematically?

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10043
Joined: Sat Apr 08, 2006 7:05 am
Contact:

Re: Routines for very large numbers.

Post by FourthWorld » Tue Aug 25, 2015 2:01 am

Interesting - try this and let me know what you get:

Code: Select all

on mouseUp
   put 123456789012345.12 into t1
   put 123456789012345.12 into t2
   put t1 + t2  into t3
   put t3 &cr& t3 / 2
end mouseUp
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10305
Joined: Wed May 06, 2009 2:28 pm

Re: Routines for very large numbers.

Post by dunbarx » Tue Aug 25, 2015 2:39 am

Do I need to use your special routines to manipulate these mathematically?
I made this handler for something lost long ago in antiquity. But it should not be hard to make it work with decimals.

Either the routine itslef can be modified to incorporate them directly, or, if I had to do it quickly, I would add the decimal portions first, keep any remaining decimal aside, and add 1 to one of the original arguments (no two decimals will ever reach "2") if a carry was created. Adding to that argument may take just a little thought, since you probably cannot add directly, but must add to the last digit or two until no further carry is engendered.

Or better, you to do a "longAdd" on the integer portion of one argument and a "1" (if a carry is needed), and then do a longAdd on the sum with the other argument, and then append the decimal from step one.

Craig

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10305
Joined: Wed May 06, 2009 2:28 pm

Re: Routines for very large numbers.

Post by dunbarx » Tue Aug 25, 2015 2:55 am

I just reread your question.

If you are dealing with 19 digit number, you will lose precision in about the 17th digit. It is a limitation of the engine.

Craig

golive
Posts: 98
Joined: Wed Jul 01, 2015 5:16 am

Re: Routines for very large numbers.

Post by golive » Tue Aug 25, 2015 4:27 am

FourthWorld wrote:Interesting - try this and let me know what you get:

Code: Select all

on mouseUp
   put 123456789012345.12 into t1
   put 123456789012345.12 into t2
   put t1 + t2  into t3
   put t3 &cr& t3 / 2
end mouseUp
I get the correct answer: 123456789012345.12

Also this gives the correct answer:

Code: Select all

   on mouseUp
       put 123456789012345.12 into t1
       put 123456789012345.12 into t2
       put 1000*t1 + t2  into t3
       put t3 &cr& (t3-t2) / 1000
end mouseUp
Also correct:

Code: Select all

   on mouseUp
       put 123456789012345.12 into t1
       put 123456789012345.12 into t2
       put t1*t2  into t3
       put t3 &cr& sqrt(t3)
end mouseUp

But this gives the wrong answer: 123456789012344.91

Code: Select all

on mouseUp
   put 123456789012345.12 into t1
   put 123456789012345.12 into t2
   put t1^12  + t2  into t3
   put (t3-t2)^(1/12) 
end mouseUp
Above is to the power of 12. To the power of 2 works, but to the power 3 (code below) also gives the same wrong answer: 123456789012344.91

Code: Select all

on mouseUp
   put 123456789012345.12 into t1
   put 123456789012345.12 into t2
   --   put t1^12  + t2  into t3
   --   put (t3-t2)^(1/12)
   put t1^3  + t2  into t3
   put (t3-t2)^(1/3)
end mouseUp
What to conclude from this? Livecode bug?
Last edited by golive on Tue Aug 25, 2015 8:29 am, edited 4 times in total.

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10305
Joined: Wed May 06, 2009 2:28 pm

Re: Routines for very large numbers.

Post by dunbarx » Tue Aug 25, 2015 4:35 am

I found the multiplication routine. It is only good to about 30 digits, and uses the "longAdd" handler. I have forgotten why it will not go farther, since there is no limit to longAdd, and I have not looked at it in a long time. You need a field "display":

Code: Select all

on mouseup
   ask "First Number?"
   if it is an integer then put it into arg1 else exit mouseup
   
   ask "Second Number?"
   if it is an integer then put it into arg2 else exit mouseup
   
   put the number of chars of arg1 into index
   repeat with y = the number of chars of arg1 down to 1
      put char y of arg2 *  arg1 & addZero(index - y) & return after temp
   end repeat
   
   repeat with y = 1 to the number of lines of temp - 1
      put longAdd(line y of temp,line y + 1 of temp) into line y + 1 of temp
   end repeat

   put last line of temp into fld "display"
end mouseup

function addZero var
   repeat var
      put 0 after zeros
   end repeat
   return zeros
end addZero

golive
Posts: 98
Joined: Wed Jul 01, 2015 5:16 am

Re: Routines for very large numbers.

Post by golive » Tue Aug 25, 2015 8:33 am

I used Edit to add some more examples to my post above.
See the power of 3 example. :cry:

hpsh
Posts: 52
Joined: Tue Aug 25, 2015 8:06 pm

Re: Routines for very large numbers.

Post by hpsh » Tue Aug 25, 2015 8:20 pm

hi, just wonder about the code to dunbarx, hope i don't mispell that username.

can the problem be that you are still using int somewhere in the multiply code?

if so, maybe it can be usefull to try some african math

can not use links because its my first post :-( but did find this

"Multiplication
Shortcuts were needed, and multiplication is a shortcut for addition, just as
addition is a shortcut for counting. With the Egyptian method, this principle is easy
to understand. In fact, tables were not needed in Egyptian multiplication. To
illustrate: “13 hekats of grain are taken 27 times. How many in all?”32
Although the problem was stated in concrete terms, as hekats of grain, the
numbers were thought of abstractly. The commutative law was used because it
was easier to multiply by 13 than by 27.
Start with one 27 and then continue to double, which can be done simply by
adding the number to itself.
1 27
2 54
4 108
8 216
At this point the scribe would stop because the next step would give 16, and only
13 of the 27's were wanted. Now the partial products are added to get 13 x 27.
\ 1 27 / 1 27
2 54 4 108
\ 4 108 / 8 216
\ 8 216 /

TOTAL 13 351 "

hope it makes some sense, english is not my native language, and i am pretty useless even in that :-)

has some code to start with

Code: Select all

on mouseUp
   global myDouble
   local myNumb
   /*
   need 3 field
   field "data" is a scrollling field
   field t1 and t2 is the factors to multiply
   */
   put empty into field "data"
   put 1 into myDouble
   repeat until myDouble > field "t2"
      if the number of lines of field "data" = 0 then
         put field "t1" into myNumb
           put myDouble & " " & myNumb & cr after field "data"
         put longAdd(myNumb,myNumb) into  myNumb
      else
          put longAdd(myNumb,myNumb) into myNumb
         
         put myDouble  & " " & myNumb & cr after  field "data"
        
      end if
      
      put longAdd(myDouble, myDouble) into myDouble
      
   end repeat
   
    
     
end mouseup

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10305
Joined: Wed May 06, 2009 2:28 pm

Re: Routines for very large numbers.

Post by dunbarx » Tue Aug 25, 2015 10:13 pm

hpsh.

I could not get your handler to work. For example, if I try to multiply 10 * 50, this is what appears in the field "data":

Code: Select all

1 10
2 40
4 80
8 160
16 320
32 640
You do know that you do not need to declare any of the variables, right?

Anyway, I am sure that the problem is just what you say, an internal collision within LC (this was from Hypercard, you know. I just ported it over, basically unchanged, though HC had similar constraints). I tried to get around that by creating a series of sums, since the methodology of the "longAdd" routine has no length limit (I think).

So it is possible that I did not write "longMult" as well as I planned, and somewhere at the bottom of the list of arguments the procedure "crashes". I guess I will have to find out where that happens. Though I must say you sound like the perfect person to try your hand at that task as well.

Craig

hpsh
Posts: 52
Joined: Tue Aug 25, 2015 8:06 pm

Re: Routines for very large numbers.

Post by hpsh » Wed Aug 26, 2015 2:50 am

you got the series:

1 10
2 40
4 80
8 160
16 320
32 640

strange,yes has done something wrong then i tryed to clean up the code

it should have been
1 10
2 20
4 40
8 80


16 160
32 320

if my head is working ok this early in the morning

the next problem would be to find the line

32 320
16 160
2 20

and add togheter 320 + 160 + 20

oh think i see the error, try this

Code: Select all

on mouseUp
   global myDouble
   local myNumb
   /*
   need 3 field
   field "data" is a scrollling field
   field t1 and t2 is the factors to multiply
   */
   put empty into field "data"
   put 1 into myDouble
   repeat until myDouble > field "t2"
      if the number of lines of field "data" = 0 then
         put field "t1" into myNumb
           put myDouble & " " & myNumb & cr after field "data"
         --put longAdd(myNumb,myNumb) into  myNumb
      else
          put longAdd(myNumb,myNumb) into myNumb
         
         put myDouble  & " " & myNumb & cr after  field "data"
        
      end if
      
      put longAdd(myDouble, myDouble) into myDouble
      
   end repeat
   
    
     
end mouseup

hpsh
Posts: 52
Joined: Tue Aug 25, 2015 8:06 pm

Re: Routines for very large numbers.

Post by hpsh » Wed Aug 26, 2015 5:51 am

ok, have worked with the code, but are getting the same problem with to large number :-( not sure what is wrong, maybe something happens then the numbers are being compared?

anyway if anyone want to check my code

Code: Select all

on mouseUp
   global myDouble
   local myNumb, dSum, sSum,fSum,gSum
   /*
   need 5 field
   field "data" is a scrollling field
   field "data2" is a scrollling field
   
   field t1 and t2 is the factors to multiply
   field display is for the answer
   */
   put empty into field "data"
   put empty into dSum
   put empty into sSum
   put empty into fSum
   put 1 into myDouble
   put 0 into sSum
   repeat until myDouble > field "t2"
      if the number of lines of field "data" = 0 then
         put field "t1" into myNumb
         put myDouble & " " & myNumb & cr before field "data"
         --put longAdd(myNumb,myNumb) into  myNumb
      else
         put longAdd(myNumb,myNumb) into myNumb
         
         put myDouble  & " " & myNumb & cr before  field "data"
         
      end if
      
      put longAdd(myDouble, myDouble) into myDouble
      
   end repeat
   put empty into field "data2"
   repeat for each line tLine in field "data"
      put word 1 of tLine into dSum
      put longAdd(sSum,dSum) into gSum
      if gSum <= field "t2" then
         put gSum into sSum
         put longAdd(fSum,word 2 of tLine) into fSum
         put tLine & cr after field "data2"
      
         end if
      end repeat
   
   put fSum into field "display"
   
    
     
end mouseup

golive
Posts: 98
Joined: Wed Jul 01, 2015 5:16 am

Re: Routines for very large numbers.

Post by golive » Wed Aug 26, 2015 7:23 am

This gives the wrong number:

Code: Select all

on mouseUp
   put 1234567890 into t1
   put (t1^3)^(1/3)
 end mouseUp
Should be: 1234567890
Answer is: 1234567889.999999

The precision in Livecode appears to be weak. Not good when financial calculations are to be done.

I filed a bug report: http://quality.runrev.com/show_bug.cgi?id=15775

Post Reply