# [vJASS]Simple Math Functions

#### masterninja13579

Level 3
Here's a collection of useful math functions for vJASS. I looked around a bit and couldn't find a concise collection of them, so I decided to make my own and post it in case others find these useful. A few of the functions reflect existing functions in the WorldEditor but have been slightly rewritten to avoid the use of Locations.

Most of the functions contain relatively simple math that can just be substituted in place of a function call, but many of these functions can help make code more readable and easier to digest. Feel free to adjust or modify your own versions however you see fit.

vJASS:
``````/*
Collection of simple math functions involving real and integer types

Functions:
AngleXY         : Calculates the angle from (x1, y1) to (x2, y2)
DistanceXY      : Calculates the straight-line distance from (x1, y1) to (x2, y2)
PolarX          : Calculates a new X coordinate by moving it 'dist' units in 'angle' direction
PolarY          : Calculates a new Y coordinate by moving it 'dist' units in 'angle' direction
AbsR            : Calculates the absolute value for real numbers
AbsI            : Calculates the absolute value for integer numbers numbers
Round           : Rounds a real number to the nearest integer
Floor           : Takes a real value and returns the closest integer less than or equal to it
Ceiling         : Takes a real value and returns the closest integer greater than or equal to it
Mod             : Returns the modulus of two integer values
MinR            : Calculates the minimum of two real numbers
MaxR            : Calculates the maximum of two real numbers
MinI            : Calculates the minimum of two integer numbers
MaxI            : Calculates the maximum of two integer numbers
ClampR          : Restricts a real number between a minimum and maximum value
ClampI          : Restricts an integer number between a minimum and maximum value
ClampBetweenR   : Restricts a real number between two other real values.
ClampBetweenI   : Restricts an integer number between two other integer values.
Lerp            : Gives a linear interpolation between two real values based on a percentage input
InvLerp         : Gives the percentage input that would produce the desired value between two real values
Transform       : Takes a value between two numbers and returns a new value that is similarly positioned between two new numbers
*/

library Math
/*
AngleXY
Calculates the angle from (x1, y1) to (x2, y2)

An equivalent to AngleBetweenPoints that doesn't use location types
Coordinate order matters, so switching the order inverts the direction of the angle
*/
public function AngleXY takes real x1, real y1, real x2, real y2 returns real
return bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
endfunction

/*
DistanceXY
Calculates the straight-line distance from (x1, y1) to (x2, y2)

An equivalent to DistanceBetweenPoints that doesn't use location types
*/
public function DistanceXY takes real x1, real y1, real x2, real y2 returns real
local real dx = x2 - x1
local real dy = y2 - y1
return SquareRoot(dx * dx + dy * dy)
endfunction

/*
PolarX
Calculates a new X coordinate by moving it 'dist' units in 'angle' direction

A partial equivalent to PolarProjectionBJ that doesn't use location types
*/
public function PolarX takes real x, real dist, real angle returns real
return x + dist * Cos(angle * bj_DEGTORAD)
endfunction

/*
PolarY
Calculates a new Y coordinate by moving it 'dist' units in 'angle' direction

A partial equivalent to PolarProjectionBJ that doesn't use location types
*/
public function PolarY takes real y, real dist, real angle returns real
return y + dist * Sin(angle * bj_DEGTORAD)
endfunction

/*
AbsR
Calculates the absolute value for real numbers

Examples:
AbsR(1.5) gives a value of 1.5
AbsR(-1.5) gives a value of 1.5
*/
public function AbsR takes real value returns real
if (value < 0) then
return value * -1.0
endif
return value
endfunction

/*
AbsI
Calculates the absolute value for integer numbers numbers

Examples:
AbsI(2) gives a value of 2
AbsI(-2) gives a value of 2
*/
public function AbsI takes integer value returns integer
if (value < 0) then
return value * -1
endif
return value
endfunction

/*
Round
Rounds a real number to the nearest integer
*/
public function Round takes real value returns integer
return R2I(value + 0.5)
endfunction

/*
Floor
Takes a real value and returns the closest integer less than or equal to it
*/
public function Floor takes real value returns integer
return R2I(value)
endfunction

/*
Ceiling
Takes a real value and returns the closest integer greater than or equal to it
*/
public function Ceiling takes real value returns integer
local integer result = R2I(value)
if (I2R(result) == value) then
return result
endif
return result + 1
endfunction

/*
Mod
Returns the modulus of two integer values

The modulus is the remainder after division takes place

Examples:
Mod(3, 3) gives a value of 0
Mod(4, 3) gives a value of 1
Mod(5, 3) gives a value of 2
Mod(6, 3) gives a value of 0
Mod(7, 3) gives a value of 1
Mod(8, 3) gives a value of 2
*/
public function Mod takes integer value, integer divisor returns integer
return value - (value / divisor) * divisor
endfunction

/*
MinR
Calculates the minimum of two real numbers

Examples:
MinR(1.5, 2.5) gives a value of 1.5
MinR(-3.0, 1.0) gives a value of -3.0
*/
public function MinR takes real a, real b returns real
if (a < b) then
return a
else
return b
endif
endfunction

/*
MaxR
Calculates the maximum of two real numbers

Examples:
MaxR(1.5, 2.5) gives a value of 2.5
MaxR(-3.0, 1.0) gives a value of 1.0
*/
public function MaxR takes real a, real b returns real
if (a < b) then
return b
else
return a
endif
endfunction

/*
MinI
Calculates the minimum of two integer numbers

Examples:
MinI(1, 2) gives a value of 1
MinI(-3, 1) gives a value of -3
*/
public function MinI takes integer a, integer b returns integer
if (a < b) then
return a
else
return b
endif
endfunction

/*
MaxI
Calculates the maximum of two integer numbers

Examples:
MaxI(1, 2) gives a value of 2
MaxI(-3, 1) gives a value of 1
*/
public function MaxI takes integer a, integer b returns integer
if (a < b) then
return b
else
return a
endif
endfunction

/*
ClampR
Restricts a real number between a minimum and maximum value

Examples:
ClampR(1.0, 2.0, 4.0) gives a value of 2.0
ClampR(2.0, 2.0, 4.0) gives a value of 2.0
ClampR(3.0, 2.0, 4.0) gives a value of 3.0
ClampR(4.0, 2.0, 4.0) gives a value of 4.0
ClampR(5.0, 2.0, 4.0) gives a value of 4.0
*/
public function ClampR takes real value, real min, real max returns real
return MaxR(MinR(value, max), min)
endfunction

/*
ClampI
Restricts an integer number between a minimum and maximum value

Examples:
ClampI(1, 2, 4) gives a value of 2
ClampI(2, 2, 4) gives a value of 2
ClampI(3, 2, 4) gives a value of 3
ClampI(4, 2, 4) gives a value of 4
ClampI(5, 2, 4) gives a value of 4
*/
public function ClampI takes integer value, integer min, integer max returns integer
return MaxI(MinI(value, max), min)
endfunction

/*
ClampBetweenR
Restricts a real number between two other real values.

This version doesn't require you to sort your min and max values

Examples:
ClampBetweenR(1.0, 4.0, 2.0) gives a value of 2.0
ClampBetweenR(2.0, 4.0, 2.0) gives a value of 2.0
ClampBetweenR(3.0, 4.0, 2.0) gives a value of 3.0
ClampBetweenR(4.0, 4.0, 2.0) gives a value of 4.0
ClampBetweenR(5.0, 4.0, 2.0) gives a value of 4.0
*/
public function ClampBetweenR takes real value, real first, real second returns real
local real min = MinR(first, second)
local real max = MaxR(first, second)
return ClampR(value, min, max)
endfunction

/*
ClampBetweenI
Restricts an integer number between two other integer values.

This version doesn't require you to sort your min and max values

Examples:
ClampBetweenI(1, 4, 2) gives a value of 2
ClampBetweenI(2, 4, 2) gives a value of 2
ClampBetweenI(3, 4, 2) gives a value of 3
ClampBetweenI(4, 4, 2) gives a value of 4
ClampBetweenI(5, 4, 2) gives a value of 4
*/
public function ClampBetweenI takes integer value, integer first, integer second returns integer
local integer min = MinI(first, second)
local integer max = MaxI(first, second)
return ClampI(value, min, max)
endfunction

/*
Lerp
Gives a linear interpolation between two real values based on a percentage input

A percentage value of 0.0 gives the first number.
A percentage value of 1.0 gives the second number.
A percentage value of 0.5 gives a value halfway between first and second

The percentage can be outside 0.0-1.0 if desired

Examples:
Lerp(4.0, 8.0, 0.00) gives a value of 4.0
Lerp(4.0, 8.0, 0.25) gives a value of 5.0
Lerp(4.0, 8.0, 0.50) gives a value of 6.0
Lerp(4.0, 8.0, 0.75) gives a value of 7.0
Lerp(4.0, 8.0, 1.00) gives a value of 8.0
*/
public function Lerp takes real first, real second, real percent returns real
return first + (second - first) * percent
endfunction

/*
InvLerp (Inverse Lerp)
Gives the percentage input that would produce the desired value between two real values

Examples:
InvLerp(4.0, 8.0, 4.0) gives a value of 0.00 (0%)
InvLerp(4.0, 8.0, 5.0) gives a value of 0.25 (25%)
InvLerp(4.0, 8.0, 6.0) gives a value of 0.50 (50%)
InvLerp(4.0, 8.0, 7.0) gives a value of 0.75 (75%)
InvLerp(4.0, 8.0, 8.0) gives a value of 1.00 (100%)
*/
public function InvLerp takes real first, real second, real value returns real
return (value - first) / (second - first)
endfunction

/*
Transform
Takes a value between two numbers and returns a new value that is similarly positioned between two new numbers

Input value does not strictly need to be between the first and second numbers

Examples:
Take a number between 2.0 and 4.0 and transform it to a number between 100.0 and 150.0
Transform(2.0, 2.0, 4.0, 100.0, 150.0)   gives a value of 100.0
Transform(2.5, 2.0, 4.0, 100.0, 150.0)   gives a value of 112.5
Transform(3.0, 2.0, 4.0, 100.0, 150.0)   gives a value of 125.0
Transform(3.5, 2.0, 4.0, 100.0, 150.0)   gives a value of 137.5
Transform(4.0, 2.0, 4.0, 100.0, 150.0)   gives a value of 150.0

An AOE spell of range 500 that deals more damage the closer you are to the center.
Let's say the damage at the center is 150 and the damage at the edge is 50
The distance from the center would be the input
damage = Transform(distance, maxAOE, minAOE, minDamage, maxDamage)

Transform(  0.0, 500.0, 0.0, 50.0, 150.0)   gives a value of 150.0 damage
Transform(100.0, 500.0, 0.0, 50.0, 150.0)   gives a value of 130.0 damage
Transform(200.0, 500.0, 0.0, 50.0, 150.0)   gives a value of 110.0 damage
Transform(300.0, 500.0, 0.0, 50.0, 150.0)   gives a value of  90.0 damage
Transform(400.0, 500.0, 0.0, 50.0, 150.0)   gives a value of  70.0 damage
Transform(500.0, 500.0, 0.0, 50.0, 150.0)   gives a value of  50.0 damage
*/
public function Transform takes real value, real first, real second, real newFirst, real newSecond returns real
return Lerp(newFirst, newSecond, InvLerp(first, second, value))
endfunction
endlibrary``````

Last edited:

#### Bribe

Code Moderator
Level 50
Approved as a repository that can be potentially instructive. Users might not be aware of how to inline coordinate math or that R2I floors the values rather than rounds them.

#### Tristronic

Level 12
These are two I added to my math library, I'm definitely going to start using some of these.

I'm also curious if these two I'm throwing out there seem viable to others (or if there are similar functions I am unaware of)

They aren't really math, but I consider them math-y enough...
JASS:
``````public function I2B takes integer i returns boolean
if i == 0 then
return false
endif
return true
endfunction

public function B2I takes boolean b returns integer
if b == true then
return 1
endif
return 0
endfunction``````

JASS:
``````// after hearing Bribe's response I realize how unnecessary this function is
public function I2B takes integer i returns boolean
return i != 0
endfunction

public function B2I takes boolean b returns integer
if b then
return 1
endif
return 0
endfunction``````

Last edited:

#### Tristronic

Level 12
Right, thank you!
I'll keep that in mind for better/ more concise code.

It is rare, but I've found some cases where I would like to use a boolean in my math to apply a shift, a recent example was using collision sizes and accounting for the offset of some sizes (units of size 16.00-31.99, and 48.00-1024.00 are not centered on their 'collision map')
There are several ways I could have done it, (in hindsight I could just divide by 16 and come up with something like:
Code:
``````e=R2I((size)/16)
X + (1+(-1)^e)/2``````
But then for numbers between 48.00-1024.00 (or whatever the max may be) the pattern doesn't follow and units don't actually get any 'bigger', so the equation fails, so in the past I opted for a boolean-like integer, setting an integer to either 0 or 1 to circumvent this.

The I2B function seems a little useless now, since any time I might need a boolean I might as well just check.

I'm still learning many tricks of the trade though, so I'm all ears if I'm missing something that would save me trouble/ be better than what I'm doing.

Level 23
JASS:
``````public function Round takes real value returns integer
return R2I(value + 0.5)
endfunction``````
There are rounding issues using your prescribed function. There is a thread that gets into it here.
Jass has a function named MathRound, that rounds numbers. Not many people know about it, so I recommend replacing your function with it, or at least make it a wrapper.

Replies
22
Views
4K
Replies
37
Views
6K
Replies
35
Views
5K
Replies
29
Views
5K
Replies
12
Views
2K