Basic Math Operations
The following math functions are available in Smallworld Magik. These are useful to know because many spatial programming methods require some sort of calculation.
Addition
2 +3 = 5
Subtraction
2 –3 = -1
Multiplication
2 *3=6
Division
2 / 3= 2/3
4/2 = 2
Exponentiation
2**3=8
Division of whole numbers
21 _div 5 = 4
Remainder
21 _mod 5 = 1
Rounding
1.234.round(2) = 1.23
1.234.round(0) = 1
1.234.rounded = 1 (rounded returns nearest whole number)
Ceiling (smallest integer greater than _self)
1.2.ceiling = 2
Floor (largest whole number less than _self)
3.4.floor = 3
Negative & Positive
4.negative? = False
0-4.negative? = True
4.positive? = True
0-4.positive? = False
Absolute Value
(0-4).abs = 4
Force Float
2/3.as_float = 0.6666666667
Radians & Degrees
100.degrees_to_radians = 1.745329252
3.141892654.radians_to_degrees.rounded = 180
Greatest Common Divisor
15.gcd(25) = 5
100.gcd(75) = 25
Lowest Common Multiple
2.lcm(3) = 6
5.lcm(10) = 10
Hypotenuse (returns sqrt(_self*_self + other*other))
3.hypot(4) = 5
Inverse
5.inverse = 1/5
5.inverse.as_float = 0.2
Square Root
4.sqrt = 2
5.sqrt = 2.236067977
Integer Square Root
4.isqrt = 2
5.isqrt = 2
Log base 10 and Natural Log
5.ln = 1.609437912
5.log10 = 0.6989700043
Max & Min
3.min(7) = 3
3.max(7) = 7
Even & Odd
3.even? = False
3.odd? = True
Prime
3.prime? = True
4.prime? = False
There are some other mathematical functions available, including basic trigonometry functions as well as some basic calculus functions. Happy calculating.
Smallworld Magik is an object oriented language, so almost everything you deal with is an object. Some examples of objects:
- Integers (1, 13, 2008)
- Floating point (1.0, 3.1415, 2e3, 0.57721)
- Note: the e in 2e6 is 2x10^6, not 2*e^6 where e = Natural Logarithmic Base
- Note: 0.57721 works while .57721 will fail
- Character( %c, %l, %t)
- Note the % denotes a character object
There are a few special objects as well. The keywords _unset, _true, _false, and _maybe are all objects and can be treated as such.
The string “It’s the end of the world as we know it.” is actually an array of characters. Knowing this, we can treat it as a collection without having to parse the string. As objects, they can be compared with each other. This code returns the string in alphabetical order, with weight given to punctuation, and capitalization first. This is accomplished through Magik’s _cf comparison which evaluates characters based on their ASCII values.
Magik2> "".new_appending(_scatter sorted_collection.new_from("It's the end of the world as we know it.").as_simple_vector())$
" '.Iaddeeeefhhiklnnooorssttttwww"
Or reversed:
Magik2> "".new_appending(_scatter sorted_collection.new_from("It's the end of the world as we know it.").as_simple_vector()).reversed()$
"wwwttttssrooonnlkihhfeeeeddaI.' "
We create an empty string “” and append to it the result of the as_simple_vector method on the sorted collection we created from our string. Simplicity defined.
In the next example we create a string object and assign it to tmp1. We then assign the tmp1 to tmp2. In this case tmp1 and tmp2 don’t just have the same value, they are the same object.
Magik2> tmp1 << "Hello"$
"Hello"
Magik2> tmp2 << tmp1
$
"Hello"
This would not be true in the next case. Both tmp1 and tmp2 are assigned the same value, but they are not the same object.
Magik2> tmp1 << "Hello"$
"Hello"
Magik2> tmp2 << "Hello"
$
"Hello"
Final notes on the subject of objects:
- Variable assignment doesn’t copy, it references.
- Variable assignment is NOT strongly typed so you don’t need to declare it first, just assign a variable to an object, be it a number, a string, an array, a collection, or even a running application.
Variable Assignment
Assigning variables in Smallworld Magik can be accomplished with a simple construct known as the left chevron (<<). A simple variable assignment will look like this:
a << 7This expression states that the variable “a” becomes 10. More complicated expressions can also be expressed in this way.
b << 7 * a + 7or
c << (b-3).squaredVariables may be named almost anything you want, with the following constraints:
- Start with a-z, or !
- Contain a-z, 0-9, _, ?, !
- Unlimited length
- Case independent (sorry camelCase junkies)
Variables may also be assigned in serial or parallel. A series assignment might look like this:
a << b << c << 7This is the same as a << (b << (c << 1))
three << (two << (one << 1) +1) +1
Parallel variable assignment might look like this:
(a,b,c) << (1,2,3)(s,c) <<> <--this works because sincos() returns two values, sin and cos
There is a somewhat classic programmer problem for swapping two variables without using a temp variable. One of the many solutions being as follows:
a << a+bb << a-b
a << a-b
Smallworld Magik has a more elegant solution however, using a swapping assignment.
(a,b) << (b,a)Variable can be assigned inside other structures as well. A common use for this is to assign a variable during an if-then evaluation.
_if (z<< (x.squared + y.squared).sqrt) <= minimum_distance_then
write(“The value “,z,” is too small!”)
_endif
There are other variations to the left chevron that have their uses.
a +<<> will increment a by 1.
a -<<> will de-increment a by 1.
a *<<> will multiply a by 2.
a /<<> will divide a by 2.
A seldom used, but kind of interesting one is known as the boot assignment.
a << b ^<< 10This is the same as saying a <<> Essentially b becomes 10 and returns its original value which is in turn assigned to a.
One final note on Smallworld Magik variables is that developers tend to use longer names to describe most variables separated by an underscore (_) with the exception being when it is an iterated variable inside of a loop. The variable ‘e’ is used by many to indicate an element inside of a loop, while more permanent element references would be named an_element.
