Skip to content

Mafs (class)

vmathmachine edited this page May 22, 2022 · 2 revisions

The Mafs class was created to add certain mathematical functions and constants that aren't there by default which are necessary or helpful in the code for complex numbers.

To read my official documentation on the fields and methods in Mafs, please see the reference javadocs included with the Complex Number Library. You can access these by opening Processing, then at the top of the window, click Help -> Libraries Reference -> Complex Numbers (assuming you have the Complex Number Library downloaded). Then, from there, press the link to "Mafs". You do not need an internet connection for this to work. :) Alternatively, if you want to access them manually, you can simply go into your Processing sketchbook folder, then open libraries -> ComplexNumberLibrary -> reference -> complexnumbers -> Mafs.html.

Fields

All fields written in Mafs are final, public, and static. That means you cannot change them, you can read them, and you do not need to declare an instance of Mafs to access them. In fact, everything in Mafs is static, so there is no need whatsoever to declare an instance of it.

The fields implemented are all basic mathematical constants, such as π/2, √(2), ∞, ln(2), ln(π), √(π)/2, and γ (the Euler-Mascheroni constant), each double precision floating points (doubles). While not all of these constants are necessarily something you'd use often, they are important for the implementation of this library. ln(2), for instance, allows us to compute the cosh and sinh functions in the special case that e^x overflows, yet (e^x)/2 doesn't. In this situation, we simply subtract ln(2) from x and calculate the exponential.

Methods

String Methods

Two functions were created for the sole purpose of string conversion. One casts a double to a string with a certain number of significant digits, the other casts a double to a string with the default accuracy. Both of them remove all leading 0s and unnecessary decimal points (i.e. 2.0 becomes 2). Another function, named "unsplice", removes a substring from the middle of a given string. It was created solely for the purpose of the other two functions (namely when the result is in scientific notation), but I see no reason why you can't use it for other things.

Sign Based Functions

The sgn and csgn functions were created mostly for the utility of the complex number library. The sgn function is officially defined to return 1 if the input is +, -1 if it's -, 0 if it's 0. The csgn function returns 1 if the input is >=0, -1 if it's <0. These functions are also defined in the Complex class, where their inputs are complex rather than real, but those are a bit more complicated.

Trigonometry

Variations of the built-in Math.sin, Math.cos, and Math.tan functions are built into Mafs as Mafs.sin, Mafs.cos, and Mafs.tan. They basically do the exact same thing as those functions, but first, they perform a test: If the input is a multiple of π, sin and tan return 0. If the input is an odd multiple of π/2, cos returns 0 and tan returns ∞.

You see, if you try computing Math.sin(Math.PI), you won't get 0 like you'd expect. You'll get 1.224646799147E-16. Technically, it's not the computer that's wrong, it's the input that's wrong. Because Math.PI is not (nor could it ever be) exactly equal to π, the sine function is basically returning the sine of that number that's slightly different than π. This is the same reason for the slight imprecision on cosine and tangent. So, while it is technically more accurate this way, in some cases, it's not exactly helpful. So, I've written these variations to help in those situations where you wouldn't want it to be technically more accurate. For instance, if you create a function that's supposed to return sin(πx), you'd want it to return 0 for all integer values of x.

Two things should be noted, however: First of all, since the modulo operation isn't exactly trivial, these functions are slightly more computationally expensive than their Math counterparts. Second of all, all functions in this library that require cosine, sine, and tangent utilize these implementations rather than the implementations used in Math. Again, this is to avoid imprecision. You'd want (-1)^(0.5) to evaluate to i, not 6.123233995737E-17+i.

There's also another trigonometric function implemented, fsinhcosh. Inspired by the FSINCOS function that many assembly level languages use, this takes some double "d" and computes its sinh and cosh simultaneously. It does so by first dealing with some special cases (such as underflow or overflow). Then, it calculates e^d. Then the reciprocal of e^d. Then, using cosh(x)=(e^x+e^-x)/2 and sinh(x)=(e^x-e^-x)/2, it returns an array containing {sinh(d), cosh(d)}.

Other

The method factorial takes an integer input and returns a long output. The output, as you can guess, is the factorial function. Computed via repeated multiplication. If the input overflows, the result will be the LONG floating point limit. If the input is negative, it'll do the same thing. Even though, I suppose, what it should really do is throw an ArithmeticException since what we're doing there is dividing by 0.

The method pow returns a double raised to an integer power. It does this through what is known as Exponentiation by squaring, which other people can explain much better than me. Long story short, it's fast.

The method modPos is a variation of the modulo where the output is pretty much never negative. (There's a slight exception to that rule, but it's logical and will be explained later). The modulo % operation in java does what is known as truncated division where the output is negative if the dividend is negative, and positive if the dividend is positive. Unfortunately, I myself have never, ever, ever, ever, ever run into a situation where this definition was preferable. So, I created this function to return the more desirable (for me anyway) version of the modulo, whereby the remainder is always between 0 and d2 (range = [0,d2)). I just find it to be more consistent this way.

However, as I mentioned, there is a slight caveat. While modulo operations rarely ever have a negative divisor, in the rare case they do, it's preferable for the output to be negative. In other words, it's preferable for the output to still be between 0 and d2, although now the range is (d2,0]. However, despite this caveat, this is a rare scenario, and thus I still stuck with the name modPos, because it's almost always positive.

Clone this wiki locally