Jump to content


- - - - -

Using strings for math functions


17 replies to this topic

#1 paul0n0n

    Member

  • Members
  • PipPip
  • 37 posts

Posted 22 August 2009 - 04:50 PM

need some help optimizing my code. When I took this on I had no idea how hard simple math is. It is mostly complete, with the exception of dividing decimals, i think it's done. I'm just wondering if there is a cleaner easier way to produce the same outcome, it needs to be faster.


;Main String math functions
Function L_DIVIDE$(a$,b$,length); partial functionality (dividing decimals does not work for now, everything else does)
	negTrigger = 0:trig = 0
	If Left$(a$,1) = "-" And Left$(b$,1) = "-" Then a$ = Right$(a$,Len(a$)-1):b$ = Right$(b$,Len(b$)-1)
	If Left$(a$,1) = "-" Then negTrigger = 1:a$ = Right$(a$,Len(a$)-1)
	If Left$(b$,1) = "-" Then negtrigger = 1:b$ = Right$(b$,Len(b$)-1)	

	RightSideDecimalCountOfa = rsdc(a$)
	RightSideDecimalCountOfb = rsdc(b$)
	LeftSideDecimalCountOfa = lsdc(a$)
	LeftSideDecimalCountOfb = lsdc(b$)
	If longGT(a$,b$) = True Then trig = 1
	trigger = 0
	If RightSideDecimalCountOfb <> 0 Then 
		a$ = removeDecimal$(a$,RightSideDecimalCountOfa)
		talc = Len(a$)
		a$ = replaceDecimal$(a$,RightSideDecimalCountOfa,RightSideDecimalCountOfb)
		b$ = removeDecimal$(b$,RightSideDecimalCountOfb)
		If talc > Len(a$) Then cdph = talc - Len(a$)
		If talc < Len(a$) Then cdph = Len(a$) - talc-1
	EndIf
	If trig = 1 Then cdph = 0
	RightSideDecimalCountOfa = rsdc(a$)
	RightSideDecimalCountOfb = rsdc(b$)
	LeftSideDecimalCountOfa = lsdc(a$)
	LeftSideDecimalCountOfb = lsdc(b$)
	z = 1
	While RightSideDecimalCountOfa <> 0 And Left$(a$,1) <> "." And z <> Len(a$)
		If Left$(a$,1) = "0" Then a$ = Right$(a$,Len(a$)-1)
		z = z + 1
	Wend
	For z = 1 To RightSideDecimalCountOfa
		b$ = b$ + "0"
	Next
	a$ = removeDecimal$(a$,RightSideDecimalCountOfa)
	;a$ = removeDecimal$(a$,RightSideDecimalCountOfa)
	;b$ = removeDecimal$(b$,RightSideDecimalCountOfb)
	While Left$(a$,1) = "0"
		a$ = Right$(a$,Len(a$)-1)
		zerroCount = ZerroCount + 1
	Wend
	If a$ = b$ Return 1:trigger = 0
	For z = 1 To length
		If a$ = 0 Then Return p$
		If a$ = "" Then Return p$
		tc=1
		While longGT(b$,a$) = True
			a$ = L_MULTIPLY$(a$,10)
			If trigger = 0 Then 
				p$ = p$ + "0" + ".":trigger = 1
				For zzz = 1 To cdph
					p$ = p$ + "0"
				Next
			Else 
				p$ = p$ + "0"
			EndIf
		Wend
		c = 0
		d$ = ""
		While longGT(d$,a$)= False
			c = c + 1
			d$ = L_MULTIPLY$(b$,c)
			If longGT(d$,a$) = True Then c = tc:Goto skip
			tc = c
		Wend
		c = 1
		.skip
		d$ = L_MULTIPLY$(b$,c)
		a$ = L_SUB$(a$,d$)
		If trigger = 1 Then p$ = p$ + c
		If trigger = 0 Then
			If trig = 1 Then p$ = p$ + c
			p$ = p$ + ".":trigger = 1
			For zzz = 1 To cdph
				p$ = p$ + "0"
			Next
			If trig = 0 Then p$ = p$ + c
		EndIf
		If Len(p$) >= length Then Goto skip2
		a$ = L_MULTIPLY$(a$,10)
	Next
	.skip2
	If negTrigger = 1 Then p$ = "-"+p$
	Return p$

End Function
Function L_ADD$(a$,b$)	;fully functional      [Long Addition]
	negtrigger = 0
	;If Left$(a$,1) = "0" Then Return b$
	If Left$(a$,1) = "-" And Left$(b$,1) <> "-" Then 
		If longGT(Right$(a$,Len(a$)-1),b$) = True Then p$ = L_SUB(Right$(a$,Len(a$)-1),b$):Return "-"+p$
		Return L_SUB(b$,Right$(a$,Len(a$)-1))
	EndIf
	If Left$(b$,1) = "-" And Left$(a$,1) <> "-" Then 
		If longGT(Right$(b$,Len(b$)-1),a$) = True Then p$=L_SUB(Right$(b$,Len(b$)-1),a$):Return "-"+p$
		Return L_SUB(a$,Right$(b$,Len(b$)-1))
	EndIf
	If Left(b$,1) = "-" And Left(a$,1) = "-" Then negtrigger = 1
	da = testDecimal(a$,1):db = testDecimal(b$,1)
	If da > db Then larm = da-db:lar = da
	If db > da Then larm = db-da:lar = db
	If db < da Then b$ = addPlaceHolders$(b$,larm)
	If da < db Then a$ = addPlaceHolders$(a$,larm)
	a$ = removeDecimal(a$,lar):b$ = removeDecimal(b$,lar)
	If Left$(a$,1) = "-" Then a$ = Right$(a$,Len(a$)-1)
	If Left$(b$,1) = "-" Then b$ = Right$(b$,Len(b$)-1)
	a1 = Len(a$):b1 = Len(b$)
	If a1 > b1 Then largest = a1
	If b1 > a1 Then largest = b1
	If a1 = b1 Then largest = a1
	For z = 0 To largest
		If z <= a1-1 Then
			n1 = Mid$(a$,a1-z,1)
		Else
			n1 = 0
		EndIf
		If z <= b1-1 Then
			n2 = Mid$(b$,b1-z,1)
		Else
			n2=0
		EndIf
		n3 = n1+n2+remander
		t$ = n3
		p$ = Right$(t$,1)+p$
		t1 = Len(t$)
		If t1-1 > 0 Then
			t$ = Left$(t$,t1-1)
		Else
			t$ = ""
		EndIf
		remander = t$
	Next
	If Left$(p$,1) = "0" Then p$ = Right$(p$,Len(p$)-1)
	If da<>0 Or db <>0 Then	p$ = addDecimal$(p$,lar)
	If negtrigger = 1 Then p$ = "-"+p$
	Return p$ 
End Function
Function L_SUB$(a$,b$)	;fully functional    [ Long Subtraction ]
	negtrigger = 0
	If longLT(a$,b$) = True And Left$(a$,1) <> "-" And Left$(b$,1) <> "-" Then negtrigger = 1:tb$=b$:b$=a$:a$=tb$
;	If Len(a$)<Len(b$) Then tb$=b$:b$=a$:a$=tb$
	If Left$(a$,1) = "-" And Left$(b$,1) = "-" And longGT(a$,b$) = True Then Return L_ADD(a$,b$)
	If Left$(a$,1) = "-" And Left$(b$,1) <> "-" Then 
		If longGT(Right$(a$,Len(a$)-1),b$) = True Then Return L_ADD$(Right$(a$,Len(a$)-1),b$)
	EndIf
	If Left$(b$,1) = "-" And Left$(a$,1) <> "-" Then 
		If longGT(Right$(b$,Len(b$)-1),a$) = True Then Return L_ADD$(Right$(b$,Len(b$)-1),a$)
	EndIf
	da = testDecimal(a$,1):db = testDecimal(b$,1)
	If da > db Then larm = da-db:lar = da
	If db > da Then larm = db-da:lar = db
	If db < da Then b$ = addPlaceHolders$(b$,larm)
	If da < db Then a$ = addPlaceHolders$(a$,larm)
	a$ = removeDecimal(a$,lar):b$ = removeDecimal(b$,lar)
	If Left$(a$,1) = "-" Then a$ = Right$(a$,Len(a$)-1)
	If Left$(b$,1) = "-" Then b$ = Right$(b$,Len(b$)-1)
	a1 = Len(a$):b1 = Len(b$)
	If a1 > b1 Then largest = a1
	If b1 > a1 Then largest = b1
	If a1 = b1 Then largest = a1
	For z = 0 To largest-1
		If z <= a1-1 Then
			n1 = Mid$(a$,a1-z,1)	
		Else
			n1 = 0
		EndIf
		If z <= b1-1 Then
			n2 = Mid$(b$,b1-z,1)
		Else
			n2=0
		EndIf
		n3 = (n1-remander)-n2
		If n3 < 0 Then 
			n3 = 10 + n3:remander =1
		Else remander = 0 :EndIf
		t$=n3:p$ = Right$(t$,1)+p$
	Next
	If Left$(p$,1) = "0" Then p$ = Right$(p$,Len(p$)-1)
	If da<>0 Or db <>0 Then	p$ = addDecimal$(p$,lar)
	If negtrigger = 1 Then p$ = "-"+p$
	Return p$
End Function
Function L_MULTIPLY$(a$,b$) ; fully functional (negative, decimal, positive, and all combinations)  [ Long Multiply ]
	negTrigger = 0
	If Left$(a$,1) = "-" And Left$(b$,1) = "-" Then a$ = Right$(a$,Len(a$)-1):b$ = Right$(b$,Len(b$)-1)
	If Left$(a$,1) = "-" Then negTrigger = 1:a$ = Right$(a$,Len(a$)-1)
	If Left$(b$,1) = "-" Then negtrigger = 1:b$ = Right$(b$,Len(b$)-1)
	da = testDecimal(a$,1) :If da <> 0 Then a$ = removeDecimal$(a$,da)
	db = testDecimal(b$,1) :If db <> 0 Then b$ = removeDecimal$(b$,db)
	dec = da+db
	For z = 0 To Len(b$)-1
		n2 = Mid$(b$,Len(b$)-z,1)
		For y = 0 To Len(a$)-1
			n1 = Mid$(a$,Len(a$)-y,1)	
			n3 = n1*n2: f$ = n3
			For e = 1 To y
				f$ = f$ + "0"
			Next
			t$ = L_ADD$(t$,f$):f$ = ""
		Next
		For e = 1 To z
			t$ = t$ + "0"
		Next
		p$ = L_ADD$(t$,p$):t$ = ""
	Next
	If Left$(p$,1) = "0" Then p$ = Right$(p$,Len(p$)-1)
	If dec <> 0 Then p$ = addDecimal$(p$,dec)
	If negTrigger = 1 Then p$ = "-"+p$
	Return p$
End Function
Function longGT(a$,b$);complete  [ Long greater than ]
	If testDecimal(a$,0) = False And testDecimal(b$,0) = False Then 
		a$ = makeEL$(a$,b$)
    	b$ = makeEL$(b$,a$)
	EndIf
	If A$ > b$ Return True
	Return False
End Function
Function longLT(a$,b$);complete   [ Long less than ]
	If testDecimal(a$,0) = False And testDecimal(b$,0) = False Then 
		a$ = makeEL$(a$,b$)
    	b$ = makeEL$(b$,a$)
	EndIf
	If A$ < b$ Return True
	Return False
End Function
Function longSin$(a$,b$)   ; [ Long sine ]
	lp$ =LongPower$(a$,3)
	lf$= longFactor(3)
	Stop
	lD$ = L_DIVIDE$(lp$,lf$,10)
	b$ = L_SUB$(a$,lD$)
	tt$ = L_ADD$(L_MULTIPLY$(b$,2),1)
	c = 0
	m$ = 3
	.loop2:	m$ = L_ADD(m$,2)
		If c = 1 Then
			lp$ =LongPower$(a$,m$)
			lf$= longFactor(m$)
			lD$ = L_DIVIDE$(lp$,lf$,10)
			b$ = L_SUB$(a$,lD$)
			c = 2
			;b$ = L_SUB$(b$,longDiv$(LongPower$(b$,3),longFactor$(m$),10)):c = 2
		EndIf
		If c = 0 Then
			lp$ =LongPower$(a$,m$)
			lf$= longFactor(m$)
			lD$ = L_DIVIDE$(lp$,lf$,10)
			b$ = L_ADD$(a$,lD$)
			c = 1
			;b$ = L_ADD$(b$,longDiv$(LongPower$(b$,3),longFactor$(m$),10)):c = 1
		EndIf
		If c = 2 Then c = 1
	If m$<=tt$ Then Goto loop2
	Return b$
End Function
Function LongPower$(a$,b)
	ta$ = a$
	For z = 1 To b-1
		a$ = L_MULTIPLY$(a$,ta$)
	Next
	Return a$
End Function
Function longFactor$(a$)
	ta$ = a$: x$ = "1"
	.loop:m$ = L_ADD$(m$,1)
		x$ = L_MULTIPLY$(x$,m$)
	If m$ <> a$ Then Goto loop
	Return x$
End Function

;Helper functions 
Function makeEL$(x$,y$) ;complete
	a1 = Len(x$):b1 = Len(y$)
	If a1 > b1 Or a1 = b1 Return x$
	For z = 1 To b1-a1
		x$ = "0"+x$
	Next
	Return x$
End Function
Function testDecimal(a$,x);complete
	f = Len(a$)
	Select True
		Case x = 0
			For z = 1 To f
				If Mid$(a$,z,1) = "." Then Return True
			Next
			Return False
		Case x = 1
			For z = 0 To f-1
				If Mid$(a$,f-z,1) = "." Then Return z
			Next
		Case x = 2
			For z = 1 To f
				If Mid$(a$,z,1) = "." Then Return z
			Next
	End Select
	Return 0
End Function
Function removeDecimal$(a$,b) ;complete
	If b = 0 Then Return a$
	a$ = Left$(a$,Len(a$)-(b+1)) + Right$(a$,b)
	Return a$
End Function
Function addDecimal$(a$,b) ;complete
	While Len(a$) < b
		a$ = "0" + a$
	Wend
	a$ = Left$(a$,Len(a$)-b)+ "." + Right$(a$,b)
	Return a$
End Function
Function addPlaceHolders$(numToChange$,decimalsToAdd)
	For z = 1to decimalsToAdd
		numToChange$ = numToChange$ + "0"
	Next
	Return numToChange$
End Function
Function CountDecimalPlaceHolder(a$)
	trigger = 0
	For z = 1 To Len(a$)
		If Mid$(a$,z,1) = "." Then trigger = 1: z = z + 1
		If trigger = 1 And Mid$(a$,z,1) = "0" Then count = count + 1
		If trigger = 1 And Mid$(a$,z,1) <> "0" Then Return count
	Next
	Return count
End Function
Function additionalPlaceHolders(a$,b$)
	z = 1
	While longGT(b$,Left$(a$,z))=True And b$ <> Left$(a$,z)
		count = count + 1
		z = z + 1
		If z = Len(a$) Then Return 0
	Wend
	Return count
End Function
Function CleanLDecimal$(a$)
	While Left$(a$,1) <> "."
		a$ = Right$(a$,Len(a$) -1)
	Wend
	Return a$
End Function
Function RSDC(A$)
	For PLACE = 1 To Len(A$)
		If Mid$(A$,Len(A$)-(PLACE-1),1)= "." Then Return PLACE
	Next
	Return 0
End Function
Function LSDC(A$)
	For PLACE = 1 To Len(A$)
		If Mid$(A$,PLACE,1) = "." Then Return PLACE
	Next
	Return 0
End Function
Function REPLACEDECIMAL$(NUM$,LS,RS)
	TEMP$ = Mid$(NUM$,1,LS) + "." + Mid$(NUM$,LS,RS)
	Return TEMP$
End Function


#2 SyntaxError

    Valued Member

  • Members
  • PipPipPip
  • 139 posts

Posted 23 August 2009 - 05:35 PM

Before going though your code, may I ask what the ultimate goal you are trying to achieve is? Are you trying to support numbers with high or unlimited precision and range? Do you want to support end user expression capability? Or are you trying to achieve something else entirely?

#3 z80

    Valued Member

  • Members
  • PipPipPip
  • 104 posts

Posted 23 August 2009 - 07:48 PM

VB is bad for fast low level functions. Perhaps it would be better to write the code in C or assembler and put it in a DLL. Then you can use that DLL with VB (assuming you really need VB).

#4 paul0n0n

    Member

  • Members
  • PipPip
  • 37 posts

Posted 23 August 2009 - 08:23 PM

SyntaxError - high to unlimited precision.

z80 - That is a good idea, wonder if c# would be just as good as c

#5 starstutter

    Senior Member

  • Members
  • PipPipPipPip
  • 1039 posts

Posted 23 August 2009 - 11:15 PM

paul0n0n said:

z80 - That is a good idea, wonder if c# would be just as good as c
If I'm not mistaken, C# is a very heavyweight language, making it a poor choice for low level functions where you need raw speed. Again though, this is just what I've heard about it.
(\__/)
(='.'=)
This is Bunny. Copy and paste bunny into
(")_(") your signature to help him gain world domination.
bunny also wants to fight spam: Click Here Bots!

#6 paul0n0n

    Member

  • Members
  • PipPip
  • 37 posts

Posted 24 August 2009 - 02:48 AM

Well, I'm not sure if I used c# correctly. but there are no syntax errors, so I'm pretty sure it will work. Here is the c# code. I'm sure I missed some things like correct conversion of strings to integers and the reverse. But if some one could test to see accuracy and maybe help improve, that would be awesome. thanks. should be easy to port to c with this, I'm not very good at c and I'm just starting in c#. If the below code works that is a plus. I'm not sure how to test a dll in c#... still a noob at it.


using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;


namespace StringMathLibrary

{

    public class StringMathClass

    {

        public static string L_DIVIDE(string a, string b,int length)

        {

            int negTrigger = 0;

            int trig = 0;

            if (Left(a,1)== "-" && Left(b,1) == "-") 

            {

                a = Right(a, Len(a) - 1);

                b = Right(b, Len(b) - 1);

            }

            if (Left(a, 1) == "-")

            {

                negTrigger = 1;

                a = Right(a, Len(a) - 1);

            }

            if (Left(b, 1) == "-")

            {

                negTrigger = 1;

                b = Right(b, Len(b) - 1);

            }

            int RightSideDecimalCountOfa = rsdc(a);

            int RightSideDecimalCountOfb = rsdc(b);

            int LeftSideDecimalCountOfa = lsdc(a);

            int LeftSideDecimalCountOfb = lsdc(b);

            if (longGT(a, b) == true)

            {

                trig = 1;

            }

            int trigger = 0;

            int cdph = 0;

            if (RightSideDecimalCountOfb != 0)

            {

                a = removeDecimal(a, RightSideDecimalCountOfa);

                int talc = Len(a);

                a = replaceDecimal(a, RightSideDecimalCountOfa, RightSideDecimalCountOfb);

                b = removeDecimal(b, RightSideDecimalCountOfb);

                if (talc > Len(a)){cdph = talc - Len(a);}

                if (talc < Len(a)){cdph = Len(a) - talc - 1;}

            }

            if (trig == 1) { cdph = 0; }

            RightSideDecimalCountOfa = rsdc(a);

            RightSideDecimalCountOfb = rsdc(b);

            LeftSideDecimalCountOfa = lsdc(a);

            LeftSideDecimalCountOfb = lsdc(b);

            int z = 1;

            while (RightSideDecimalCountOfa != 0 && Left(a, 1) != "." && z != Len(a))

            {

                if (Left(a, 1) == "0") { a = Right(a, Len(a) - 1); }

                z++;

            }

            for (int i = 1; 1 <= RightSideDecimalCountOfa; i++) { b = b + "0"; }

            a = removeDecimal(a, RightSideDecimalCountOfa);

            int zerroCount = 0;

            while (Left(a, 1) == "0")

            {

                a = Right(a, Len(a) - 1);

                zerroCount++;

            }

            if (a == b) { return "1"; }

            string p = "";

            int tc;

            int c;

            string d;

            bool exit = false;

            for (int i = 1; i <= length; i++)

            {

                while (Left(a, 1) == "0") { a = Right(a, Len(a) - 1); }

                if (a == "") { return p; }

                tc = 1;

                while (longGT(b, a) == true)

                {

                    a = L_MULTIPLY(a,"10");

                    if (trigger == 0)

                    {

                        p = p + "0" + ".";

                        trigger = 1;

                        for (int iz = 1; iz <= cdph; iz++) { p = p + "0"; }

                    }

                    else { p = p + "0"; }

                }

                c = 0;

                d = "";

                exit = false;

                while (longGT(d, a) == false && exit == false)

                {

                    c++;

                    d = L_MULTIPLY(b, Convert.ToString(c));

                    if (longGT(d, a) == true)

                    {

                        c = tc;

                        exit = true;

                    }

                    if (exit == false) { tc = c; }

                }

                if (exit == false) { c = 1; }

                d = L_MULTIPLY(b, Convert.ToString(c));

                a = L_SUB(a, d);

                if (trigger == 1) { p = p + c; }

                if (trigger == 0)

                {

                    if (trig == 1) { p = p + c; }

                    p = p + ".";

                    trigger = 1;

                    for (int iz = 1; iz <= cdph; i++) { p = p + "0"; }

                    if (trig == 0) { p = p + c; }

                }

                if (Len(p) >= length)

                {

                    if (negTrigger == 1) { p = "-" + p; }

                    return p;

                }

                a = L_MULTIPLY(a, "10");

            }

            if (negTrigger == 1) { p = "-" + p; }

            return p;

        }

        public static string L_ADD(string a, string b)

        {

            int negTrigger = 0;

            string p = "";

            int larm = 0;

            int lar = 0;

            if (Left(a, 1) == "-" && Left(b, 1) != "-")

            {

                if (longGT(Right(a, Len(a) - 1), b) == true)

                {

                    p = "-"+L_SUB(Right(a,Len(a) - 1),b);

                    return p;

                }

                return L_SUB(b, Right(a, Len(a) - 1));

            }

            if (Left(b, 1) == "-" && Left(a, 1) != "-")

            {

                if (longGT(Right(a,Len(a)-1),b) == true)

                {

                    p ="-" + L_SUB(Right(b,Len(b)-1),a);

                    return p;

                }

                return L_SUB(a,Right(b,Len(b)-1));

            }

            if (Left(b,1)=="-" && Left(a,1)=="-"){negTrigger = 1;}

            int da = testDecimal(a,1);

            int db = testDecimal(b,1);

            if (da > db){larm = da-db;lar = da;}

            if (db > da){larm = db-da;lar = db;}

            if (db < da){b = addPlaceHolders(b,larm);}

            if (da < db){a = addPlaceHolders(a,larm);}

            a = removeDecimal(a,lar);

            b = removeDecimal(b,lar);

            if (Left(a,1) == "-"){ a = Right(a,Len(a)-1);}

            if (Left(b,1) == "-"){ b = Right(b,Len(b)-1);}

            int a1 = Len(a);

            int b1 = Len(b);

            int largest= 0;

            if (a1 > b1) {largest = a1;}

            if ( b1>a1){largest = b1;}

            if (a1==b1){largest = a1;}

            int n1;int n2;int n3;string t;int remander = 0;int t1;

            for (int i = 0; i <= largest; i++)

            {

                if (i <= a1-1){

                    n1 = int.Parse(Mid(a,a1-i,1));

                }else{n1 = 0;}

                if (i <= b1-1){

                    n2 = int.Parse(Mid(b,b1-i,1));

                }else{n2 = 0;}

                n3 = n1+n2+remander;

                t = Convert.ToString(n3);

                p = Right(t,1)+p;

                t1 = Len(t);

                if (t1-1 > 0){t = Left(t,t1-1);}else{t = "";}

                remander = int.Parse(t);

            }

            if (Left(p,1)=="0"){p = Right(p,Len(p)-1);}

            if (da!=0 || db != 0) { p = addDecimal(p,lar);}

            if (negTrigger == 1){p = "-"+p;}

            return p;

        }

        public static string L_SUB(string a, string b)

        {

            int negTrigger = 0;string p = "";string tb = "";int da = 0; int db = 0;int larm= 0;int lar= 0;

	        if (longLT(a,b) == true && Left(a,1) != "-" && Left(b,1) != "-"){ negTrigger = 1;tb=b;b=a;a=tb;}

	        if (Left(a,1) == "-" && Left(b,1) == "-" && longGT(a,b) == true){ return L_ADD(a,b);}

	        if (Left(a,1) == "-" && Left(b,1) != "-")

            {

		        if (longGT(Right(a,Len(a)-1),b) == true){return L_ADD(Right(a,Len(a)-1),b);}

            }

	        if (Left(b,1) == "-" && Left(a,1) != "-")

            {

		        if (longGT(Right(b,Len(b)-1),a) == true){return L_ADD(Right(b,Len(b)-1),a);}

	        }

	        da = testDecimal(a,1);db = testDecimal(b,1);

	        if (da > db){larm = da-db;lar = da;}

	        if (db > da){larm = db-da;lar = db;}

	        if (db < da){b = addPlaceHolders(b,larm);}

	        if (da < db){a = addPlaceHolders(a,larm);}

	        a = removeDecimal(a,lar);b = removeDecimal(b,lar);

	        if (Left(a,1) == "-"){a = Right(a,Len(a)-1);}

	        if (Left(b,1) == "-"){b = Right(b,Len(b)-1);}

	        int a1 = Len(a);int b1 = Len(b);int largest = 0;

	        if (a1 > b1){largest = a1;}

	        if (b1 > a1){largest = b1;}

	        if (a1 == b1){largest = a1;}

            int n1; int n2; int n3;int remander = 0;string t;

	        for (int z = 0; z<=largest-1;z++)

            {

                if (z <= a1-1){n1 = int.Parse(Mid(a,a1-z,1));}else{n1 = 0;}

		        if (z <= b1-1){n2 = int.Parse(Mid(b,b1-z,1));}else{n2=0;}

                n3 = (n1-remander)-n2;

		        if (n3 < 0){n3 = 10 + n3;remander =1;}else{remander = 0;}

		        t=Convert.ToString(n3);p = Right(t,1)+p;

            }

            if (Left(p,1) == "0"){p = Right(p,Len(p)-1);}

	        if (da!=0 || db != 0){p = addDecimal(p,lar);}

            if (negTrigger == 1) { p = "-" + p; }

	        return p;

        }

        public static string L_MULTIPLY(string a, string b)

        {

            int negTrigger = 0;

            string p = "";

	        if(Left(a,1) == "-" && Left(b,1) == "-"){ a = Right(a,Len(a)-1);b = Right(b,Len(b)-1);}

	        if (Left(a,1) == "-") {negTrigger = 1;a = Right(a,Len(a)-1);}

	        if (Left(b,1) == "-") {negTrigger = 1;b = Right(b,Len(b)-1);}

	        int da = testDecimal(a,1); 

            if (da != 0){a = removeDecimal(a,da);}

	        int db = testDecimal(b,1);

            if (db != 0){b = removeDecimal(b,db);}

	        int dec = da+db;

            int n1;int n2;int n3;string f;string t = "";

	        for (int z = 0; z<=Len(b)-1;z++)

            {

		        n2 = int.Parse(Mid(b,Len(b)-z,1));

		        for (int y = 0;y<=Len(a)-1;y++)

                {

			        n1 = int.Parse(Mid(a,Len(a)-y,1));	

			        n3 = n1*n2; f = Convert.ToString(n3);

			        for (int e = 1; e<=y;e++){f = f + "0";}

			        t = L_ADD(t,f);f = "";

		        }

                for (int e = 1; e <= z; e++) { t = t + "0"; }

		        p = L_ADD(t,p);t = "";

	        }

	        if (Left(p,1) == "0"){ p = Right(p,Len(p)-1);}

	        if (dec != 0){p = addDecimal(p,dec);}

	        if (negTrigger == 1){p = "-"+p;}

	        return p;

        }

        public static bool longGT(string a, string b)

        {

            if (testDecimal(a, 0) == 0 && testDecimal(b, 0) == 0)

            {

                a = makeEL(a, b);

                b = makeEL(b, a);

            }

            int result = a.CompareTo(b);

            if (result > 0) { return true; }

            return false;

        }

        public static bool longLT(string a, string b)

        {

            if (testDecimal(a, 0) == 0 && testDecimal(b, 0) == 0)

            {

                a = makeEL(a, b);

                b = makeEL(b,a);

            }

            int result = a.CompareTo(b);

            if (result < 0) { return true; }

            return false;

        }

        // Helper functions

        public static string makeEL(string x, string y)

        {

            int a1 = Len(x); int b1 = Len(y);

            if (a1 > b1 || a1 == b1) { return x; }

            for (int z = 1; z <= b1 - a1; z++) { x = "0" + x; }

            return x;

        }

        public static int testDecimal(string a, int x)

        {

            int f = Len(a);

            if (x == 0)

            {

                for (int z = 1; z <= f; z++) { if (Mid(a, z, 1) == ".") { return 1; } }

                return 0;

            }

            if (x == 1)

            {

                for (int z = 1; z <= f - 1; z++) { if (Mid(a, f - z, 1) == ".") { return z; } }

            }

            if (x == 2)

            {

                for (int z = 1; z <= f; z++) { if (Mid(a, z, 1) == ".") { return z; } }

            }

            return 0;

        }

        public static string removeDecimal(string a, int b)

        {

            if (b == 0) { return a; }

            return Left(a,Len(a)-(b+1))+Right(a,b);

        }

        public static string addDecimal(string a, int b)

        {

            while (Len(a) < b) { a = "0" + a; }

            return Left(a, Len(a) - b) + "." + Right(a, b);

        }

        public static string addPlaceHolders(string numToChange, int decimalsToAdd)

        {

            for (int z = 1; z <= decimalsToAdd; z++) { numToChange = numToChange + "0"; }

            return numToChange;

        }

        public static int CountDecimalPlaceHolder(string a)

        {

            bool trigger = false;int count = 0;

            for (int z = 1; z <= Len(a); z++)

            {

                if (Mid(a, z, 1) == ".") { trigger = true; z++; }

                if (trigger == true && Mid(a, z, 1) == "0") { count++; }

                if (trigger == true && Mid(a, z, 1) != "0") { return count; }

            }

            return count;

        }

        public static int additionalPlaceHolders(string a, string b)

        {

            int z = 1;

            int count = 0 ;

            while (longGT(b, Left(a, z)) == true && b != Left(a, z))

            {

                count++;

                z++;

                if (z == Len(a)) { return 0; }

            }

            return count;

        }

        public static string CleanLDecimal(string a)

        {

            while (Left(a, 1) != ".") { a = Right(a, Len(a) - 1); }

            return a;

        }

        public static int rsdc(string a)

        {

            for (int place = 1; place <= Len(a); place++) { if (Mid(a, (Len(a) - (place - 1)), 1) == ".") { return place; } }

            return 0;

        }

        public static int lsdc(string a)

        {

            for (int place = 1; place <= Len(a); place++) { if (Mid(a, place, 1) == ".") { return place; } }

            return 0;

        }

        public static string replaceDecimal(string num, int ls, int rs)

        {

            string temp;

            temp = Mid(num, 1, ls) + "." + Mid(num, ls, rs);

            return temp;

        }

        // string functions

        static string Right(string s, int count)

        {

            string newString = String.Empty;

            if (s != null && count > 0)

            {

                int startIndex = s.Length - count;

                if (startIndex > 0)

                    newString = s.Substring(startIndex, count);

                else

                    newString = s;

            }

            return newString;

        }

        static string Left(string s, int count)

        {

            string newString = string.Empty;

            if (s != null && count > 0)

            {

                int startIndex = 1;

                if (startIndex > 0)

                    newString = s.Substring(startIndex, count);

                else

                    newString = s;

            }

            return newString;

        }

        static string Mid(string s, int start, int end)

        {

            string newString = string.Empty;

            if (s != null && start > 0 && end > 0)

            {

                int totalIndex = start + end;

                if (totalIndex <= s.Length)

                    newString = s.Substring(start, end);

                else

                    newString = s;

            }

            return newString;

        }

        static int Len(string s){return s.Length;}

    }

}



#7 TheNut

    Senior Member

  • Moderators
  • 1470 posts
  • LocationThornhill, ON

Posted 24 August 2009 - 10:35 AM

.NET usually isn't that far behind C in performance (10% is the usual figure thrown around). I've been converting my C++ engine over to C# and it's been a pleasant experience. All my procedural algorithms run almost on par with the C++ counterpart. In Paul's case, the strings are weighing the program down. Although even in C, dealing with strings is expensive compared to base data types. paul0n0n, read up on Binary Coded Decimal (BCD) arithmetic. It's like string arithmetic, but you operate on a byte array instead. Most operations can also be performed using logic (OR, XOR, AND, etc...) which is really fast compared to "school-book arithmetic". You don't have to convert between numbers and strings, so that's an instant boost there. If you implement full BCD, you can store 2 digits in a single byte (4 bits per digit), although management gets a little more complicated. Once you convert to that format, you should already see a boost. Avoid creating copies of objects (ie: substring(...)).

Also, in case you just want a quick fix, there are C# libraries out there that do this sort of thing. See: http://en.wikipedia....sion_arithmetic.
http://www.nutty.ca - Being a nut has its advantages.

#8 martinsm

    Member

  • Members
  • PipPip
  • 88 posts

Posted 24 August 2009 - 10:38 AM

I would suggest using byte[] or uint[] array for storing digits of large integer (as 8-bit or 32-bit digits), not strings. Then manipulating array elements will be easier and without any string maniuplation functions (that are heavy on memory allocations).

#9 paul0n0n

    Member

  • Members
  • PipPip
  • 37 posts

Posted 24 August 2009 - 02:12 PM

martinsm - That may be so, but it can be more complicated. I started out with trying to use array's but gave it up as... well maybe I could figure it out. at any rate I'm not too worried about memory consumption at this point. I just want to know how to use it, then maybe improve upon it.

TheNut - Using array's isn't a bad idea, but are array's re-sizable in c#? If not I'm not sure how to make it essentially (hardware determined) infinite.

#10 SyntaxError

    Valued Member

  • Members
  • PipPipPip
  • 139 posts

Posted 24 August 2009 - 02:37 PM

paul0n0n said:

SyntaxError - high to unlimited precision.

z80 - That is a good idea, wonder if c# would be just as good as c

Well if you really want it to be fast I used to program in 8086 asm and there were BCD assembly instructions on the 8086. I assume they have also carried over to the 32 bit architecture. However I'm not sure how you get to them from C#. If I remember C# can call C DLLs so if you write an asm program, use C calling convention and compile it as a DLL you should be able to get it to work. I'm not the best expert on C# though.

Edit: It pays the read the thread :) Ok well I guess I added at least a little.

#11 geon

    Senior Member

  • Members
  • PipPipPipPip
  • 891 posts

Posted 24 August 2009 - 02:43 PM

If you need to convert between your bignum data and strings a lot, it might be a good idea to store it as decimal numbers in memory too, since the base conversion is quite costly.

(I have no idea what any of the above code is doing, since it was too painful to read.)

#12 paul0n0n

    Member

  • Members
  • PipPip
  • 37 posts

Posted 24 August 2009 - 02:57 PM

geon - i know its painful, it's just simple arithmetic using strings. It's complicated and just, well messy. I will comment the c# code to death, hopefully that will help.

#13 TheNut

    Senior Member

  • Moderators
  • 1470 posts
  • LocationThornhill, ON

Posted 24 August 2009 - 03:43 PM

paul0n0n said:

are array's re-sizable in c#
Basic array's don't have a "resize" method, although it wouldn't be difficult to write a method to do it. Instead, you can use List<byte> with Add / Insert calls. .NET will manage the memory for you, and in some ways it will be efficient since it will allocate more than you actually need, giving you buffer space to work with. The trick here is to store the number backwards in the list. That is, the most significant number is stored at the end of the the list.

Ex: 123.456
List[0] = 6, List[1] = 5, List[2] = 4, etc...

This way you progressively add into the list rather than insert, which is quite expensive.

This will make your arithmetic calculations much easier. A really basic example is provided below. This example assumes both number1 and number2 are the same size, are both positive (note, you can use Two's Compliment to perform addition of a negative value), and have a mantissa at the same location, which is represented by some sort of "mantissa index" class member (ie: you don't include the decimal in the list).


public List<byte> add (List<byte> number1, List<byte> number2)

{

     List<byte> result = new List<byte>();


     // Add from left to right (remember, this number will be backwards)

     byte carry = 0;

     for (int i = 0; i < number1.Count; ++i)

     {

          byte addition = number1[i] + number2[i] + carry;

          if ( addition > 9 )

          {

               carry = 1;

               addition -= 10;

          }

          else

               carry = 0;


          result.Add(addition);

     }


     return result;

}


public string ToString (List<byte> number)

{

     string result = "";

     for (int i = number.Count - 1; i >= 0; --i)

          result += number[i];

     return result;

}


Pretty clean eh? Just throw in the extra part to handle negatives and varying number sizes and that should get you going.
http://www.nutty.ca - Being a nut has its advantages.

#14 alphadog

    DevMaster Staff

  • Moderators
  • 1641 posts

Posted 24 August 2009 - 04:01 PM

If you are going to do this with strings in C#, consider using StringBuilder. I didn't pour through your code, but generally and when used appropriately, it can help alleviate the overhead of repeated rebuilds of string objects since they are immutable in .NET C#.
Hyperbole is, like, the absolute best, most wonderful thing ever! However, you'd be an idiot to not think dogmatism is always bad.

#15 martinsm

    Member

  • Members
  • PipPip
  • 88 posts

Posted 24 August 2009 - 04:55 PM

Yes, arrays are resizeable in C#:
byte[] arr = new byte[10];
Array.resize(ref arr, 100);
Console.WriteLine(arr); // will print 100

But you should use List<T> anyway, because it has other nice properties and methods (like std::vector<T> in C++)

#16 paul0n0n

    Member

  • Members
  • PipPip
  • 37 posts

Posted 24 August 2009 - 06:12 PM

ok, here is the commented code for just Division.. I know there are errors in it as I came across a few that I didn't fix.

public static string L_DIVIDE(string a, string b,int length)
        {
            //For example perposis 'a' = "0000000.0034"
            //For example perpeses 'b' = "29"
            // 'a' is the numerator
            // 'b' is the denominator
            // 'length' is the max number of decimal places to be calculated,
            // as most fractions are endlessly repeating.

            //Initialize Integers
            int RightSideDecimalCountOfa;
            int RightSideDecimalCountOfb;
            int LeftSideDecimalCountOfa;
            int LeftSideDecimalCountOfb;
            int cdph = 0;
            int talc;
            int z = 1;
            int zerroCount = 0;
            int tc;
            int c;
            //Initialize Strings
            string Outcome = "";
            string d;
            //Initialize bools
            bool trigger = false;
            bool negTrigger = false;
            bool trig = false;
            bool exit = false;

            //Find out if the outcome is going to be a Negitive number
            if (Left(a,1)== "-" && Left(b,1) == "-") 
            {
                // if both a and b are negitive the outcome will be positive.
                // so remove the negitive sign from both a and b.
                a = Right(a, Len(a) - 1);
                b = Right(b, Len(b) - 1);
            }
            if (Left(a, 1) == "-")
            {
                // If only a is negitive the outcome will be negative.
                // So turn the negTrigger to true and remove the negitive sign from a.
                // With the negTrigger to true the last step before returning the outcome will
                // be to add the negitive sign infront of the outcome.
                negTrigger = true;
                a = Right(a, Len(a) - 1);
            }
            if (Left(b, 1) == "-")
            {
                // If only b is negitive the outcome will be negative
                // So turn the negTrigger to true and remove the negitive sign from b.
                // With the negTrigger to true the last step before returning the outcome will
                // be to add the negitive sign infront of the outcome.
                negTrigger = true;
                b = Right(b, Len(b) - 1);
            }

            //Find the Decimal point's position from the right side
            RightSideDecimalCountOfa = rsdc(a); //rsdc is Right Side Decimal Count
            RightSideDecimalCountOfb = rsdc(b);
            //Find the decimal point's position from the left side
            LeftSideDecimalCountOfa = lsdc(a);//lsdc is Left Side Decimal Count
            LeftSideDecimalCountOfb = lsdc(b);

            // If a is greater than b then the cdph (Common Decimal point Place Holder) is triggered
            // to be set to 0.  This is so that wholeNumber/wholeNumber works.
            if (longGT(a, b) == true)
            {
                trig = true;
            }
            
            // This section is used to deturmain the decimal point's placeholder (cdph)
            // if  'a' is a fraction and 'b' is a fraction.  (not working properly)
            if (RightSideDecimalCountOfb != 0)
            {
                a = removeDecimal(a, RightSideDecimalCountOfa);
                talc = Len(a);
                a = replaceDecimal(a, RightSideDecimalCountOfa, RightSideDecimalCountOfb);
                b = removeDecimal(b, RightSideDecimalCountOfb);
                if (talc > Len(a)){cdph = talc - Len(a);}
                if (talc < Len(a)){cdph = Len(a) - talc - 1;}
            }
            if (trig == true) { cdph = 0; }

            
            //Find the Decimal point's position from the right side.
            //This is done for a second time for the fraction/fraction cenerio
            RightSideDecimalCountOfa = rsdc(a); //rsdc is Right Side Decimal Count
                                                //if 'a' = "000000.0034" rsdc(a) would return 4.
            RightSideDecimalCountOfb = rsdc(b);
            //Find the decimal point's position from the left side
            LeftSideDecimalCountOfa = lsdc(a);//lsdc is Left Side Decimal Count
                                              //if 'a' = "000000.0034" lsdc(a) would return 6.
            LeftSideDecimalCountOfb = lsdc(b);

            //If a = "0000000.0034" then remove all the "0"'s on the left side.
            //So that a = ".0034".  It's not really necesary but is here as a precaution.
            while (RightSideDecimalCountOfa != 0 && Left(a, 1) != "." && z != Len(a))
            {
                if (Left(a, 1) == "0") { a = Right(a, Len(a) - 1); }
                z++;
            }

            //Make 'b' have an equal right side decimal point place holders as 'a'
            //So if 'a' = ".0034 and 'b' = "29"  after this 'b' = "290000"
            for (int i = 1; 1 <= RightSideDecimalCountOfa; i++) { b = b + "0"; }
            
            //if 'a' = ".0034" afther this removes the decimal point 'a' = 0034
            a = removeDecimal(a, RightSideDecimalCountOfa);
            
            //Change 'a' from "0034" to "34" and count how many zerro's were removed
            //zerroCount = 2
            while (Left(a, 1) == "0")
            {
                a = Right(a, Len(a) - 1);
                zerroCount++;
            }

            //If 'a' is equal to 'b' then it will always be "1" so return that.
            if (a == b) { return ("1"); }
            
            //Now the Division.  'length' is used here as a basis and not as the strict guid.
            for (int i = 1; i <= length; i++)
            {
                //remove any "0"'s that happen to pop up infront of 'a'
                //this avoids an endless loop if 'a' ever happens to equal "0" or "00" or "00...00"
                while (Left(a, 1) == "0") { a = Right(a, Len(a) - 1); }

                //If 'a' is empty as it should be from the above statement were 'a' would equal "0"
                //return the 'Outcome'.
                if (a == "") { return (Outcome); }
                
                //Make 'a' greater then 'b' if it is not already
                while (longGT(b, a) == true)
                {
                    //multiply 'a' by "10"
                    a = L_MULTIPLY(a,"10");

                    //add's the standard "0." to the 'Outcome' if it hasn't been done.
                    //Then add the necisary place holders.
                    if (trigger == false)
                    {
                        Outcome = Outcome + "0" + ".";
                        trigger = true;

                        //Adds the place holders to the 'Outcome'.
                        for (int iz = 1; iz <= cdph; iz++) { Outcome = Outcome + "0"; }
                    } 
                    else { Outcome = Outcome + "0"; }// if 'a' is multiplied by 10 then the 'Outcome' needs a "0" added.
                }

                //Reset for next pass.
                tc = 1;         //'tc' (temp count)
                c = 0;          //'c' (count)
                d = "";         //'d' (temp denominator) so that 'b' is never changed.
                exit = false;   //'exit' (exit loop trigger)

                //'c' is the um well..
                //Say 'Outcome' ="0.01272" 'c' is the individial '1' then '2' then '7' ect.
                //I don't know if this part is works in c#.  I had to make some changes from
                //my original basic structure. There could be a possable infinit loop here.
                //If 'a' = "1000000000" and 'b' = "1" then 'c' would have to count upto 1000000000.
                while (longGT(d, a) == false && exit == false)
                {
                    c++;  //Increase 'c' by 1.
                    d = L_MULTIPLY(b, Convert.ToString(c)); //Multiply 'b' by 'c' and put it in 'd'
                    
                    //Increase 'c' until 'd' is greater then 'a'.
                    if (longGT(d, a) == true)
                    {
                        c = tc;  // 'c' equals the last 'c' so that 'd' is not greater then 'a'.
                        exit = true; //'exit' the loop.
                    }
                    if (exit == false) { tc = c; } // 'tc' = 'c', skip this if 'exit' is true.
                }
                // if (exit == false) { c = 1; }  //I don't think This is needed.


                d = L_MULTIPLY(b, Convert.ToString(c)); //Multiply 'b' by 'c' and put it in 'd'
                a = L_SUB(a, d); //Subtract 'a' from 'd' and replace 'a'

                //Append 'c' to 'Outcome' if 'Outcome' already has "0.".
                if (trigger == true) { Outcome = Outcome + c; }
                
                //If 'Outcome' doesn't have "0." then 'c' is on the left side of the decimal point.
                if (trigger == false)
                {
                    //Append 'c' to 'Outcome'
                    if (trig == true) { Outcome = Outcome + c; }
                    Outcome = Outcome + "."; //Add the decimal point
                    trigger = true;  //The decimal point has been added

                    //Add "0"'s to 'Outcome'
                    for (int iz = 1; iz <= cdph; i++) { Outcome = Outcome + "0"; }
                    
                    //Append 'c' to 'Outcome' if nothing else was done.
                    if (trig == false) { Outcome = Outcome + c; }
                }

                // If 'Outcome' has 'length' decimal places then
                if (Len(Outcome) >= length)
                {
                    //If 'Outcome' should be negative then add "-" to the front of it.
                    if (negTrigger == true) { Outcome = "-" + Outcome; }

                    //Return 'Outcome'.
                    return (Outcome);
                }

                //Increase the size of 'a' by "10" for the next pass.
                a = L_MULTIPLY(a, "10");
            }
            //If 'Outcome' should be negative then add "-" to the front of it.
            if (negTrigger == true) { Outcome = "-" + Outcome; }

            //Return 'Outcome'.
            return (Outcome);
        }


#17 paul0n0n

    Member

  • Members
  • PipPip
  • 37 posts

Posted 24 August 2009 - 09:52 PM

TheNut said:

use List<byte> with Add / Insert calls. .NET will manage the memory for you, and in some ways it will be efficient since it will allocate more than you actually need, giving you buffer space to work with. The trick here is to store the number backwards in the list. That is, the most significant number is stored at the end of the the list.

Ex: 123.456
List[0] = 6, List[1] = 5, List[2] = 4, etc...

This way you progressively add into the list rather than insert, which is quite expensive.

This will make your arithmetic calculations much easier. A really basic example is provided below. This example assumes both number1 and number2 are the same size, are both positive (note, you can use Two's Compliment to perform addition of a negative value), and have a mantissa at the same location, which is represented by some sort of "mantissa index" class member (ie: you don't include the decimal in the list).

this is very helpful! Thanks.

#18 z80

    Valued Member

  • Members
  • PipPipPip
  • 104 posts

Posted 26 August 2009 - 04:14 PM

How about using some existing libraries?

http://en.wikipedia....metic#Libraries





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users