Commit | Line | Data |
---|---|---|
9428c1c5 | 1 | #!./perl |
5aabfad6 | 2 | |
3 | # | |
4 | # Regression tests for the Math::Trig package | |
5 | # | |
bf5f1b4c JH |
6 | # The tests here are quite modest as the Math::Complex tests exercise |
7 | # these interfaces quite vigorously. | |
5aabfad6 | 8 | # |
9 | # -- Jarkko Hietaniemi, April 1997 | |
10 | ||
9853179e | 11 | use Test::More tests => 153; |
affad850 | 12 | |
f1e71051 RGS |
13 | use Math::Trig 1.18; |
14 | use Math::Trig 1.18 qw(:pi Inf); | |
bf5f1b4c | 15 | |
9428c1c5 JH |
16 | our $vax_float = (pack("d",1) =~ /^[\x80\x10]\x40/); |
17 | our $has_inf = !$vax_float; | |
18 | ||
bf5f1b4c | 19 | my $pip2 = pi / 2; |
5aabfad6 | 20 | |
21 | use strict; | |
22 | ||
9853179e | 23 | our($x, $y, $z); |
5aabfad6 | 24 | |
25 | my $eps = 1e-11; | |
26 | ||
2f367121 JH |
27 | if ($^O eq 'unicos') { # See lib/Math/Complex.pm and t/lib/complex.t. |
28 | $eps = 1e-10; | |
29 | } | |
30 | ||
5aabfad6 | 31 | sub near ($$;$) { |
e64f0054 | 32 | my $e = defined $_[2] ? $_[2] : $eps; |
affad850 SP |
33 | my $d = $_[1] ? abs($_[0]/$_[1] - 1) : abs($_[0]); |
34 | print "# near? $_[0] $_[1] : $d : $e\n"; | |
35 | $_[1] ? ($d < $e) : abs($_[0]) < $e; | |
5aabfad6 | 36 | } |
37 | ||
1515bec6 SP |
38 | print "# Sanity checks\n"; |
39 | ||
40 | ok(near(sin(1), 0.841470984807897)); | |
41 | ok(near(cos(1), 0.54030230586814)); | |
42 | ok(near(tan(1), 1.5574077246549)); | |
43 | ||
44 | ok(near(sec(1), 1.85081571768093)); | |
45 | ok(near(csc(1), 1.18839510577812)); | |
46 | ok(near(cot(1), 0.642092615934331)); | |
47 | ||
48 | ok(near(asin(1), 1.5707963267949)); | |
49 | ok(near(acos(1), 0)); | |
50 | ok(near(atan(1), 0.785398163397448)); | |
51 | ||
52 | ok(near(asec(1), 0)); | |
53 | ok(near(acsc(1), 1.5707963267949)); | |
54 | ok(near(acot(1), 0.785398163397448)); | |
55 | ||
56 | ok(near(sinh(1), 1.1752011936438)); | |
57 | ok(near(cosh(1), 1.54308063481524)); | |
58 | ok(near(tanh(1), 0.761594155955765)); | |
59 | ||
60 | ok(near(sech(1), 0.648054273663885)); | |
61 | ok(near(csch(1), 0.850918128239322)); | |
62 | ok(near(coth(1), 1.31303528549933)); | |
63 | ||
64 | ok(near(asinh(1), 0.881373587019543)); | |
65 | ok(near(acosh(1), 0)); | |
66 | ok(near(atanh(0.9), 1.47221948958322)); # atanh(1.0) would be an error. | |
67 | ||
68 | ok(near(asech(0.9), 0.467145308103262)); | |
69 | ok(near(acsch(2), 0.481211825059603)); | |
70 | ok(near(acoth(2), 0.549306144334055)); | |
71 | ||
72 | print "# Basics\n"; | |
73 | ||
5aabfad6 | 74 | $x = 0.9; |
affad850 | 75 | ok(near(tan($x), sin($x) / cos($x))); |
5aabfad6 | 76 | |
affad850 | 77 | ok(near(sinh(2), 3.62686040784702)); |
5aabfad6 | 78 | |
affad850 | 79 | ok(near(acsch(0.1), 2.99822295029797)); |
5aabfad6 | 80 | |
81 | $x = asin(2); | |
affad850 | 82 | is(ref $x, 'Math::Complex'); |
5aabfad6 | 83 | |
84 | # avoid using Math::Complex here | |
85 | $x =~ /^([^-]+)(-[^i]+)i$/; | |
86 | ($y, $z) = ($1, $2); | |
affad850 SP |
87 | ok(near($y, 1.5707963267949)); |
88 | ok(near($z, -1.31695789692482)); | |
5aabfad6 | 89 | |
affad850 | 90 | ok(near(deg2rad(90), pi/2)); |
5aabfad6 | 91 | |
affad850 | 92 | ok(near(rad2deg(pi), 180)); |
ace5de91 | 93 | |
d54bf66f JH |
94 | use Math::Trig ':radial'; |
95 | ||
96 | { | |
97 | my ($r,$t,$z) = cartesian_to_cylindrical(1,1,1); | |
98 | ||
affad850 SP |
99 | ok(near($r, sqrt(2))); |
100 | ok(near($t, deg2rad(45))); | |
101 | ok(near($z, 1)); | |
d54bf66f JH |
102 | |
103 | ($x,$y,$z) = cylindrical_to_cartesian($r, $t, $z); | |
104 | ||
affad850 SP |
105 | ok(near($x, 1)); |
106 | ok(near($y, 1)); | |
107 | ok(near($z, 1)); | |
d54bf66f JH |
108 | |
109 | ($r,$t,$z) = cartesian_to_cylindrical(1,1,0); | |
110 | ||
affad850 SP |
111 | ok(near($r, sqrt(2))); |
112 | ok(near($t, deg2rad(45))); | |
113 | ok(near($z, 0)); | |
d54bf66f JH |
114 | |
115 | ($x,$y,$z) = cylindrical_to_cartesian($r, $t, $z); | |
116 | ||
affad850 SP |
117 | ok(near($x, 1)); |
118 | ok(near($y, 1)); | |
119 | ok(near($z, 0)); | |
d54bf66f JH |
120 | } |
121 | ||
122 | { | |
123 | my ($r,$t,$f) = cartesian_to_spherical(1,1,1); | |
124 | ||
affad850 SP |
125 | ok(near($r, sqrt(3))); |
126 | ok(near($t, deg2rad(45))); | |
127 | ok(near($f, atan2(sqrt(2), 1))); | |
d54bf66f JH |
128 | |
129 | ($x,$y,$z) = spherical_to_cartesian($r, $t, $f); | |
130 | ||
affad850 SP |
131 | ok(near($x, 1)); |
132 | ok(near($y, 1)); | |
133 | ok(near($z, 1)); | |
134 | ||
d54bf66f JH |
135 | ($r,$t,$f) = cartesian_to_spherical(1,1,0); |
136 | ||
affad850 SP |
137 | ok(near($r, sqrt(2))); |
138 | ok(near($t, deg2rad(45))); | |
139 | ok(near($f, deg2rad(90))); | |
d54bf66f JH |
140 | |
141 | ($x,$y,$z) = spherical_to_cartesian($r, $t, $f); | |
142 | ||
affad850 SP |
143 | ok(near($x, 1)); |
144 | ok(near($y, 1)); | |
145 | ok(near($z, 0)); | |
d54bf66f JH |
146 | } |
147 | ||
148 | { | |
149 | my ($r,$t,$z) = cylindrical_to_spherical(spherical_to_cylindrical(1,1,1)); | |
150 | ||
affad850 SP |
151 | ok(near($r, 1)); |
152 | ok(near($t, 1)); | |
153 | ok(near($z, 1)); | |
d54bf66f JH |
154 | |
155 | ($r,$t,$z) = spherical_to_cylindrical(cylindrical_to_spherical(1,1,1)); | |
156 | ||
affad850 SP |
157 | ok(near($r, 1)); |
158 | ok(near($t, 1)); | |
159 | ok(near($z, 1)); | |
d54bf66f JH |
160 | } |
161 | ||
162 | { | |
9db5a202 | 163 | use Math::Trig 'great_circle_distance'; |
d54bf66f | 164 | |
affad850 | 165 | ok(near(great_circle_distance(0, 0, 0, pi/2), pi/2)); |
d54bf66f | 166 | |
affad850 | 167 | ok(near(great_circle_distance(0, 0, pi, pi), pi)); |
d54bf66f | 168 | |
9db5a202 | 169 | # London to Tokyo. |
d020892c SP |
170 | my @L = (deg2rad(-0.5), deg2rad(90 - 51.3)); |
171 | my @T = (deg2rad(139.8), deg2rad(90 - 35.7)); | |
d54bf66f | 172 | |
9db5a202 | 173 | my $km = great_circle_distance(@L, @T, 6378); |
d54bf66f | 174 | |
affad850 | 175 | ok(near($km, 9605.26637021388)); |
9db5a202 JH |
176 | } |
177 | ||
178 | { | |
fdf27e67 JH |
179 | my $R2D = 57.295779513082320876798154814169; |
180 | ||
181 | sub frac { $_[0] - int($_[0]) } | |
182 | ||
9db5a202 | 183 | my $lotta_radians = deg2rad(1E+20, 1); |
affad850 | 184 | ok(near($lotta_radians, 1E+20/$R2D)); |
9db5a202 JH |
185 | |
186 | my $negat_degrees = rad2deg(-1E20, 1); | |
affad850 | 187 | ok(near($negat_degrees, -1E+20*$R2D)); |
9db5a202 JH |
188 | |
189 | my $posit_degrees = rad2deg(-10000, 1); | |
affad850 | 190 | ok(near($posit_degrees, -10000*$R2D)); |
d54bf66f JH |
191 | } |
192 | ||
7e5f197a JH |
193 | { |
194 | use Math::Trig 'great_circle_direction'; | |
195 | ||
affad850 | 196 | ok(near(great_circle_direction(0, 0, 0, pi/2), pi)); |
7e5f197a | 197 | |
bf5f1b4c | 198 | # Retired test: Relies on atan2(0, 0), which is not portable. |
affad850 | 199 | # ok(near(great_circle_direction(0, 0, pi, pi), -pi()/2)); |
7e5f197a | 200 | |
d139edd6 JH |
201 | my @London = (deg2rad( -0.167), deg2rad(90 - 51.3)); |
202 | my @Tokyo = (deg2rad( 139.5), deg2rad(90 - 35.7)); | |
203 | my @Berlin = (deg2rad ( 13.417), deg2rad(90 - 52.533)); | |
204 | my @Paris = (deg2rad ( 2.333), deg2rad(90 - 48.867)); | |
7e5f197a | 205 | |
affad850 SP |
206 | ok(near(rad2deg(great_circle_direction(@London, @Tokyo)), |
207 | 31.791945393073)); | |
bf5f1b4c | 208 | |
affad850 SP |
209 | ok(near(rad2deg(great_circle_direction(@Tokyo, @London)), |
210 | 336.069766430326)); | |
d139edd6 | 211 | |
affad850 SP |
212 | ok(near(rad2deg(great_circle_direction(@Berlin, @Paris)), |
213 | 246.800348034667)); | |
d139edd6 | 214 | |
affad850 SP |
215 | ok(near(rad2deg(great_circle_direction(@Paris, @Berlin)), |
216 | 58.2079877553156)); | |
bf5f1b4c JH |
217 | |
218 | use Math::Trig 'great_circle_bearing'; | |
219 | ||
affad850 SP |
220 | ok(near(rad2deg(great_circle_bearing(@Paris, @Berlin)), |
221 | 58.2079877553156)); | |
bf5f1b4c JH |
222 | |
223 | use Math::Trig 'great_circle_waypoint'; | |
224 | use Math::Trig 'great_circle_midpoint'; | |
225 | ||
226 | my ($lon, $lat); | |
227 | ||
228 | ($lon, $lat) = great_circle_waypoint(@London, @Tokyo, 0.0); | |
229 | ||
affad850 | 230 | ok(near($lon, $London[0])); |
bf5f1b4c | 231 | |
618e05e9 | 232 | ok(near($lat, $London[1])); |
bf5f1b4c JH |
233 | |
234 | ($lon, $lat) = great_circle_waypoint(@London, @Tokyo, 1.0); | |
235 | ||
affad850 | 236 | ok(near($lon, $Tokyo[0])); |
bf5f1b4c | 237 | |
618e05e9 | 238 | ok(near($lat, $Tokyo[1])); |
bf5f1b4c JH |
239 | |
240 | ($lon, $lat) = great_circle_waypoint(@London, @Tokyo, 0.5); | |
241 | ||
618e05e9 | 242 | ok(near($lon, 1.55609593577679)); # 89.16 E |
bf5f1b4c | 243 | |
618e05e9 | 244 | ok(near($lat, 0.36783532946162)); # 68.93 N |
bf5f1b4c JH |
245 | |
246 | ($lon, $lat) = great_circle_midpoint(@London, @Tokyo); | |
247 | ||
618e05e9 | 248 | ok(near($lon, 1.55609593577679)); # 89.16 E |
bf5f1b4c | 249 | |
618e05e9 | 250 | ok(near($lat, 0.367835329461615)); # 68.93 N |
bf5f1b4c JH |
251 | |
252 | ($lon, $lat) = great_circle_waypoint(@London, @Tokyo, 0.25); | |
253 | ||
618e05e9 | 254 | ok(near($lon, 0.516073562850837)); # 29.57 E |
affad850 | 255 | |
618e05e9 | 256 | ok(near($lat, 0.400231313403387)); # 67.07 N |
bf5f1b4c | 257 | |
bf5f1b4c JH |
258 | ($lon, $lat) = great_circle_waypoint(@London, @Tokyo, 0.75); |
259 | ||
618e05e9 | 260 | ok(near($lon, 2.17494903805952)); # 124.62 E |
bf5f1b4c | 261 | |
618e05e9 | 262 | ok(near($lat, 0.617809294053591)); # 54.60 N |
bf5f1b4c JH |
263 | |
264 | use Math::Trig 'great_circle_destination'; | |
265 | ||
266 | my $dir1 = great_circle_direction(@London, @Tokyo); | |
267 | my $dst1 = great_circle_distance(@London, @Tokyo); | |
268 | ||
269 | ($lon, $lat) = great_circle_destination(@London, $dir1, $dst1); | |
270 | ||
affad850 | 271 | ok(near($lon, $Tokyo[0])); |
bf5f1b4c | 272 | |
affad850 | 273 | ok(near($lat, $pip2 - $Tokyo[1])); |
bf5f1b4c JH |
274 | |
275 | my $dir2 = great_circle_direction(@Tokyo, @London); | |
276 | my $dst2 = great_circle_distance(@Tokyo, @London); | |
277 | ||
278 | ($lon, $lat) = great_circle_destination(@Tokyo, $dir2, $dst2); | |
279 | ||
affad850 | 280 | ok(near($lon, $London[0])); |
bf5f1b4c | 281 | |
affad850 | 282 | ok(near($lat, $pip2 - $London[1])); |
bf5f1b4c JH |
283 | |
284 | my $dir3 = (great_circle_destination(@London, $dir1, $dst1))[2]; | |
285 | ||
affad850 | 286 | ok(near($dir3, 2.69379263839118)); # about 154.343 deg |
bf5f1b4c JH |
287 | |
288 | my $dir4 = (great_circle_destination(@Tokyo, $dir2, $dst2))[2]; | |
289 | ||
affad850 | 290 | ok(near($dir4, 3.6993902625701)); # about 211.959 deg |
bf5f1b4c | 291 | |
affad850 | 292 | ok(near($dst1, $dst2)); |
7e5f197a JH |
293 | } |
294 | ||
9428c1c5 JH |
295 | SKIP: { |
296 | # With netbsd-vax (or any vax) there is neither Inf, nor 1e40. | |
297 | skip("different float range", 42) if $vax_float; | |
298 | skip("no inf", 42) unless $has_inf; | |
299 | ||
1515bec6 SP |
300 | print "# Infinity\n"; |
301 | ||
9428c1c5 | 302 | my $BigDouble = eval '1e40'; |
1515bec6 | 303 | |
b57c8994 | 304 | # E.g. netbsd-alpha core dumps on Inf arith without this. |
f1e71051 | 305 | local $SIG{FPE} = sub { }; |
7637cd07 SP |
306 | |
307 | ok(Inf() > $BigDouble); # This passes in netbsd-alpha. | |
b57c8994 | 308 | ok(Inf() + $BigDouble > $BigDouble); # This coredumps in netbsd-alpha. |
1515bec6 SP |
309 | ok(Inf() + $BigDouble == Inf()); |
310 | ok(Inf() - $BigDouble > $BigDouble); | |
311 | ok(Inf() - $BigDouble == Inf()); | |
312 | ok(Inf() * $BigDouble > $BigDouble); | |
313 | ok(Inf() * $BigDouble == Inf()); | |
314 | ok(Inf() / $BigDouble > $BigDouble); | |
315 | ok(Inf() / $BigDouble == Inf()); | |
316 | ||
317 | ok(-Inf() < -$BigDouble); | |
318 | ok(-Inf() + $BigDouble < $BigDouble); | |
319 | ok(-Inf() + $BigDouble == -Inf()); | |
320 | ok(-Inf() - $BigDouble < -$BigDouble); | |
321 | ok(-Inf() - $BigDouble == -Inf()); | |
322 | ok(-Inf() * $BigDouble < -$BigDouble); | |
323 | ok(-Inf() * $BigDouble == -Inf()); | |
324 | ok(-Inf() / $BigDouble < -$BigDouble); | |
325 | ok(-Inf() / $BigDouble == -Inf()); | |
326 | ||
327 | print "# sinh/sech/cosh/csch/tanh/coth unto infinity\n"; | |
328 | ||
9428c1c5 JH |
329 | ok(near(sinh(100), eval '1.3441e+43', 1e-3)); |
330 | ok(near(sech(100), eval '7.4402e-44', 1e-3)); | |
331 | ok(near(cosh(100), eval '1.3441e+43', 1e-3)); | |
332 | ok(near(csch(100), eval '7.4402e-44', 1e-3)); | |
1515bec6 SP |
333 | ok(near(tanh(100), 1)); |
334 | ok(near(coth(100), 1)); | |
335 | ||
9428c1c5 JH |
336 | ok(near(sinh(-100), eval '-1.3441e+43', 1e-3)); |
337 | ok(near(sech(-100), eval ' 7.4402e-44', 1e-3)); | |
338 | ok(near(cosh(-100), eval ' 1.3441e+43', 1e-3)); | |
339 | ok(near(csch(-100), eval '-7.4402e-44', 1e-3)); | |
1515bec6 SP |
340 | ok(near(tanh(-100), -1)); |
341 | ok(near(coth(-100), -1)); | |
342 | ||
86a885eb NC |
343 | cmp_ok(sinh(1e5), '==', Inf()); |
344 | cmp_ok(sech(1e5), '==', 0); | |
345 | cmp_ok(cosh(1e5), '==', Inf()); | |
346 | cmp_ok(csch(1e5), '==', 0); | |
347 | cmp_ok(tanh(1e5), '==', 1); | |
348 | cmp_ok(coth(1e5), '==', 1); | |
349 | ||
350 | cmp_ok(sinh(-1e5), '==', -Inf()); | |
351 | cmp_ok(sech(-1e5), '==', 0); | |
352 | cmp_ok(cosh(-1e5), '==', Inf()); | |
353 | cmp_ok(csch(-1e5), '==', 0); | |
354 | cmp_ok(tanh(-1e5), '==', -1); | |
355 | cmp_ok(coth(-1e5), '==', -1); | |
1515bec6 | 356 | |
9428c1c5 JH |
357 | } |
358 | ||
f3828575 SP |
359 | print "# great_circle_distance with small angles\n"; |
360 | ||
361 | for my $e (qw(1e-2 1e-3 1e-4 1e-5)) { | |
362 | # Can't assume == 0 because of floating point fuzz, | |
363 | # but let's hope for at least < $e. | |
364 | cmp_ok(great_circle_distance(0, $e, 0, $e), '<', $e); | |
365 | } | |
366 | ||
367 | print "# asin_real, acos_real\n"; | |
368 | ||
369 | is(acos_real(-2.0), pi); | |
370 | is(acos_real(-1.0), pi); | |
371 | is(acos_real(-0.5), acos(-0.5)); | |
372 | is(acos_real( 0.0), acos( 0.0)); | |
373 | is(acos_real( 0.5), acos( 0.5)); | |
374 | is(acos_real( 1.0), 0); | |
375 | is(acos_real( 2.0), 0); | |
376 | ||
377 | is(asin_real(-2.0), -&pip2); | |
378 | is(asin_real(-1.0), -&pip2); | |
379 | is(asin_real(-0.5), asin(-0.5)); | |
380 | is(asin_real( 0.0), asin( 0.0)); | |
381 | is(asin_real( 0.5), asin( 0.5)); | |
382 | is(asin_real( 1.0), pip2); | |
383 | is(asin_real( 2.0), pip2); | |
384 | ||
5aabfad6 | 385 | # eof |