Tes3Mod:Math Functions

The UESPWiki – Your source for The Elder Scrolls since 1995
Jump to: navigation, search

Overview[edit]

Morrowind comes with a very limited math library. By limited, we mean square root (GetSquareRoot) and distance (GetDistance) from one object to another (with some substantial limitations). Occasionally, there's a need for something more.

For anyone writing a script in a mod using MWSE, the basic trig functions are built in. So xArcTan is a simple extended function call. Degree/Radian conversions, Distance calculations, and the 6 basic trig functions. No power function though.

Ghan Buri Ghan's Scripting for Dummies mentions Soralis' Math Mod, available at Planet Elder Scrolls: Math Mod. This contains the following functions: SquareRoot Sine Cosine Tangent NaturalLog Log intPower intRoot Modulus Antiln Antilog AbsoluteValue Power

The math mod can either be included with your mod or you can use the scripts as a basis for your own.

LN by Taylor Expansion[edit]

LN can be expressed in a series similar to the SIN example, though it is slightly more complex:

x1 = ( Value - 1 ) / ( Value + 1 )
x3 = x1*x1*x1
x5 = x3*x1*x1
x7 = x5*x1*x1
x9 = x9*x1*x1

LNValue = 2 * ( x1 + x3/3 + x5/5 + x7/7 + x9/9 + ... )

You'd likely have to use more values than in the SIN case to get a similar accuracy (though I haven't checked). There are similar expansions for any trig/math function.

Modulo[edit]

Modulo gives you the remainder of division operation.

short divXY
float modXY
set divXY to ( X / Y )
set modXY to ( X - ( divXY * Y ) )

Sin/Cos Approximation[edit]

Here's a very simple example script which assumes the existence of 4 global floats: SinIN, SinOUT, CosIN, CosOUT. All the script does is take the sin of what's in SinIN and set SinOUT to the result, then take cos of what's in CosIN and set CosOUT to the result of that. It also prints out the results in a message box

begin SinScript

;Global float SinIN
;Global float SinOUT
;Global float CosIN
;Global float CosOUT

float IN
float OUT

short DEBUG

set IN to SinIN
;==================================================
;                                     Simple Sin
;                  By: Matt (Simpleton) Edlefsen
;               Remember to declare IN and OUT!!
;==================================================
while ( IN > 270 )
    set IN to IN - 360
endwhile
while ( IN < -90 )
    set IN to IN + 360
endwhile
if ( IN > 90 )
    set IN to 180 - IN
endif
set IN to IN * 3.14159265 / 180
set OUT to IN  * IN
set OUT to IN *  ( ( -0.16605 * OUT) + ( 0.00761 * OUT * OUT) + 1 )
;==================================================
if ( DEBUG == 1 )
    if ( OUT != SinOUT)
         MessageBox, "Sin(%.4f) = %.4f", SinIN, OUT
    endif
endif
set SinOUT to OUT

set IN to CosIN
; subtracting IN from 90 right before the sin will make it do cos instead
set IN to 90 - IN
;==================================================
;                                    Simple Sin
;                  By: Matt (Simpleton) Edlefsen
;              Remember to declare IN and OUT!!
;==================================================
while ( IN > 270 )
    set IN to IN - 360
endwhile
while ( IN < -90 )
    set IN to IN + 360
endwhile
if ( IN > 90 )
    set IN to 180 - IN
endif
set IN to IN * 3.14159265 / 180
set OUT to IN  * IN
set OUT to IN *  ( ( -0.16605 * OUT) + ( 0.00761 * OUT * OUT) + 1 )
;==================================================
if ( DEBUG == 1 )
    if ( OUT != CosOUT)
         MessageBox, "Cos(%.4f) = %.4f", CosIN, OUT
    endif
endif
set CosOUT to OUT

end

If you want to test it out, just make sure to have the 4 globals declared and add the script to the start scripts

Sin by Taylor Expansion[edit]

Sin/Cosine can be easily computed to a reasonable degree of accuracy using Taylor series (I did this really fast so ignore any obvious errors):

begin SinTaylor
float X
float X2
float X4
float X5
float X7
float X8
float X9
float SinResult
float Angle 
float Mult

set Angle to 45; Angle you want in degrees

; We get a few more digits accuracy with large angles if we do this...
if ( Angle >= 270 ) then
    set Angle to 360 - Angle
    set Mult to -1
else if ( Angle >= 180 ) then
    set Angle to 270 - Angle
    set Mult to -1
else if ( Angle >= 90 ) then
    set Angle to 180 - Angle
    set Mult to 1
else
    set Mult to 1
endif

set X to Angle / 57.2957792; Convert angle to radians
set X2 to X*X
set X4 to X2*X2
set X5 to X4*X
set X7 to X5*X2
set X8 to X4*X4
set X9 to X4*X4*X

set SinResult to X - X2*X/6 + X5/120 - X7/5040 + X9/362880 - X9*X2/39916800 + X9*X4/6227020800 - X8*X7/1.307674368e12
set SinResult to SinResult * Mult
end

This will give you a sin of any angle 0-360deg to at least 10 digits of accuracy. You can remove some of the end terms if you need less (really 3-4 digits is fine for most things you'd do in Morrowind anyways which means you can remove 3-4 terms).

Cos, Tan, ArcCin, SinH, exp, log etc... can be computed in a similar manner.