Page 4 of 5

Re: Routines for very large numbers.

Posted: Mon Sep 07, 2015 3:31 am
by golive
istech wrote:I have been testing the routines over the last couple days and all but one appear to work as expected. The function in question is "BigDivide"

Can someone confirm that if you do.

put bigDivide(99999999,10) into t
answer t

LC stops responding or crashes. This does not happen on every calculation only on some trying to narrow it down.
Yes, you are right.
MaxV's bigDivide hangs my PC as well.

Re: Routines for very large numbers.

Posted: Tue Sep 08, 2015 1:59 pm
by MaxV
I think it's a time problem, every size differences between the two numbers increase the time exponentially.

Re: Routines for very large numbers.

Posted: Tue Sep 08, 2015 2:33 pm
by MaxV
Now I can confirm it,
the request

Code: Select all

put bigDivide(99999999,10)
Results:
9999999 , 9
Waiting just 45 minutes... :lol:

Re: Routines for very large numbers.

Posted: Wed Sep 09, 2015 9:31 am
by golive
25 minutes here
(Windows 8.1)

So not really usable, unfortunately.

Re: Routines for very large numbers.

Posted: Wed Sep 09, 2015 10:35 am
by MaxV
Well, the bigDivide() function has to be improved for efficiency.
If you have any idea, please post your code here.
I'll work on it.

Re: Routines for very large numbers.

Posted: Wed Sep 09, 2015 11:11 am
by istech

Code: Select all

breakpoint 
repeat while (bigGreater(a1,a2))
      put bigSub(a1,a2) into a1
      put bigAdd(1,count) into count
      wait 0 milliseconds with messages
   end repeat
Thanks MaxV. Addling the with 0 milliseconds stops the GUI freeze up. But the time taken to process the sum is not efficient as MaxV said. Maybe some chunking of the numbers may speed it up?

Re: Routines for very large numbers.

Posted: Wed Sep 09, 2015 1:49 pm
by MaxV
Solved, I just divided the big number in smallest pieces. Please add and subistute these functions (bigDivide and bigDivide2):

Code: Select all

function bigDivide a1,a2
   #output is a block of two numbers "quotient , remainder"
   if bigGreater(a2,a1) then
      return ("0," & a1)
   end if
   if a1 = a2 then
      return "1,0"
   end if
   put 0 into count
   repeat while (bigGreater(a1,a2))
      put bigSub(a1,a2) into a1
      put bigAdd(1,count) into count
   end repeat
   if a1 = a2 then
      put bigAdd(count,1) into count
      put 0 into a1
   end if
   return (count & comma & a1)
end bigDivide

function bigDivide2 a1,a2     
   put length(a1) into ldividendo
   put length(a2) into ldivisore   
   if ldividendo <= ldivisore then 
      return bigDivide(a1,a2)
   end if   
   put char 1 to ldivisore of a1 into tDiv
   put bigDivide(tDiv,a2) into rrr 
   put item 1 of rrr into quoziente
   put item 1 of rrr into resto
   put ldivisore + 1 into nn   
   repeat with i = nn  to ldividendo
      put char i of a1 after resto
      put bigDivide(resto,a2) into temp
      put item 1 of temp after quoziente
      put item 2 of temp into resto
   end repeat
   return (quoziente & comma & resto)
end bigDivide2
so

Code: Select all

put bigDivide2(999999999,10)
returns
99999999,9
in less than a second.
Please test bigDivide2 and let me know.

TO DO:
working with negative numbers. At the present the substract function generates only positive numbers (like an abs function). Moreover all other functions work only with positive numbers.

Re: Routines for very large numbers.

Posted: Thu Sep 10, 2015 2:54 am
by golive
MaxV wrote:Solved, I just divided the big number in smallest pieces. Please add and subistute these functions (bigDivide and bigDivide2):
Hi MaxV

Well done on the speed; now very fast.

But accuracy of result is not so good.

Example:

Code: Select all

put bigDivide2(123,111) into tNum
Calculator gives: 1.108108108108108
bigDivide2 gives: 1.12



Another example:

Code: Select all

put bigDivide2(123456789,12345678) into tNum
Calculator gives: 10.00000072900006
bigDivide2 gives: 10.19

Re: Routines for very large numbers.

Posted: Thu Sep 10, 2015 10:19 am
by MaxV
The first case is correct, but you read the result wrongly :lol:

bigDivide2(123,111) = 1,12 means 1 with remainder of 12 ( 111 * 1 + 12 = 123)

In other cases there is a bug, because it adds a "1" at the beginning of the remainder:

bigDivide2(123456789,12345678) = 10,19 means 10 with the remainder of 19

but the correct results is "10,9" , i.e. 10 with the remainder of 19; because ((10 * 12345678) + 9) = 123456789

I have to investigate further this bug in bigDivide2.

Re: Routines for very large numbers.

Posted: Thu Sep 10, 2015 10:31 am
by MaxV
Ok, I found the bug, now this should work:

########CODE#######
function bigAdd a1, a2
#let's check if it's negative...
#end check
put reverse2(a1) into b1
put reverse2(a2) into b2
put 0 into mem
if length(b1) < length(b2) then
put b1 into temp
put b2 into b1
put temp into b1
end if
repeat while b2 is not empty
put (char 1 of b1) + (char 1 of b2) + mem into ppp
if length(ppp) = 1 then
put 0 into mem
put ppp before rrr
else
put 1 into mem
put char 2 of ppp before rrr
end if
delete char 1 of b1
delete char 1 of b2
end repeat
repeat while (b1 is not empty)
put mem + (char 1 of b1) into ppp
if length(ppp) = 1 then
put 0 into mem
put ppp before rrr
else
put 1 into mem
put char 2 of ppp before rrr
end if
delete char 1 of b1
end repeat
if mem = 1 then
put 1 before rrr
else
put b1 before rrr
end if
return rrr
end bigAdd

function reverse2 temp
repeat for each char tChar in temp
put tChar before temp2
end repeat
return temp2
end reverse2


function bigMultiply a1,a2
put reverse2(a1) into a1
put 0 into temp
repeat for each char tChar in a1
repeat with i=1 to tChar
put bigAdd(temp,a2) into temp
end repeat
put 0 after a2
end repeat
return temp
end bigMultiply

function bigGreater a1,a2
#compare two bignumbers:
#return true if n1 > n2
#return false if n1 < n2
#return empty if n1 = n2
#let's check is a number is negative
if ((char 1 of a1 = "-") or (char 1 of a2 = "-")) then
if ((char 1 of a1 = "-") and (char 1 of a2 is not "-")) then
return false
end if
if ((char 1 of a1 is not "-") and ( char 1 of a2 = "-" )) then
return true
end if
#if we are here, both are negative
delete char 1 of a1
delete char 1 of a2
if a1 = a2 then
return empty
else
return (not bigGreater(a1,a2))
end if
end if
if length(a1) is not length(a2) then
return ( length(a1) > length(a2) ) #this is evalueted true or false
else
if a1 = a2 then
return empty
else
repeat while ((char 1 of a1) = (char 1 of a2) )
delete char 1 of a1
delete char 1 of a2
end repeat
return ((char 1 of a1) > (char 1 of a2)) #this is evalueted true or false
end if
end if
end bigGreater

function bigSub a1,a2
#substract the smallest big number from the largest one
if bigGreater(a2,a1) then
put a1 into temp
put a2 into a1
put temp into a2
end if
put reverse2(a1) into a1
put reverse2(a2) into a2
put 0 into mem
repeat while (a2 is not empty)
put (char 1 of a1) - mem + 10 - (char 1 of a2) into minus
if length(minus) = 1 then
put 1 into mem
put minus before rrr
else
put 0 into mem
put char 2 of minus before rrr
end if
delete char 1 of a1
delete char 1 of a2
end repeat
repeat while (a1 is not empty)
put char 1 of a1 + 10 - mem into minus
if length(minus) = 1 then
put 1 into mem
put minus before rrr
else
put 0 into mem
put char 2 of minus before rrr
end if
delete char 1 of a1
end repeat
#remove inital zeros
repeat while (char 1 of rrr is "0")
delete char 1 of rrr
end repeat
return rrr
end bigSub

function bigDivide a1,a2
#output is a block of two numbers "quotient , remainder"
if bigGreater(a2,a1) then
return ("0," & a1)
end if
if a1 = a2 then
return "1,0"
end if
put 0 into count
repeat while (bigGreater(a1,a2))
put bigSub(a1,a2) into a1
put bigAdd(1,count) into count
end repeat
if a1 = a2 then
put bigAdd(count,1) into count
put 0 into a1
end if
return (count & comma & a1)
end bigDivide

function bigDivide2 a1,a2
put length(a1) into ldividendo
put length(a2) into ldivisore
if ldividendo <= ldivisore then
return bigDivide(a1,a2)
end if
put char 1 to ldivisore of a1 into tDiv
put bigDivide(tDiv,a2) into rrr
put item 1 of rrr into quoziente
put item 2 of rrr into resto
put ldivisore + 1 into nn
repeat with i = nn to ldividendo
put char i of a1 after resto
put bigDivide(resto,a2) into temp
put item 1 of temp after quoziente
put item 2 of temp into resto
end repeat
put removezeros(quoziente) into quoziente
put removezeros(resto) into resto
return (quoziente & comma & resto)
end bigDivide2

function removezeros temp
repeat while char 1 of temp is "0"
delete char 1 of temp
end repeat
return temp
end removezeros
#####END OF CODE#####

Please let me know.

Re: Routines for very large numbers.

Posted: Fri Sep 11, 2015 5:49 am
by golive
@maxV Yes works fine, very nice! Thanks.

To display the result as a decimal number, I assume I can do something like this:

Code: Select all

on mouseUp
   put 123 into tNumerator
   put 118 into tDenominator
   put bigDivide2(tNumerator,tDenominator) into tNum
   answer tNum&cr&\
   item 1 of tNum &(item 2  of tNum)/tDenominator
end mouseUp
Actually this adds an extra zero ie item 1 of tNum &(item 2 of tNum)/tDenominator begins with "0."
Can you tell me what is the Livecode command to remove the leading zero?

Re: Routines for very large numbers.

Posted: Mon Sep 14, 2015 11:25 am
by MaxV
golive wrote:@maxV Yes works fine, very nice! Thanks.

To display the result as a decimal number, I assume I can do something like this:

Code: Select all

on mouseUp
   put 123 into tNumerator
   put 118 into tDenominator
   put bigDivide2(tNumerator,tDenominator) into tNum
   answer tNum&cr&\
   item 1 of tNum &(item 2  of tNum)/tDenominator
end mouseUp
Actually this adds an extra zero ie item 1 of tNum &(item 2 of tNum)/tDenominator begins with "0."
Can you tell me what is the Livecode command to remove the leading zero?
The function to remove leading zeros is removezeros(), however I'll avoid try to get decimal numbers that way, it isn't correct.

Re: Routines for very large numbers.

Posted: Tue Sep 15, 2015 12:42 am
by golive
MaxV wrote: The function to remove leading zeros is removezeros(), however I'll avoid try to get decimal numbers that way, it isn't correct.

removezeros() is not in the dictionary. How do you use it?

Tried this (doesn't work):

Code: Select all

put  0.123456789 into t2
put removezeros(t2)
Also you say "I'll avoid try to get decimal numbers that way, it isn't correct." Why is it not correct?
How would you get the result as a decimal number?

Re: Routines for very large numbers.

Posted: Tue Sep 15, 2015 5:35 am
by dunbarx
GoLive.

The function "removeZeros" is part of MaxV's suite of handlers. It is not a native function. Look back at his post where he lists all his functions.

Craig

Re: Routines for very large numbers.

Posted: Tue Sep 15, 2015 8:44 am
by MaxV
golive wrote:
MaxV wrote: The function to remove leading zeros is removezeros(), however I'll avoid try to get decimal numbers that way, it isn't correct.
Also you say "I'll avoid try to get decimal numbers that way, it isn't correct." Why is it not correct?
How would you get the result as a decimal number?
For example:

1 / 3 = 0.3 is not correct, it's an approximation 0.3=3/10
1 / 3 = 0.33 is not correct, it's an approximation 0.33=33/100
1 / 3 = 0.333 is not correct, it's an approximation 0.333=333/1000
1 / 3 = 0.333333333 is not correct, it's an approximation
1 / 3 = 0.3333333333333333333333333333 is not correct, it's an approximation
1 / 3 = 0.3333333333333333333333333333333333 is not correct, it's an approximation
1 / 3 = 0.3333333333333333333333333333333333333333333333333333333333 is not correct, it's an approximation
1 / 3 = 0 with remainder of 1. This is the only correct solution contemplating all digits