line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# $Id: Calc.pm 3606 2007-02-04 13:34:09Z lestrrat $ |
2
|
|
|
|
|
|
|
# |
3
|
|
|
|
|
|
|
# Copyright (c) 2004-2007 Daisuke Maki <daisuke@endeworks.jp> |
4
|
|
|
|
|
|
|
# All rights reserved. |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package DateTime::Util::Calc; |
7
|
8
|
|
|
8
|
|
448850
|
use strict; |
|
8
|
|
|
|
|
11
|
|
|
8
|
|
|
|
|
271
|
|
8
|
8
|
|
|
8
|
|
34
|
use warnings; |
|
8
|
|
|
|
|
11
|
|
|
8
|
|
|
|
|
246
|
|
9
|
8
|
|
|
8
|
|
31
|
use Carp qw(carp); |
|
8
|
|
|
|
|
13
|
|
|
8
|
|
|
|
|
411
|
|
10
|
8
|
|
|
8
|
|
6066
|
use DateTime; |
|
8
|
|
|
|
|
2779444
|
|
|
8
|
|
|
|
|
377
|
|
11
|
8
|
|
|
8
|
|
8747
|
use Math::BigInt ('upgrade' => 'Math::BigFloat'); |
|
8
|
|
|
|
|
164800
|
|
|
8
|
|
|
|
|
43
|
|
12
|
8
|
|
|
8
|
|
157398
|
use Math::BigFloat ('lib' => 'GMP,Pari'); |
|
8
|
|
|
|
|
170324
|
|
|
8
|
|
|
|
|
49
|
|
13
|
8
|
|
|
8
|
|
13091
|
use Math::Trig (); |
|
8
|
|
|
|
|
77635
|
|
|
8
|
|
|
|
|
226
|
|
14
|
8
|
|
|
8
|
|
79
|
use POSIX(); |
|
8
|
|
|
|
|
12
|
|
|
8
|
|
|
|
|
246
|
|
15
|
|
|
|
|
|
|
|
16
|
8
|
|
|
8
|
|
39
|
use constant RATA_DIE => DateTime->new(year => 1, time_zone => 'UTC'); |
|
8
|
|
|
|
|
11
|
|
|
8
|
|
|
|
|
69
|
|
17
|
|
|
|
|
|
|
|
18
|
8
|
|
|
8
|
|
5139
|
use vars qw($VERSION @EXPORT_OK @ISA); |
|
8
|
|
|
|
|
14
|
|
|
8
|
|
|
|
|
528
|
|
19
|
8
|
|
|
8
|
|
32
|
use vars qw($DOWNGRADE_ACCURACY); |
|
8
|
|
|
|
|
7
|
|
|
8
|
|
|
|
|
588
|
|
20
|
|
|
|
|
|
|
BEGIN |
21
|
|
|
|
|
|
|
{ |
22
|
8
|
|
|
8
|
|
15
|
$VERSION = '0.12'; |
23
|
8
|
|
|
|
|
73
|
@ISA = qw(Exporter); |
24
|
8
|
|
|
|
|
40
|
@EXPORT_OK = qw( |
25
|
|
|
|
|
|
|
bf_downgrade |
26
|
|
|
|
|
|
|
bi_downgrade |
27
|
|
|
|
|
|
|
binary_search |
28
|
|
|
|
|
|
|
search_next |
29
|
|
|
|
|
|
|
angle |
30
|
|
|
|
|
|
|
polynomial |
31
|
|
|
|
|
|
|
sin_deg |
32
|
|
|
|
|
|
|
cos_deg |
33
|
|
|
|
|
|
|
tan_deg |
34
|
|
|
|
|
|
|
asin_deg acos_deg mod amod min |
35
|
|
|
|
|
|
|
max bigfloat bigint moment dt_from_moment rata_die |
36
|
|
|
|
|
|
|
truncate_to_midday |
37
|
|
|
|
|
|
|
revolution |
38
|
|
|
|
|
|
|
rev180 |
39
|
|
|
|
|
|
|
); |
40
|
|
|
|
|
|
|
|
41
|
8
|
|
|
|
|
7965
|
$DOWNGRADE_ACCURACY = 32; |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
|
44
|
0
|
|
|
0
|
1
|
0
|
sub rata_die { RATA_DIE->clone } |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
sub bigfloat |
47
|
|
|
|
|
|
|
{ |
48
|
|
|
|
|
|
|
return |
49
|
0
|
0
|
|
0
|
1
|
0
|
UNIVERSAL::isa($_[0], 'Math::BigFloat') ? $_[0] : |
50
|
|
|
|
|
|
|
Math::BigFloat->new($_[0]); |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
sub bigint |
54
|
|
|
|
|
|
|
{ |
55
|
0
|
0
|
|
0
|
1
|
0
|
return UNIVERSAL::isa($_[0], 'Math::BigInt') ? $_[0] : Math::BigInt->new($_[0]); |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
my $warn_bf_downgrade = 0; |
59
|
|
|
|
|
|
|
my $warn_bi_downgrade = 0; |
60
|
|
|
|
|
|
|
sub bf_downgrade |
61
|
|
|
|
|
|
|
{ |
62
|
0
|
0
|
|
0
|
1
|
0
|
$warn_bf_downgrade++ or carp "DateTime::Util::Calc::bf_downgrade has been deprecated, and will be removed in future versions."; |
63
|
0
|
|
|
|
|
0
|
return $_[0]; |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub bi_downgrade |
67
|
|
|
|
|
|
|
{ |
68
|
0
|
0
|
|
0
|
1
|
0
|
$warn_bi_downgrade++ or carp "DateTime::Util::Calc::bi_downgrade has been deprecated, and will be removed in future versions."; |
69
|
0
|
|
|
|
|
0
|
return $_[0]; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub angle |
73
|
|
|
|
|
|
|
{ |
74
|
0
|
|
|
0
|
1
|
0
|
Math::BigFloat->new($_[0]) + (Math::BigFloat->new($_[1]) + (Math::BigFloat->new($_[2]) / 60)) / 60; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# polynomial($x, $a(0) ... $a(n)) |
78
|
|
|
|
|
|
|
sub polynomial |
79
|
|
|
|
|
|
|
{ |
80
|
3
|
50
|
|
3
|
1
|
1178
|
if (@_ == 1) { |
81
|
0
|
|
|
|
|
0
|
require Carp; |
82
|
0
|
|
|
|
|
0
|
Carp::croak('polynomial requires at least two arguments: polynomial($x, @coeffients)'); |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# XXX - There seems to be a bug in adding BigInt and BigFloat |
86
|
|
|
|
|
|
|
# Math::BigFloat->bzero must be used |
87
|
3
|
|
|
|
|
18
|
my $x = Math::BigFloat->new(shift @_); |
88
|
3
|
|
|
|
|
317
|
my $v = Math::BigFloat->bzero(); |
89
|
3
|
|
|
|
|
54
|
my $ret = Math::BigFloat->new(shift @_); |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
# reuse $v for sake of efficiency. we just want to check if $x |
92
|
|
|
|
|
|
|
# is zero or not |
93
|
3
|
100
|
|
|
|
153
|
if ($x == $v) { |
94
|
1
|
|
|
|
|
35
|
return $ret; |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
2
|
|
|
|
|
171
|
while (@_) { |
98
|
5
|
|
|
|
|
853
|
$v = $x * ($v + pop @_); |
99
|
|
|
|
|
|
|
} |
100
|
2
|
|
|
|
|
547
|
return $ret + $v; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub deg2rad |
104
|
|
|
|
|
|
|
{ |
105
|
5
|
50
|
|
5
|
0
|
12
|
my $deg = ref($_[0]) ? $_[0]->bstr() : $_[0]; |
106
|
5
|
50
|
|
|
|
21
|
return Math::Trig::deg2rad($deg > 360 ? $deg % 360 : $deg); |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
2
|
|
|
2
|
1
|
544
|
sub sin_deg { CORE::sin(deg2rad($_[0])) } |
110
|
2
|
|
|
2
|
1
|
1389
|
sub cos_deg { CORE::cos(deg2rad($_[0])) } |
111
|
1
|
|
|
1
|
1
|
433
|
sub tan_deg { Math::Trig::tan(deg2rad($_[0])) } |
112
|
|
|
|
|
|
|
sub asin_deg |
113
|
|
|
|
|
|
|
{ |
114
|
1
|
50
|
|
1
|
1
|
16
|
my $v = ref($_[0]) ? $_[0]->bstr() : $_[0]; |
115
|
1
|
|
|
|
|
6
|
return Math::Trig::rad2deg(Math::Trig::asin($v)); |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub acos_deg |
119
|
|
|
|
|
|
|
{ |
120
|
1
|
50
|
|
1
|
1
|
10
|
my $v = ref($_[0]) ? $_[0]->bstr() : $_[0]; |
121
|
1
|
|
|
|
|
5
|
Math::Trig::rad2deg(Math::Trig::acos($v)); |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
sub mod |
125
|
|
|
|
|
|
|
{ |
126
|
12
|
|
|
12
|
1
|
1237
|
my $fraction = 0; |
127
|
12
|
|
|
|
|
12
|
my $modulus = 0; |
128
|
12
|
100
|
|
|
|
19
|
if (ref($_[0])) { |
129
|
2
|
|
|
|
|
9
|
$modulus = $_[0]->babs->bmod($_[1]); |
130
|
|
|
|
|
|
|
} else { |
131
|
10
|
|
|
|
|
14
|
$fraction = abs(abs($_[0]) - abs(int($_[0]))); |
132
|
10
|
|
|
|
|
16
|
$modulus = int($_[0]) % $_[1]; |
133
|
|
|
|
|
|
|
} |
134
|
12
|
|
|
|
|
722
|
return $modulus + $fraction; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
3
|
100
|
|
3
|
1
|
8
|
sub amod { mod($_[0], $_[1]) || $_[1]; } |
138
|
3
|
50
|
|
3
|
1
|
88
|
sub min { $_[0] > $_[1] ? $_[1] : $_[0] } |
139
|
3
|
100
|
|
3
|
1
|
15
|
sub max { $_[0] < $_[1] ? $_[1] : $_[0] } |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
sub moment |
142
|
|
|
|
|
|
|
{ |
143
|
0
|
|
|
0
|
1
|
0
|
my $dt = shift; |
144
|
0
|
|
|
|
|
0
|
my($rd, $seconds) = $dt->utc_rd_values; |
145
|
0
|
|
|
|
|
0
|
return $rd + $seconds / (24 * 3600); |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
sub dt_from_moment |
149
|
|
|
|
|
|
|
{ |
150
|
0
|
|
|
0
|
1
|
0
|
my $moment = Math::BigFloat->new(shift); |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
# Truncate the moment down to an int |
153
|
0
|
|
|
|
|
0
|
my $rd_days = $moment->as_int(); |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# Upgrade here to BigFloat to maintain accuracy to the second |
156
|
0
|
|
|
|
|
0
|
my $time = ($moment - $rd_days) * 24 * 3600; |
157
|
0
|
|
|
|
|
0
|
my $dt = rata_die(); |
158
|
|
|
|
|
|
|
|
159
|
0
|
0
|
0
|
|
|
0
|
if ($rd_days || $time) { |
160
|
0
|
|
|
|
|
0
|
$dt->add( |
161
|
|
|
|
|
|
|
days => ($rd_days - 1)->bstr(), |
162
|
|
|
|
|
|
|
seconds => $time->as_int()->bstr(), |
163
|
|
|
|
|
|
|
); |
164
|
0
|
|
|
|
|
0
|
$dt->truncate(to => 'second'); |
165
|
|
|
|
|
|
|
} |
166
|
0
|
|
|
|
|
0
|
return $dt; |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub binary_search |
171
|
|
|
|
|
|
|
{ |
172
|
0
|
|
|
0
|
1
|
0
|
my ($lo, $hi, $mu, $phi) = @_; |
173
|
|
|
|
|
|
|
|
174
|
0
|
|
|
|
|
0
|
$lo = Math::BigFloat->new($lo); |
175
|
0
|
|
|
|
|
0
|
$hi = Math::BigFhiat->new($hi); |
176
|
|
|
|
|
|
|
|
177
|
0
|
|
|
|
|
0
|
while (1) { |
178
|
0
|
|
|
|
|
0
|
my $x = ($lo + $hi) / 2; |
179
|
0
|
0
|
|
|
|
0
|
if ($mu->($lo, $hi)) { |
|
|
0
|
|
|
|
|
|
180
|
0
|
|
|
|
|
0
|
return $x; |
181
|
|
|
|
|
|
|
} elsif ($phi->($x)) { |
182
|
0
|
|
|
|
|
0
|
$hi = $x; |
183
|
|
|
|
|
|
|
} else { |
184
|
0
|
|
|
|
|
0
|
$lo = $x; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
0
|
|
|
0
|
|
0
|
sub __increment_one { $_[0] + 1 } |
190
|
|
|
|
|
|
|
sub search_next |
191
|
|
|
|
|
|
|
{ |
192
|
1
|
|
|
1
|
1
|
124
|
my %args = @_; |
193
|
1
|
|
|
|
|
4
|
my $x = $args{base}; |
194
|
1
|
|
|
|
|
1
|
my $check = $args{check}; |
195
|
1
|
|
50
|
|
|
5
|
my $next = $args{next} || \&__increment_one; |
196
|
1
|
|
|
|
|
2
|
while (! $check->($x) ) { |
197
|
6
|
|
|
|
|
22
|
$x = $next->($x); |
198
|
|
|
|
|
|
|
} |
199
|
1
|
|
|
|
|
5
|
return $x; |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
sub truncate_to_midday |
203
|
|
|
|
|
|
|
{ |
204
|
1
|
|
|
1
|
1
|
464
|
$_[0]->truncate(to => 'hour'); |
205
|
1
|
|
|
|
|
202
|
$_[0]->set( hour => 12 ); |
206
|
1
|
|
|
|
|
380
|
$_[0]; |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
sub revolution |
210
|
|
|
|
|
|
|
{ |
211
|
|
|
|
|
|
|
# |
212
|
|
|
|
|
|
|
# |
213
|
|
|
|
|
|
|
# FUNCTIONAL SEQUENCE for revolution |
214
|
|
|
|
|
|
|
# |
215
|
|
|
|
|
|
|
# _GIVEN |
216
|
|
|
|
|
|
|
# any angle |
217
|
|
|
|
|
|
|
# |
218
|
|
|
|
|
|
|
# _THEN |
219
|
|
|
|
|
|
|
# |
220
|
|
|
|
|
|
|
# reduces any angle to within the first revolution |
221
|
|
|
|
|
|
|
# by subtracting or adding even multiples of 360.0 |
222
|
|
|
|
|
|
|
# |
223
|
|
|
|
|
|
|
# |
224
|
|
|
|
|
|
|
# _RETURN |
225
|
|
|
|
|
|
|
# |
226
|
|
|
|
|
|
|
# the value of the input is >= 0.0 and < 360.0 |
227
|
|
|
|
|
|
|
# |
228
|
|
|
|
|
|
|
|
229
|
0
|
|
|
0
|
1
|
|
my $x = $_[0]; |
230
|
0
|
|
|
|
|
|
return ( $x - 360.0 * floor( $x * ( 1.0 / 360.0 ) ) ); |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub rev180 |
234
|
|
|
|
|
|
|
{ |
235
|
|
|
|
|
|
|
# |
236
|
|
|
|
|
|
|
# |
237
|
|
|
|
|
|
|
# FUNCTIONAL SEQUENCE for rev180 |
238
|
|
|
|
|
|
|
# |
239
|
|
|
|
|
|
|
# _GIVEN |
240
|
|
|
|
|
|
|
# |
241
|
|
|
|
|
|
|
# any angle |
242
|
|
|
|
|
|
|
# |
243
|
|
|
|
|
|
|
# _THEN |
244
|
|
|
|
|
|
|
# |
245
|
|
|
|
|
|
|
# Reduce input to within +180..+180 degrees |
246
|
|
|
|
|
|
|
# |
247
|
|
|
|
|
|
|
# |
248
|
|
|
|
|
|
|
# _RETURN |
249
|
|
|
|
|
|
|
# |
250
|
|
|
|
|
|
|
# angle that was reduced |
251
|
|
|
|
|
|
|
# |
252
|
0
|
|
|
0
|
1
|
|
my ($x) = @_; |
253
|
0
|
|
|
|
|
|
return ( $x - 360.0 * floor( $x * ( 1.0 / 360.0 ) + 0.5 ) ); |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
1; |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
__END__ |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
=head1 NAME |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
DateTime::Util::Calc - DateTime Calculation Utilities |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
=head1 SYNOPSIS |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
use DateTime::Util::Calc qw(polynomial); |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
my @coeffs = qw(2 3 -2); |
270
|
|
|
|
|
|
|
my $x = 5; |
271
|
|
|
|
|
|
|
my $rv = polynomial($x, @coeffs); |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=head1 DESCRIPTION |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
This module contains some common calculation utilities that are required |
276
|
|
|
|
|
|
|
to perform datetime calculations, specifically from "Calendrical Calculations" |
277
|
|
|
|
|
|
|
-- they are NOT meant to be general purpose. |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
Nothing is exported by default. You must either explicitly export them, |
280
|
|
|
|
|
|
|
or use as fully qualified function names. |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=head1 FUNCTIONS |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
=head2 max($a, $b) |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
=head2 min($a, $b) |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
max() returns the bigger of $a and $b. min() returns the smaller of $a and $b. |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
=head2 polynomial($x, @coefs) |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
Calculates the value of a polynomial equation, based on Horner's Rule. |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
c + b * x + a * (x ** 2) x = 5 |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
is expressed as: |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
polynomial(5, c, b, a); |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
=head2 moment($dt) |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
=head2 dt_from_moment($moment) |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
moment() converts a DateTime object to moment, which is RD days + the time |
305
|
|
|
|
|
|
|
of day as fraction of the total seconds in a day. |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
dt_from_moment() converts a moment to DateTime object. |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
=head2 rata_die() |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
Returns a new DateTime object that is set to Rata Die, 0001-01-01 00:00:00 UTC |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
=head2 bigfloat($v) |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
=head2 bigint($v) |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
If the value $v is not a Math::BigFloat object, returns the value converted |
318
|
|
|
|
|
|
|
to Math::BigFloat. Otherwise returns the value itself. |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
bigint() does the same for Math::BigInt. |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
=head2 bf_downgrade($v) |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=head2 bi_downgrade($v) |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
These have been deprecated. |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=head2 truncate_to_midday($dt) |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
Truncates the DateTime object to 12:00 noon. |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=head2 sin_deg($degrees) |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=head2 cos_deg($degrees) |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
=head2 tan_deg($degrees) |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
=head2 asin_deg($degrees) |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
=head2 acos_deg($degrees) |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
Each of these functions calculates their respective values based on degrees, |
343
|
|
|
|
|
|
|
not radians (as Perl's version of sin() and cos() would do). |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
=head2 mod($v,$mod) |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
Calculates the modulus of $v over $mod. Perl's built-in modulus operator (%) |
348
|
|
|
|
|
|
|
for some reason rounds numbers UP when a fractional number's modulus is |
349
|
|
|
|
|
|
|
taken. Many of the calculations also needed the fractional part of the |
350
|
|
|
|
|
|
|
calculation, so this function takes care of both. |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
Example: |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
mod(12.234, 5) = 2.234 |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
=head2 amod($v,$mod) |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
This function is almost identical to mod(), but when the regular modulus value |
359
|
|
|
|
|
|
|
is 0, returns $mod instead of 0. |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
Example: |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
amod(11, 5) = 1 |
364
|
|
|
|
|
|
|
amod(10, 5) = 5 |
365
|
|
|
|
|
|
|
amod(9, 5) = 4 |
366
|
|
|
|
|
|
|
amod(8, 5) = 3 |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
=head2 binary_search($hi, $lo, $mu, $phi) |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
This is a special version of binary search, where the terminating condition |
371
|
|
|
|
|
|
|
is determined by the result of coderefs $mu and $phi. |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
$mu is passed the value of $hi and $lo. If it returns true upon execution, |
374
|
|
|
|
|
|
|
then the search terminates. |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
$phi is passed the next median value. If it returns true upon execution, |
377
|
|
|
|
|
|
|
then the search terminates. |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
If the above two fails, then $hi and $lo are re-computed for the next |
380
|
|
|
|
|
|
|
iteration. |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
=head2 search_next(%opts) |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
Performs a "linear" search until some condition is met. This is a generalized |
385
|
|
|
|
|
|
|
version of the formula defined in [1] p.22. The basic idea is : |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
x = base |
388
|
|
|
|
|
|
|
while (! check(x) ) { |
389
|
|
|
|
|
|
|
x = next(x); |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
return x |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
%opts can contain the following parameters: |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
=over 4 |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
=item base |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
The initial value to use to start the search process. The value can be |
400
|
|
|
|
|
|
|
anything, but you must provide C<check> and C<next> parameters that are |
401
|
|
|
|
|
|
|
capable of handling the type of thing you specified. |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
=item check (coderef) |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
Code to be executed to determine the end of the search. The function receives |
406
|
|
|
|
|
|
|
the current value of "x", and should return a true value if the condition |
407
|
|
|
|
|
|
|
to end the loop has been reached |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
=item next (coderef, optional) |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
Code to be executed to determine the next value of "x". The function receives |
412
|
|
|
|
|
|
|
the current value of "x", and should return the value to be used for the |
413
|
|
|
|
|
|
|
next iteration. |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
If unspecified, it will use a function that blindly adds 1 to whatever x is. |
416
|
|
|
|
|
|
|
(so if you specified a number for C<base>, it should work -- but if you |
417
|
|
|
|
|
|
|
passed an object like DateTime, it will probably be an error) |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
=back |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
So for example, to iterate through 1 through 9, you could do something |
422
|
|
|
|
|
|
|
like this |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
my $x = search_next( |
425
|
|
|
|
|
|
|
base => 1, |
426
|
|
|
|
|
|
|
check => sub { $_[0] == 9 } |
427
|
|
|
|
|
|
|
); |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
And $x will be set to 9. For a more interesting example, we could look |
430
|
|
|
|
|
|
|
for a DateTime object $dt matching a certain condition C<foo()>: |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
my $dt = search_next( |
433
|
|
|
|
|
|
|
base => $base_date, |
434
|
|
|
|
|
|
|
check => \&foo, |
435
|
|
|
|
|
|
|
next => sub { $_[0] + DateTime::Duration->new(days => 1) } |
436
|
|
|
|
|
|
|
); |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=head2 revolution($angle_in_degrees) |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
Reduces any angle to within the first revolution by sbtracting or adding |
441
|
|
|
|
|
|
|
even multiples of 360.0. |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
=head2 rev180($angle_in_degrees) |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
Reduces input to within +180..+180 degrees |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
=head2 angle($h, $m, $s) |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=head1 AUTHOR |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
Copyright (c) 2004-2007 Daisuke Maki E<lt>daisuke@endeworks.jpE<gt> |
452
|
|
|
|
|
|
|
All rights reserved. |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
=cut |
455
|
|
|
|
|
|
|
|