Σάββατο 21 Δεκεμβρίου 2024

using left or right associative for exponents;

M2000 use left associative for exponents:

So 3+4*2/(1-5)^2^3 return 3.001953125

but unary + and - are right associative

So 3+4*2/(1-5)^+2^3   return 3.0001220703125 because the + between ^ and 2 is a unary +.

It is the same as 3+4*2/(1-5)^+(2^3) or 3+4*2/(1-5)^(2^3)

Old versions of M2000 always using left associative for exponents, so the unary + or - are all computed for the following operand not the entire following expression, so  3+4*2/(1-5)^+2^3 was like 3+4*2/(1-5)^(+2)^3 same as  3+4*2/((1-5)^2)^3

Also old versions -2^2 return 4, because was like (-2)^2 but the current version 12 return -4 because the -  and the - as unary are left associative wich means -(2^2) or -(4) or -4.

Old version 5+-2^2 return 9, because after + we have the -2^2 which is 4. so we have 5+4=9

Current version 5+-2^2 return 1 because -2^2 is -4 so  5 + -4 is 5-4 is 1,



Πέμπτη 19 Δεκεμβρίου 2024

Shallow and Deep Copy for Objects of type Group.

An object of type Group, may have some members like values, and some other as pointers to values. Some objects are used as values also. A group object can be a value or a pointer to object. 

Here we will see a subset of properties of groups about copy, deep and shallow. 

About Check1 module:

We have a class named alfa which make a group of 4 members, a, b, k() and beta with member z. From these members objects are array k() and group beta. These are "values" for interpreter. See the add() which take a pointer to array one time and a double at second time and the semantic a+=m works for either type. The & symbol used for passing by reference.

About Check2 module:

Now our alfa class has  k as pointer to array (we make it assign an empty array), and beta as pointer to group (we make it assign the null object, which is not Null but an object of type Null).  We have a Class: part. This part say to interpreter that the following members exist only on construction time. Module alfa called when we use alfa()  to make a new group of type alfa. Also we have a private class betaClass. A class definition which isn't member is global, but as member of group is local. So this class used to make the object which place to member beta. We do the work to place numbers to array which point the member k, and the object to beta from the constructor of alfa.

To use the z member of beta inner object we have to use the fat arrow. So for z, the z.beta=>z used for return or set value. See that between z and beta there is no fat arrow (this means that z isn't pointer to group, so beta is a normal member - a normal member can be pass by reference), So how we pass by reference the z member of beta? To do that we have to "open" the beta using for beta { }. At this point the block used for temporary definitions (all new definitions deleted after the exit from this block). So one temporary hidden variable is the variable which hold the group, not as pointer but as normal group. So tge add(&.z, 100) say that .z is member of the first hidden variable (we can use ten hidden variables, adding a list of variables one one or more nested for object blocks.

We see here that we have a shallow copy. The x group created from z but have the same values for k and beta (x get a copy of pointers, not a copy of those which points). So changing values from z side we get the same change from x side. When we do x=z  we merge z to x, so we get copy from pointers not the copies of actual objects which these pointers points.

About Check3 module:

We change the class alfa to get a Value part. This part make the group to return what we want to return. When we do this, without made a Set part, then our object block any merging from other object. So the X=Z first time can be done because X has no value/type, but second time X=Z can't be done, there is no Set part. The value part, first time make the m from This (we use This like This of java, but we didn't use it - we can - for members inside a function member, we just use dot and identifier which is the same as This dot identifier). Next at the value part we make a new pointer making a new object of class betaclass passing the same value of this.beta=>z. Also we make a copy of this.k using the cons(array, ....) which concatenate arrays by using shallow copies of them. Last we return the group(m) because this function (group()) can get a copy of the object without using the value part (using =m and not =group(m) we call again the value part of that m, until we fill all the process stack). So the Value part make a new object with deep copies of the two objects k and beta. So when we do the shallow copy at x=z then the m which is a deep copy then by shallow copy we get a real deep copy (the m destroyed silentlly) . At the end of  then Check3 module we check for the second x=z inside a Try block. So we trap  the error and continue,

About Check4 module:


Now we make the Set part. This part has only one statement Read This, so we get to This the merged group. If we want to get a group of a specific type we can use Read m as thatType: Let This=m (we can't use This=m inside set part because is like we do recursion, and we fill the process stack). As you see there is one condition for each Value and Set functions, which excaust the stack, which raise the "out of memory" error. The let this=m is actually a Push m and a Read This. 
        Set {
            read m as alfa: let this=m
        }
Better is this (Read This as alfa). But see the example. Using Let we can merge another group. See also the final clause for value and set. This means that these functions are final, they can't change from other merging. Merging is a "live" inheritance. Not only merge members, but also the final group has all the types from the merged objects.

    class alfa {
        double x
        set final {
            read this as alfa
        }
        value final {
            =this
        }
    class:
        module alfa (.x) {}
    }
    z=alfa(100)
    ? z.x=100
    m=alfa(300)
    class beta {
        x=500
    }
    try {
        z=beta()
    }
    ? z.x=100
    z=m
    ? z.x=300
    ' let z=beta() skip the set part
    let z=beta()
    ? z.x=500
    ? z is type alfa = true
    ' now z is also type beta
    ? z is type beta = true
    k=beta()
    k.x=1000
    try {
        z=k
    } ' can't because now we not skip the Set part

So for this module, the second x=z run without raising error.

About Check5 module:


This is the advanced test. The z now is pointer to object. We make the Remove { } part which run when the object deleted. The remove part is the deconstructor. So now we have constructor module alfa, value, set and deconstructor called remove.We place a print statement at value part to identify when we use the value part and when we skip it. Because z is a pointer, to use the value part we have to do explicitly, using eval(z) .  Inside Value part the This not call the Value part, and not return the pointer (the z value) to m. So value part not changed from Check4 and Check3 modules.
So if we use x=z  the x will be a pointer to the same object which z points. We use x=Eval(z) so we get a group copy of actual object which z point. 
So how we send by reference z.k and z.beta.z when z is a pointer and beta is a pointer too?

    for z {
        add(&.k, 20)
        for .beta {
            add(&..z, 100)
        }
    }

As we see from code we have two for object, the second nested, and we send .k and ..z (see the double dot before the name of z).
At the second part of this module we set z at another object, the x. First the old object deleted by calling the constructor before actual deleted.
Now the z pointer isn't a real pointer but a "reference type". Because the x is a "named" group, which means a group with a name (like z and x in module Check1, which they are attach to module like variables), when we do z->x or z=pointer(x), interpreter save a weak reference and the status "i am a reference", and when we use the pointer the interpreter make the hard link (but maybe that can't be done, if the refernced object not exist, because module where this object attached now not run, so an error raised). A pointer to object may change to normal pointer or to weak reference depends from the assigment.

We see next the z->(x) which make a copy of x (deep copy, we will see the output of print statement from value part of class alfa). The z->(x) is same as z=pointer((x))  (see the double parenthesis, when we didn't place parenthesis then we have either a group or a class name with parentesis and maybe values for constractor), but when we have "extra" parenthesis then interpreter expect a goup object from expression inside parenthesis.

The last thing we see in Check1 is the test for null for the pointer z. We place the null (pointer() without something). There is no NULL as the 0 address from other programming languages. Although we can do that: z->0 which is the same as z=pointer()  (we can't use z->pointer() because pointer() isn't a user class but an internal function). The Null object can't merged to group (there is no members and the type Null can't be passed to other objects). When interpreter start make the Null object, with a specific address. So the null pointer internal isn't null. For us the Null object is the Null object. So the z is type Null return True if z point to Null object.

For other objects like arrays (of type mArray) there is no Null object. We can place an empty array but the test of two array pointers which have empty arrays point to different empty arrays:

a=(,)
b=(,)
? a is b = False
NullArray=(,)
a=NullArray
b=NullArray
? a is b = True

Although using this is like a Null array, there are some functions which append members. and the NullArray isn't blocked for appending members. So from the time we accidentally place members we break the use of NullArray.


module Check1 {

    print module.name$
    class alfa {
         double a, b
         dim k(1 to 10)=10
         group beta {
             z=100
         }
    }
    z=alfa()
    ? z.k()#sum()=100 ' True
    x=z ' deep copy because of k() and Group
    add(&z.k(), 20)
    add(&z.beta.z, 100)
    ? z.beta.z=200
    ? z.k()#sum()=300
    ? x.K()#sum()=100
    ? x.beta.z=100
    x=z ' we do a merge and the values changed
    ? x.K()#sum()=300
    ? x.beta.z=200
    sub add(&a, m)
        a+=m
    end sub
}
Check1
module Check2 {
    print module.name$
    class alfa {
        double a, b
        k=(,)
        beta=pointer()
    private:
        class betaClass {
             z
        class:
            module betaClass (.z) {
            }
        }
    class:
        module alfa {
            dim a(1 to 10)=10
            .k<=a()
            .beta<=pointer(.betaClass(100))
        }
    }
    z=alfa()
    ? z.k#sum()=100 ' True
    x=z ' shallow copy because of k and beta are pointers to objects
    add(&z.k, 20)
    for z.beta {
        add(&.z, 100)
    }
    ? z.beta=>z=200
    ? z.k#sum()=300
    ? x.K#sum()=300
    ? x.beta=>z=200
    ? x.beta is z.beta = true
    ? x.k is z.k = true
    ? x is z = false
    x=z ' we can do that, but objects but we have shallow copy too
    ? x is z = false ' x internal pointer can't change
    ' x and z are objects with unique and private pointer
    ' x and z deleted when this module exit run
    sub add(&a, m)
        a+=m
    end sub
}
Check2
module Check3 {
    print module.name$
    class alfa {
        double a, b
        k=(,)
        beta=pointer()
        value {
            m=this
            m.beta=pointer(.betaClass(.beta=>z))
            m.k=cons(.k)
            =group(m)
        }
    private:
        class betaClass {
             z
        class:
            module betaClass (.z) {
            }
        }
    class:
        module alfa {
            dim a(1 to 10)=10
            .k<=a()
            .beta<=pointer(.betaClass(100))
        }
    }
    z=alfa()
    ? z.k#sum()=100 ' True
    x=z ' deep copy because now object handle the export (has Value part)
    add(&z.k, 20)
    for z.beta {
        add(&.z, 100)
    }
    ? z.beta=>z=200
    ? z.k#sum()=300
    ? x.K#sum()=100
    ? x.beta=>z=100
    // we can't change it because we didn't handle the import (has no Set part)
    Try ok {
        x=z
    }
    If not ok then Print "Error:";Error$
    sub add(&a, m)
        a+=m
    end sub
}
Check3
module Check4 {
    print module.name$
    class alfa {
        double a, b
        k=(,)
        beta=pointer()
        value {
            m=this
            m.beta=pointer(.betaClass(.beta=>z))
            m.k=cons(.k)
            =group(m)
        }
        Set {
            read this
        }
    private:
        class betaClass {
             z
        class:
            module betaClass (.z) {
            }
        }
    class:
        module alfa {
            dim a(1 to 10)=10
            .k<=a()
            .beta<=pointer(.betaClass(100))
        }
    }
    z=alfa()
    ? z.k#sum()=100 ' True
    x=z ' deep copy because now object handle the export (has Value part)
    add(&z.k, 20)
    for z.beta {
        add(&.z, 100)
    }
    ? z.beta=>z=200
    ? z.k#sum()=300
    ? x.K#sum()=100
    ? x.beta=>z=100
    ' now we can merge z to x because we have a Set part
    x=z
    ? x.K#sum()=300
    ? x.beta=>z=200
    sub add(&a, m)
        a+=m
    end sub
}
Check4
module Check5 {
    print module.name$
    class alfa {
        double a, b
        k=(,)
        beta=pointer()
        value {
        ? "value ok"
            m=this
            m.beta=pointer(.betaClass(.beta=>z))
            m.k=cons(.k)
            =group(m)
        }
        Set {
            read this
        }
        remove {
            print "just deleted", .a, .b
        }
    private:
        class betaClass {
             z
        class:
            module betaClass (.z) {
            }
        }
    class:
        module alfa(.a, .b) {
            dim a(1 to 10)=10
            .k<=a()
            .beta<=pointer(.betaClass(100))
        }
    }
    z->alfa(10, 30)
    ? z=>k#sum()=100 ' True
    ' eval(z) call value when z is a pointer to group
    x=eval(z) ' deep copy because now object handle the export (has Value part)
    ' x=group(z)  'shallow copy for members which are pointers to objects
    for z {
        add(&.k, 20)
        for .beta {
            add(&..z, 100)
        }
    }
    ? z=>beta=>z=200
    ? z=>k#sum()=300
    ? x.K#sum()=100
    ? x.beta=>z=100
    ? "now z will point to x, so old object deleted"
    ' z=pointer(x)
    z->x
    ? "now z point to x"
    ? z=>beta=>z=100
    ? z=>k#sum()=100
    ? "now z point to a copy of x (as a deep copy)"
    x.a+=100
    z->(x)
    for z {
        add(&.k, 20)
        for .beta {
            add(&..z, 100)
        }
    }
    ? z=>a=110
    ? z=>beta=>z=200
    ? z=>k#sum()=300
    ? x.K#sum()=100
    ? x.beta=>z=100
    ? z is type alfa=true
    ? "now z point to null, old deleted"
    z=pointer()
    ? z is type null=true
    sub add(&a, m)
        a+=m
    end sub
}
Check5

Τετάρτη 18 Δεκεμβρίου 2024

Revision 55 Version 12

1. Numbers using underscore _

? 0x6000_0000_0000_0000&& ' long long 64bit
? 9_223_372_036_854_775_807&& ' max long long
? 0x0000_0000& ' long 32 bit
? 2_147_483_647& ' max long
? 0x0000% ' integer 16bit
? 32_767% ' max integer
? 0x00ub ' byte 8bit unsigned only (0 to 255)
? 2_55ub ' max byte
? 0x8000_0000_0000_0000 ' decimal type (hold values as unsigned long long)
? 18_446_744_073_709_551_615@ ' max usnigned long long (decimal type)
? 123_456_789.876_543_210@ ' decimal type 27 digits
? #FFFFFF, #FFFF00=-65535 ' HTML COLORS - NO underscore
? 46_000ud=date("9/12/2025")
Def t(x)=type$(x)
? t(12_456.123_4#)="Currency"
? t(1_012.232e-10~)="Single"

2. Structures. New type Currency. When we use offset without label (here c) now interpreter pick the first one here the c.

2.1 Using only offest

structure alfa {
    c as currency
}
buffer mem as alfa*100
? len(mem)
return mem, 3:=123121.2345#
z=eval(mem, 3)
? type$(z)="Currency", z=123121.2345#

2.2 Casting Currency to byte offsets

buffer mem as byte*1000
? len(mem)
return mem, 0:=123121.2345 as currency
z=eval(mem, 0 as currency)
? type$(z), z

2.3 Casting from long long to currency (123.4567 they have the same bits but rendering with the last 4 digits as fractional part)

buffer clear mem as byte*1000
Return mem, 100:=1234567 as long long
? eval(mem, 100 as Currency)

2.4 Long Long have also a bug and that bug removed

structure cc {
    d as integer*10
    c as long long ' usigned long long (8 bytes)
}
buffer clear mem as cc*100
a=0xFFFF_FFFF_FFFF_FFFF
' unsigned long long are Decimal types
Print type$(a)="Decimal"
' but we fit it on 8 bytes (the first 64bit)
return mem, 10!c:=0xFFFF_FFFF_FFFF_FFFF, 4!d!9:=65535
z=eval(mem, 10!c)
Print type$(z)="Decimal", z=18446744073709551615@
k=sint(z) 'same bits as long long (signed) )is the number -1
Print type$(k)="Long Long", k=-1 ' so k is long long signed
b=eval(mem, 4!d!9)
? b, type$(b)="Currency" ' this is the unsigned type for long and integer
integer b1=sint(b, 2)
? b1=-1, type$(b1)="Integer"

2.5 A bigger example with structure (Buffers can be put/get using files) 

module check3 {
    structure compount {
        s as integer*19 ' for string
        st as integer ' for end point
        c as currency
        q as currency
    }
    buffer clear mem as compount*10
    put(mem, 4,"Mc Donuts", 1.233#, 12)
    put(mem, 5,"Hellios", 123.789#, 100.5)
    open "saveme.dat" for output as #f
    put #f, mem, 1
    close #f
    // narrow our buffer
    buffer clear mem as compount*2
    open "saveme.dat" for input as #f
        get #f, mem, len(compount)*4+1
    close #f
    show(mem, 0)
    show(mem, 1)
    sub put(m, a, n as string, am as currency, qu as currency)
        Return m, a!s:=n, a!st:=0, a!c:=am, a!q:=qu
    end sub
    sub show(m, a)
        Print "Name:";LeftPart$(Eval$(m, a!s, 40), chr$(0)),
        Print @(20),"Amount:";eval(m, a!c),@(40),
        Print "Items:";eval(m, a!q)
    end sub
}
check3


Τρίτη 17 Δεκεμβρίου 2024

Complex Numbers

This is a class fot complex numbers. Here is the export. We get power of complex, with various combinations. I use Atan2 from internal math library (atach on Math object). To prevent π to write as π (greek letter) and not p (windows subtitute π to p) we use  Wide Output (UTF16LE).

Output:

(1+i)^5=(-4-4i)
(2+2i)^6=(-512i)
(1+i)^18=(512i)
(2+i)^(3-i)=(14.8073788312+9.8335865958i)
(221-4i)^(12+3i)=(-1.38398760508149E+28-3.82799320957046E+27i)
e^(πi)+1 = (0)


module check (filename as string=""){
Class Complex {
private:
double vr, vi
public:
function Arg {
declare m math
Method m, "Atan2", .vi, .vr as ret
=ret
}
final pidivby180=1.74532925199433E-02
final m_e=2.71828182845905
final maxval=1.7976931348623157E+308
property real {
value {link parent vr to vr : value=vr}
}
property imaginary {
value {link parent vi to vi : value=vi}
}
property toString {
value { clear 'so a new clear as string created after
link parent vr, vi to vr, vi
if vi then
if vr then
if vi>0 then
if vi==1 then value="("+vr+"+i)" else value="("+vr+"+"+vi+"i)"
else
if vi==-1 then value="("+vr+"-i)" else value="("+vr+""+vi+"i)"
end if
else
if vi=1 then value="(i)" else.if vi=-1 then value="(-i)" else value="("+vi+"i)"
end if
else
value="("+vr+")"
end if
}
}

function exp(rr=10) {
            double exp = .m_e^.vr
            c=this
            th=.vi/.pidivby180
            c.vr<=round(exp * cos(th), rr)
            c.vi<=round(exp * sin(th),rr)
            =c
       }
function cabs() { ' ret type double
if abs(.vr)=infinity or abs(.vi)=infinity then =.maxval:Exit
double c=abs(.vr), d=abs(.vi)
if c>d then
r=d/c
=c*sqrt(1+r*r)
else.if d==0 then
=c
else
r=c/d
=d*sqrt(1+r*r)
end if
}
function clog {
c=this
c.vr<=ln(.cabs())
c.vi<=.Arg()
=c
}
function pow() {
if match("G") then
read p as Complex
else
read p1 as double
p=this:p.vr=p1:p.vi=0
end if
Read ? rr=10
exp=.clog()*p
c=exp.exp(rr)
c.vr=round(c.vr, rr)
c.vi=round(c.vi, rr)
=c
       }
function conj {
c=this : c.vi-! : =c
}
function absc {
c=this*.conj() : =sqrt(c.vr)
}
operator "+" {
read k as Complex : .vr+= k.vr : .vi+= k.vi
}
operator "-" {
read k as Complex : .vr-= k.vr : .vi-= k.vi
}
operator "*" {
read k as Complex
double ivr = .vr*k.vr-.vi*k.vi
.vi <= .vi*k.vr+.vr*k.vi
.vr <= ivr
}
operator "/" {
read k as Complex
k1=k*k.conj()
acb = this*k.conj()
.vr <= acb.vr/k1.vr
.vi <= acb.vi/k1.vr
}
class:
module Complex (.vr, .vi) {}
}
open filename for wide output as #f
r=Complex(1,1)
rr=r.pow(5)
Print #f, r.toString+"^5="+rr.toString
r=Complex(2,2)
rr=r.pow(6)
Print #f, r.toString+"^6="+ rr.toString
r=Complex(1, 1)
rr=r.pow(18)
Print #f, r.toString+"^18="+rr.toString
z=complex(2,1)
b=complex(3, -1)
r=z.pow(b)
Print #f, z.toString+"^"+b.toString+"="+r.toString
z=complex(221, -4)
b=complex(12, 3)
r=z.pow(b)
Print #f, z.toString+"^"+b.tostring+"="+r.toString
r=Complex(2.71828182845905)
b=Complex(0, pi)
z=r.pow(b)+complex(1)
Print #f, "e^(πi)+1 = "+z.toString
close #f
}
check "out.txt"
win "notepad", dir$+"out.txt"