-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathTime.ele
112 lines (99 loc) · 4.29 KB
/
Time.ele
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#[[ TimeSpan objects store time using two Nums to gain increased precision
#
# It is not recommended to construct manually from the constructor, but instead
# to use a factory function such as "fromSeconds" if you need to create one.
#]]
struct TimeSpan(integer:Num, fractional:Num)
{
# Internally the integer component can be positive or negative,
# and the fractional component is a non-negative number between 0 and 1.
#
# The encoding of numbers is such that the stored number is equal to the integer member
# plus the fractional member.
# eg: value = this.integer.add(this.fractional)
#
# This applied to negative numbers too, so that
# eg: -0.75 is encoded as integer = -1, fractional = 0.25
#
# This makes addition and negation quick and easy. Multiplication is a little more difficult.
#[[ Create a TimeSpan from the specified number, in seconds ]]
fromSeconds(x:Num):TimeSpan = TimeSpan(x.floor, x.sub(x.floor))
#[[ Return the value of the TimeSpan, modulo one "period" ]]
value(this:TimeSpan, period:Num):Num = this.integer.rem(period).add(this.fractional).rem(period)
#[[ Return the integer number of elapsed periods ]]
cycles(this:TimeSpan, period:Num):Num = this.integer.div(period).add(this.fractional.div(period)).floor
#[[ Return the progress of the current time period. Between 0 and 1. ]]
progress(this:TimeSpan, period:Num):Num = this.value(period).div(period)
abs(this:TimeSpan):TimeSpan
{
return = if(this.integer.geq(0), this, this.negate)
}
negate(this:TimeSpan):TimeSpan
{
return = TimeSpan(this.integer.mul(-1).sub(1), 1.sub(this.fractional))._regularise
}
add(this:TimeSpan, other:TimeSpan):TimeSpan
{
return = TimeSpan(this.integer.add(other.integer), this.fractional.add(other.fractional))._regularise
}
sub(this:TimeSpan, other:TimeSpan):TimeSpan
{
return = this.add(other.negate)
}
mul(this:TimeSpan, x:Num):TimeSpan
{
# When we multiply by a number, the integer component of the TimeSpan can acquire
# a fractional part. For this reason we need a more complicated regularisation
# process in this case.
mi = this.integer.mul(x)
mf = this.fractional.mul(x)
# Separate the integer and fractional parts of the originally-integer input
miIntegerPart = mi.roundToZero
miFractionalPart = mi.sub(miIntegerPart)
# Add both known fractional-ish parts together
mfTotal = mf.add(miFractionalPart)
# Separate the integer and fractional parts of our remaining fractional-ish value
mfTotalIntegerPart = mfTotal.floor
mfTotalFractionalPart = mfTotal.sub(mfTotalIntegerPart)
# Collect all the integer parts and return
fullIntegerPart = miIntegerPart.add(mfTotalIntegerPart)
return = TimeSpan(fullIntegerPart, mfTotalFractionalPart)
}
div(this:TimeSpan, x:Num):TimeSpan
{
return = this.mul(1.div(x))
}
eq(a:TimeSpan, b:TimeSpan):Bool = Bool.and(a.integer.eq(b.integer), a.fractional.eq(b.fractional))
neq(a:TimeSpan, b:TimeSpan):Bool = not(eq(a, b))
lt(a:TimeSpan, b:TimeSpan):Bool
{
return = if(a.integer.lt(b.integer),
true,
if(a.integer.eq(b.integer),
a.fractional.lt(b.fractional),
false
)
)
}
leq(a:TimeSpan, b:TimeSpan):Bool
{
return = if(a.integer.lt(b.integer),
true,
if(a.integer.eq(b.integer),
a.fractional.leq(b.fractional),
false
)
)
}
gt(a:TimeSpan, b:TimeSpan):Bool = not(a.leq(b))
geq(a:TimeSpan, b:TimeSpan):Bool = not(a.lt(b))
_regularise(this:TimeSpan):TimeSpan
{
# Regularising a TimeSpan means ensuring that the fractional component is between 0 and 1,
# and adjusting the integer component appropriately.
#
# NOTE: This assumes that the integer part of the TimeSpan is an integer and does not have
# a fractional component.
return = TimeSpan(this.integer.add(this.fractional.floor), this.fractional.rem(1))
}
}