- Joined
- Sep 26, 2009
- Messages
- 9,534
JASS:
library Fractions
//===========================================================================
// Created by Bribe. Largely based on the "fractions" module used in Python.
// It allows you to do things like:
//
// call Fraction(1, 2).add(Fraction(3, 2)).print(5.00)
//
// Which displays the message "Fraction(2, 1)" for 5 seconds. "Fractions"
// allows you to do math without the imprecision of real numbers, and auto-
// matically simplifies results ((3, 12) becomes (1, 4)).
//
//=======================================================================
// Returns 0.14 from 3.14. Its purpose is to get the right-side of the
// decimal point of a real number.
//
function GetRemainder takes real r returns real
return r - R2I(r)
endfunction
//=======================================================================
// Returns 2 for 10; 4 for 1000. Its purpose is to find out how many
// digits are in a given integer.
//
function CountDigits takes integer i returns integer
return StringLength(I2S(i))
endfunction
//=======================================================================
// Turns 0.15 (with p == 2) into 15. Its purpose is to swap imprecise
// real numbers into workable integers.
//
function PromoteReal takes real r, integer p returns integer
return R2I(r * Pow(10, p))
endfunction
//=======================================================================
// Turns 15 into 0.15; 165 into 0.165. Its purpose is to reverse the
// effects of PromoteReal.
//
function DemoteInteger takes integer i returns real
return i / Pow(10, CountDigits(i))
endfunction
//=======================================================================
// Returns true for 1.00, false for 3.14. Its purpose is to determine
// if a real number is also a rational number.
//
function IsRational takes real r returns boolean
return r * 10000 == 0
endfunction
//=======================================================================
// Rounds 1.2 to 1, 1.7 to 2. Its purpose is to not simply truncate reals
// vith R2I, but to also round the number if its remainder is higher than
// 0.50.
//
function Real2Int takes real r returns integer
if r > 0 then
return R2I(r + 0.50)
endif
return R2I(r - 0.50)
endfunction
//=======================================================================
// Finds the greatest-common-denominator for a fraction to be simplified
// into.
//
public function GCD takes integer a, integer b returns integer
local integer a2
loop
exitwhen b == 0
set a2= a
set a = b
set b = ModuloInteger(a2, b)
endloop
return a
endfunction
struct fraction
readonly integer num // numerator
readonly integer den // denominator
//===================================================================
// f.reset(1, 2) resets the numerator and denominator to whatever you
// want.
//
method reset takes integer a, integer b returns thistype
local integer d = GCD(a, b)
if (d != 0) then
set num = a / d
set den = b / d
else
set num = 0
set den = 1
endif
return this
endmethod
//===================================================================
// f = fraction.create(1, 2) creates a new fraction instance with the
// first value as the numerator, the second as the denominator.
//
static method create takes integer num, integer den returns thistype
return thistype.allocate().reset(num, den)
endmethod
//===================================================================
// f.product() returns 0.50. This is useful when you need a real num-
// ber as a parameter.
//
method product takes nothing returns real
return (num + 0.) / den
endmethod
//===================================================================
// f2 = f.copy() returns a new fraction instance with the same num-
// erator and denominator as f.
//
method copy takes nothing returns thistype
return thistype.create(num, den)
endmethod
//===================================================================
// Fraction(1, 3).add(Fraction(1, 3)) makes Fraction(2, 3).
//
method add takes thistype f returns thistype
return this.reset((this.num * f.den) + (this.den * f.num), (this.den * f.den))
endmethod
//===================================================================
// Fraction(2, 3).subtract(Fraction(1, 3)) makes Fraction(1, 3).
//
method subtract takes thistype f returns thistype
return this.reset((this.num * f.den) - (this.den * f.num), (this.den * f.den))
endmethod
//===================================================================
// Fraction(1, 2).multiply(Fraction(2, 3)) makes Fraction(1, 3).
//
method multiply takes thistype f returns thistype
return this.reset(this.num * f.num, this.den * f.den)
endmethod
//===================================================================
// Fraction(3, 4).divide(Fraction(4, 5)) makes Fraction(15, 16).
//
method divide takes thistype f returns thistype
return this.reset(this.num * f.den, this.den * f.num)
endmethod
//===================================================================
// f.eq(f2) returns true if the numerator and denominator are the
// same for both f and f2.
//
method eq takes thistype f returns boolean
return this.num == f.num and this.den == f.den
endmethod
//===================================================================
// f.gt(f2) returns true if f is greater than f2.
//
method gt takes thistype f returns boolean
return this.num * f.den > f.num * this.den
endmethod
//===================================================================
// f.lt(f2) returns true if f is less than f2.
//
method lt takes thistype f returns boolean
return this.num * f.den < f.num * this.den
endmethod
//===================================================================
// f.print(5.00) displays Fraction(1, 2) for 5 seconds, useful for
// debugging or for playing around with some math.
//
method print takes real duration returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.00, 0.00, duration, "Fraction(" + I2S(num) + ", " + I2S(den) + ")")
endmethod
//===================================================================
// Turns "10" into Fraction(10, 1). Easy way to convert an integer to
// a fraction.
//
static method fromint takes integer i returns thistype
return thistype.create(i, 1)
endmethod
//===================================================================
// Turns "0.5" (with p==1) into Fraction(1, 2). Easy way to convert a
// real number into a fraction. "p" is the amount of precision to
// check on the right side of the floating point. A low "p" produces
// more simplified fractions than a high "p".
//
static method fromreal takes real r, integer p returns thistype
set p = R2I(Pow(10, p))
return thistype.create(R2I(r * p), p)
endmethod
endstruct
globals
private timer g_timer = CreateTimer()
private integer g_size = 0
private fraction array a_list
endglobals
//=======================================================================
// Auto-destroys fraction instances created with "Fraction(1, 2)".
//
private function Recycle takes nothing returns nothing
local integer i = 0
loop
call a_list[i].destroy()
set i = i + 1
exitwhen i == g_size
endloop
set g_size = 0
endfunction
//=======================================================================
// Returns a temporary fraction, great for numers you only need for a
// single instance. f.add(Fraction(1, 2)) is an ideal way to use it.
//
function Fraction takes integer num, integer den returns fraction
local fraction f = fraction.create(num, den)
set a_list[g_size] = f
set g_size = g_size + 1
call TimerStart(g_timer, 0.00, false, function Recycle)
return f
endfunction
endlibrary
Last edited: