Realistic math solver

Quick note: You are all thinking too hard on how to evaluate the expressions. While this code doesn’t do what you want, it demonstrates an easier way to show the steps in evaluating an expression:


function setup()
    answer = 0
    parameter.text("Problem","0",function(str)
                                        output.clear()
                                        if pcall(function() evalExp(str) end) then
                                            
                                        else
                                            print("Invalid expression")
                                        end
                                    end)
    parameter.watch("answer")
end

function evalExp(str)
    assert(loadstring("answer = "..tostring(str)),0)()
end

With this code, you start by finding the first step, evaluating that, moving on to adding the second step to the string, evaluating that, etc. which it seems that many of you have managed to do some of that.
Thanks!

@SkyTheCoder Since @Prynok wants to prevent decimal numbers, here’s how I would do it using my original split routine and math.floor(). I prefer working with tables over strings. @Zoyt I’m not following your code so I’m not sure how Prynok would be able to use it for what he wants to do. I’ll keep looking at it to see if I can figure it out.


function setup()
    parameter.number("v1",0,1200,123.45,compare)
    parameter.number("v2",0,11000,345.67,compare)
end

function draw()
    background(40, 40, 50)  
end

function compare()
    output.clear()
    t1=split(math.floor(v1))
    t2=split(math.floor(v2))
    for z=1,math.max(#t1,#t2) do
        a=t1[z]
        b=t2[z]
        if a==nil then
            print(a," < ",b)
        elseif b==nil then
            print(a," > ",b)
        elseif a>b then
            print(a," > ",b)
        elseif a<b then
            print(a," < ",b)
        else
            print(a," = ",b)
        end 
    end  
end

function split(val)
    local st={}
    while val>0 do
        table.insert(st,val%10)
        val=math.floor(val/10)
    end
    return(st)
end

I absolutely LOVE that one person’s question has turned in to a code war to see who can write the better routine…

I smell a challenge coming. =)

@tomxp411 I don’t look at it as who can write the better code. It’s writing code that works based on the information that the person who started the question is giving us as they see more examples. The more examples that are given, the more choices there are to choose from and the different styles of coding for the new coders to see.

PS. I’m sure there are many LUA coders lurking here that can code circles around me.

If you want a real challenge, write functions that can do arithmetic on numbers of ANY length (without showing every step!). I’ve just written some code for this. I don’t claim it’s optimally fast, but it seems to work.

https://gist.github.com/dermotbalson/6472101

Example of use:

    a="12345678901234567890"
    b="31415918281828"
    print("a",a)
    print("b",b)
    c=bm.Add(a,b)
    print("c=a+b",c)
    d=bm.Sub(c,a)
    print("c-a",d,"=b",d==b)
    c=bm.Mult(a,b)
    print("c=a*b",c)
    d=bm.Div(c,a)
    print("c/a",d,"=b",d==b)

@Ignatz Thanks, I was looking for something like this. But when I do a divide, it doesn’t like log.print. Is the code missing something else.

PS. Does it handle decimal points.
PS. Never mind, it doesn’t handle decimal points, and I just commented out all the log.print statements.

I could easily add decimals by just continuing the division and appending “0”, but I was thinking of one of the main uses, encryption, where everything is integers

At the moment, for division, it returns the integer and remainder

And I removed all the log.print statements (included for testing only)

Looks great, I may have to see if I can get some help on one of my projects some time later.

For those who are interested, addition and subtraction is char by char, then you come back and deal with carry forwards. Biggest problem is the +/- signs.

Multiplication is by breaking the numbers into the biggest chunks that can be multiplied without exceeding Codea’s max, and that’s only 3 digits. So basically you reduce it to multiplying two numbers together in clumps of 3 digits, ie cross multiply everything, do the carries…

Division is by the manual long division approach, there are mathematical alternatives but i didn’t understand them, and I wasn’t trying to break speed records…

-- Opération sur les Grands Nombres GN

supportedOrientations(LANDSCAPE_ANY) ; displayMode(FULLSCREEN)

function setup()
    A="45896328714523695" ; A2=ENG(A) ; B="45892631745" ; B2=ENG(B)
    C=ADD(A,B) ; C2=ENG(C) ; D=MULT(A,B) ; D2=ENG(D)
    E=FACT("25") ; E2=ENG(E) ; F=FIB("50") ; F2=ENG(F)
    G=PUIS("99",9) ; G2=ENG(G)
end

function draw()
    
    background(31, 29, 146, 255) ; strokeWidth(5) ; font("AmericanTypewriter")
    fontSize(35) ; textMode(CORNER) ; fill(175, 116, 24, 255)
    text("Opération sur les Grands Nombres :",30,700)
    
    fill(226, 58, 23, 255)
    text("A =",30,600) ; text("B =",30,550)
    text(A2,100+800-textSize(A2),600) ; text(B2,100+800-textSize(B2),550)
    
    fill(255, 238, 0, 255)
    text("A+B =",30,500) ; text(C2,100+800-textSize(C2),500)
    text("A*B =",30,450) ; text(D2,100+800-textSize(D2),450)
    
    fill(55, 203, 20, 255)
    text("25! =",30,350) ; text(E2,100+800-textSize(E2),350)
    text("FIB(50) =",30,300) ; text(F2,100+800-textSize(F2),300)
    
    fill(214, 16, 208, 255)
    text("99^9 =",30,250) ; text(G2,100+800-textSize(G2),250)
    
end

function ADD(A_ADD,B_ADD)
    A_ADD_SIZE=string.len(A_ADD) ; B_ADD_SIZE=string.len(B_ADD)
    if A_ADD_SIZE<B_ADD_SIZE then TMP=A_ADD ; A_ADD=B_ADD ; B_ADD=TMP
    TMP=A_ADD_SIZE ; A_ADD_SIZE=B_ADD_SIZE ; B_ADD_SIZE=TMP end   
    retenue=0 ; result = ""
    for i=1, A_ADD_SIZE do if i<=B_ADD_SIZE then
        vala=string.sub(A_ADD,A_ADD_SIZE-i+1,A_ADD_SIZE-i+1)
        valb=string.sub(B_ADD,B_ADD_SIZE-i+1,B_ADD_SIZE-i+1) ; valc=vala+valb ; valc=valc+retenue
        else vala=string.sub(A_ADD,A_ADD_SIZE-i+1,A_ADD_SIZE-i+1) ; valc=vala+retenue end
        if valc>9 then retenue=1 ; valc=string.sub(valc,2,2) else retenue=0 end
        result = valc .. result
    end
    if retenue~=0 then result = retenue .. result end
    return result
end

function MOINS(A_MOINS,B_MOINS)
end

function MULT(A_MUL,B_MUL)
    A_MUL_SIZE=string.len(A_MUL) ; B_MUL_SIZE=string.len(B_MUL) ; total="0"
    for j=B_MUL_SIZE, 1, -1 do
        valb=string.sub(B_MUL,j,j) ; valb2=tonumber(valb) ; retenue=0 ; result="" 
        for i=1, A_MUL_SIZE do vala=string.sub(A_MUL,A_MUL_SIZE-i+1,A_MUL_SIZE-i+1)
            vala2=tonumber(vala) ; valc = valb2 * vala2 + retenue
            if valc>9 then retenue=math.floor(valc/10) ; valc=valc-retenue*10 else retenue=0 end
            result = valc .. result
        end
        if retenue~=0 then result = retenue .. result end
        result = result .. string.rep("0",B_MUL_SIZE-j) ; total=ADD(total,result)
    end
    return result
end

function DIV(A_DIV,B_DIV)
end

function PUIS(A_PUISS,N_PUISS)
    C="1"
    for i=1, N_PUISS do
        C=MULT(C,A_PUISS)
    end
    return C
end

function RACN(A_RACN,B_RACN)
end

function EXP(A_EXP,B_EXP)
end

function LOG(A_LOG,B_LOG)
end

function COMB(A_COMB,B_COMB)
end

function PERM(A_PERM,B_PERM)
end

function ALEA(A_ALEA,B_ALEA)
end

function ENG(str)
    taille=string.len(str) ; str2="" ; n=0
    for i=taille, 1, -1 do n = n + 1 ; str2 = string.sub(str,i,i) .. str2
        if math.fmod(n,3)==0 and n~=taille then str2 = "." .. str2 end
    end ; return str2
end

function IPART()
end

function FPART()
end

function FIB(N_FIB)
    A="0" ; B="1"
    for i=0, N_FIB do
        if i<2 then
            if i==0 then C="0" end
            if i==1 then C="1" end
        else
            C=ADD(A,B)
            A=B
            B=C
        end
    end
    return C
end

function FACT(A_FACT)
    vala=tonumber(A_FACT) ; result="1"
    for i=1, vala do result = MULT(result,""..i) end
    return result
end

Cool! Big numbers…

@hpsoft I like your code. I changed some code in function ENG(str). I changed the “.” to “,” which is what I’m used to for large numbers. One question, are you going to work on the empty functions, EXP(), LOG(), etc.

prynok if you want a codea’s calculator
take a look at : http://gregory.thomas.free.fr/codea/rpncalc.rar
or in the page : http://gregory.thomas.free.fr/codea for screenshots
i don’t have used bignum because it missed mult and div function
thanks to ignatz for bignum

dave1707 thanks, sorry but i stopped for a moment

-- Addition Grands Nombres GN

supportedOrientations(LANDSCAPE_ANY)
displayMode(FULLSCREEN)

function setup()
    
    A="1825586312156318"
    B="9219815399813347"
    
    ASIZE=string.len(A)
    BSIZE=string.len(B)
    
    -- Si ASIZE < BSIZE alors j'inverse
    -- Le 1 er nombre (A) a toujours le plus grand nombre de chiffres
    
    if ASIZE<BSIZE then
        TMP=A ; A=B ; B=TMP
        TMP=ASIZE ; ASIZE=BSIZE ; BSIZE=TMP
    end
    
end

function draw()
    
    background(31, 29, 146, 255) ; strokeWidth(5)
    font("AmericanTypewriter") ; fontSize(35) ; textMode(CORNER)
    
    fill(175, 116, 24, 255)
    text("Addition de Grands Nombres :",30,700)
    
    fill(220, 30, 181, 255)
    decalage=math.max(BSIZE-ASIZE,0)
    for i=1,ASIZE do text(string.sub(A,i,i),(i+decalage)*30+100,600) end
    fill(255, 63, 0, 255)
    text(ASIZE.." chiffres",800,600)
    
    fill(0, 239, 255, 255)
    text("+",50,550)
    
    fill(220, 30, 181, 255)
    decalage=math.max(ASIZE-BSIZE,0)
    for i=1,BSIZE do text(string.sub(B,i,i),(i+decalage)*30+100,550) end
    fill(255, 63, 0, 255)
    text(BSIZE.." chiffres",800,550)
    
    fill(253, 255, 0, 255) ; retenue=0
    
    result = ""
        
        for i=1, ASIZE do
            
            if i<=BSIZE then
                vala=string.sub(A,ASIZE-i+1,ASIZE-i+1)
                valb=string.sub(B,BSIZE-i+1,BSIZE-i+1)
                valc=vala+valb ; valc=valc+retenue
            else
                vala=string.sub(A,ASIZE-i+1,ASIZE-i+1)
                valc=vala+retenue
            end
            
            if valc>9 then retenue=1
                fill(108, 251, 1, 255) ; fontSize(15)
                text(string.sub(valc,1,1),(ASIZE-i)*30+100,650)
                valc=string.sub(valc,2,2)
            else retenue=0 end
            
            fill(233, 241, 11, 255) ; fontSize(35)
            text(valc,(ASIZE-i+1)*30+100,500)
            
            if i==ASIZE and retenue ~= 0 then
                fill(233, 241, 11, 255)
                text(retenue,(ASIZE-i)*30+100,500)
            end
            
            result = valc .. result
            
        end
    
    if retenue~=0 then
        result = retenue .. result
    end
    
    affiche=eng(result)
    text(affiche,100,300)
    
end

function eng(str)
    taille=string.len(str)
    str2="" ; n=0
    for i=taille, 1, -1 do
        n = n + 1
        str2 = string.sub(str,i,i) .. str2
        if math.fmod(n,3)==0 and n~=taille then
            str2 = "." .. str2
        end
    end
    return str2
end

Well, I couldn’t let this pass without trying it myself. I just did the multiply routine, but I wanted it to handle decimal points. I didn’t take the time to go thru the code to see if I could eliminate anything to make it smaller. I multiply one digit at a time instead of packing the digits for speed. It also handles a negative sign as the left most character.


displayMode(FULLSCREEN)
supportedOrientations(LANDSCAPE_ANY)

function setup()
    t1={}
    sgn=0
    dp=0
    a1="1122334455.66778899"
    b1="9988776655.44332211"
    a=strip(a1)
    b=strip(b1)
    mult()
    str=table.concat(t1)
end

function draw()
    background(40, 40, 50)
    fill(255)
    textMode(CORNER)
    textWrapWidth(WIDTH-100)
    text(a1,50,600)
    text("   X",50,560)
    text(b1,50,520)
    text("   =",50,480)
    text(str,50,440)
end

function strip(v)
    v1=""
    if string.sub(v,1,1)=="-" then
        sgn=sgn+1
        v=string.sub(v,2)
    end
    for z=1,#v do
        if string.sub(v,z,z)=="." then
            dp=dp+#v-z
            v1=string.sub(v,1,z-1)
            v1=v1..string.sub(v,z+1)
            break
        end
    end
    if v1=="" then
        v1=v
    end
    return v1
end

function mult()
    t={}
    q=0
    for z=#b,1,-1 do
        q=q+1
        s=0
        for y=#a,1,-1 do
            if t[q+s]==nil then
                t[q+s]=0
            end
            v1=string.sub(a,y,y)
            v2=string.sub(b,z,z)
            t[q+s]=t[q+s]+v1*v2
            s=s+1
        end        
    end
    c=0
    for z=1,#t do
        t[z]=t[z]+c
        c=math.floor(t[z]/10)
        t[z]=t[z]%10
    end
    if c>0 then
        table.insert(t,c)
    end
    for z=#t,1,-1 do
        table.insert(t1,t[z])
    end
    if dp>0 then
        if #t==dp-1 then
            table.insert(t1,1,"0")
            table.insert(t1,#t-(dp-2),".")
            table.insert(t1,1,0)
        else
            table.insert(t1,#t-(dp-1),".")
        end
    end
    if sgn==1 then
        table.insert(t1,1,"-")
    end
end

So now you want something to practise big numbers with

http://projecteuler.net/problem=13

@Ignatz Interesting. I have to write the add routine in my above code, then I have to read in those 100 50 digit numbers. It will have to wait until tomorrow, it’s 11PM and I’m off to bed.