MathLib
Loading...
Searching...
No Matches
TestComplex.cpp
Go to the documentation of this file.
4#include <cassert>
5#include <iostream>
6#include <cstdlib>
7
26namespace ComplexTests
27{
28
29using namespace Math;
30using namespace Math::Literals;
31
32void TestRotationAtRegularIntervals(Complexf begin, Degreef amount_of_rotation, int num_equal_steps)
33{
34 Complexf end_rotation{ Complexf::make_rotation(amount_of_rotation) };
35 float step_percentage = 1.0f / num_equal_steps;
36
37 for (int iCurrentStep = 0; iCurrentStep < num_equal_steps; ++iCurrentStep)
38 {
39 float current_percentage{ step_percentage * iCurrentStep };
40 Degreef current_rotation_amount{ amount_of_rotation * current_percentage };
41 Complexf new_rotation{ Complexf::make_rotation(current_rotation_amount) };
42 Complexf slerp_result = slerp(begin, end_rotation, current_percentage);
43
44 if ( approximately_equal_to( std::abs( end_rotation.imaginary() ), 0.0f, 0.0000001f ) )
45 {
46 // If the imaginary component is very close to 0, then the rotation direction
47 // is ambiguous, so we just compare the absolute values of the imaginary
48 // components (i.e. we ignore the sign of the rotation).
49 slerp_result = Complexf(slerp_result.real(), std::abs(slerp_result.imaginary()));
50 new_rotation = Complexf(new_rotation.real(), std::abs(new_rotation.imaginary()));
51 }
52
53 CHECK_IF_EQUAL( slerp_result, new_rotation);
54 }
55 Complexf slerp_result = slerp(begin, end_rotation, 1.0f);
56
57 CHECK_IF_EQUAL( slerp_result, end_rotation);
58}
59
62{
63 Complexf unit = Complexf::identity();
64
65 CHECK_IF_EQUAL(unit.real(), 1.0f);
66 CHECK_IF_EQUAL(unit.i(), 0.0f);
67}
68
70{
71 Complexf zero = Complexf::zero();
72
73 CHECK_IF_EQUAL(zero.real(), 0.0f);
74 CHECK_IF_EQUAL(zero.i(), 0.0f);
75}
76
78{
79 Complexf c{ 1.0, 2.0 };
80
81 CHECK_IF_EQUAL(c.real(), 1.0f);
82 CHECK_IF_EQUAL(c.i(), 2.0f);
83}
84
86{
87 Complexf c_left{ 1.0, 2.0 };
88 Complexf c_right{ 5.0, 6.0 };
89 Complexf c_result = c_left + c_right;
90
91 CHECK_IF_EQUAL(c_result.real(), 6.0f);
92 CHECK_IF_EQUAL(c_result.i(), 8.0f);
93}
94
96{
97 Complexf c_original{ 1.0, 2.0 };
98 Complexf c_tocompareagainst{ 1.0, 2.0 };
99
100 CHECK_IF_EQUAL(c_original, c_tocompareagainst);
101 CHECK_IF_EQUAL(c_original.real(), c_tocompareagainst.real());
102 CHECK_IF_EQUAL(c_original.i(), c_tocompareagainst.i());
103}
104
106{
107 Complexf c_original{ 1.0, 2.0 };
108 Complexf c_tocompareagainst{ 1.0, 2.0 };
109 Complexf c_different4{ -1.0, -2.0 };
110 Complexf c_different3{ 99.0, 2.0 };
111 Complexf c_different2{ 1.0, 12.0 };
112 Complexf c_different1{ 100.0, 2.0 };
113
114 CHECK_IF_EQUAL(c_original, c_tocompareagainst);
115
116 assert( (c_original != c_tocompareagainst) == false );
117
118 // Now test for each component individually
119 CHECK_IF_NOT_EQUAL(c_original, c_different1);
120 CHECK_IF_NOT_EQUAL(c_original, c_different2);
121 CHECK_IF_NOT_EQUAL(c_original, c_different3);
122 CHECK_IF_NOT_EQUAL(c_original, c_different4);
123}
124
126{
127 Complexf q_original{ 2.0, 4.0 };
128 Complexf q_copy{ q_original };
129
130 CHECK_IF_EQUAL(q_original, q_copy);
131}
132
134{
135 Complexf arbitrary_value1{ 1.0, 2.0 };
136 Complexf arbitrary_value2{ 1.0, -2.0 };
137 Complexf arbitrary_value3{ 1.0, 2.0 };
138
139 Complexf expected_value1{ 1.0, -2.0 };
140 Complexf expected_value2{ 1.0, 2.0 };
141 Complexf expected_value3{ 1.0, -2.0 };
142
143 CHECK_IF_EQUAL(arbitrary_value1.conjugate(), expected_value1);
144 CHECK_IF_EQUAL(arbitrary_value2.conjugate(), expected_value2);
145 CHECK_IF_EQUAL(arbitrary_value3.conjugate(), expected_value3);
146}
147
149{
150 Complexf arbitrary_value1{ 6.0, 7.0 };
151
152 CHECK_IF_EQUAL(arbitrary_value1.conjugate().conjugate(), arbitrary_value1);
153}
154
156{
157 CHECK_IF_EQUAL( Complexf::unit_i(), Complexf{ 0.0, 1.0 } );
158}
159
161{
162 Complexf negative_1{ -1.0, 0.0 };
163 Complexf i = Complexf::unit_i();
164
165 CHECK_IF_EQUAL( i * i, negative_1 );
166}
167
169{
170 CHECK_IF_EQUAL( -Complexf::identity(), Complexf{ -1.0, 0.0 } );
171 CHECK_IF_EQUAL( -Complexf::unit_i(), Complexf{ 0.0, -1.0 } );
172
173 CHECK_IF_EQUAL( -Complexf(1.0f, -2.2f), Complexf(-1.0f, 2.2f) );
174}
175
177{
178 Complexf::value_type starting_value = 0;
179 Complexf::value_type value = 6;
180 Complexf::value_type added_value = starting_value + value;
181 Complexf::value_type subtracted_value = starting_value - value;
182
183 CHECK_IF_EQUAL( added_value - value, starting_value );
184 CHECK_IF_EQUAL( subtracted_value + value, starting_value );
185}
186
188{
189 CHECK_IF_EQUAL( Complexf{ 1.0, 1.0 }.norm(), std::sqrt(1.0f + 1.0f) );
190
191 CHECK_IF_EQUAL( Complexf{ 2.0, 2.0 }.norm(), std::sqrt(4.0f + 4.0f) );
192 CHECK_IF_EQUAL( Complexf{ 1.0, 2.0 }.norm(), std::sqrt(1.0f + 4.0f) ); // 1^2 + 2^2
193}
194
196{
197 CHECK_IF_EQUAL( Complexf::identity().norm(), 1.0f );
198 CHECK_IF_EQUAL( Complexf::unit_i().norm(), 1.0f );
199}
200
202{
203 {
204 Complexf a(1.0f, 2.0f);
205 Complexf a_div = a / 2.0f;
206 Complexf b(1.0f / 2.0f, 2.0f / 2.0f);
207
208 CHECK_IF_EQUAL( a_div, b );
209 }
210 {
211 Complexf a(1.0f, 2.0f);
212 Complexf a_div = a / 3.0f;
213 Complexf b(1.0f / 3.0f, 2.0f / 3.0f);
214
215 CHECK_IF_EQUAL( a_div, b );
216 }
217}
218
220{
221 {
222 Complexf a(1.0f, 2.0f);
223 Complexf a_mul = a * 2.0f;
224 Complexf b(1.0f * 2.0f, 2.0f * 2.0f);
225
226 CHECK_IF_EQUAL( a_mul, b );
227 }
228 {
229 Complexf a(1.0f, 2.0f);
230 Complexf a_mul = a * 3.0f;
231 Complexf b(1.0f * 3.0f, 2.0f * 3.0f);
232
233 CHECK_IF_EQUAL( a_mul, b );
234 }
235}
236
238{
239 Complexf c1{ 6.3f, 2.2f };
240 Complexf c1_inverse = c1.inverse();
241 Complexf c1_product = c1_inverse * c1;
242 Complexf c1_product_reversed = c1 * c1_inverse;
243
244 CHECK_IF_EQUAL( c1_product, Complexf::identity() );
245 CHECK_IF_EQUAL( c1_product_reversed, Complexf::identity() );
246 CHECK_IF_EQUAL( c1_product_reversed, c1_product );
247}
248
250{
251 CHECK_IF_EQUAL(Complexf::unit_real().inverse(), Complexf::unit_real().conjugate());
252 CHECK_IF_EQUAL(Complexf::unit_i().inverse(), Complexf::unit_i().conjugate());
253}
254
256{
257 assert( Complexf::identity().isUnit() );
258 CHECK_IF_EQUAL( Complexf::identity().norm(), 1.0f );
259}
260
262{
263 CHECK_IF_EQUAL( Complexf::make_pure( 2.0f ).real(), 0.0f );
264}
265
267{
268 CHECK_IF_EQUAL( Complexf::make_pure( 2.0f ).imaginary(), 2.0f );
269}
270
272{
273 Complexf c1{ 1.0f, 2.0f };
274 Complexf c2{ 9.0f, 10.0f };
275
276 CHECK_IF_EQUAL( dot( c1, c2 ), 29.0f );
277}
278
280{
281 Complexf c{ 3.5f, -45.668f };
282 Complexf product = c * c.conjugate();
283
284 CHECK_IF_EQUAL( product.real(), 2097.81616f );
285 CHECK_IF_EQUAL( product.imaginary(), 0.0f );
286}
287
289{
290 Complexf c{ 3.5f, 113.443f };
291 Complexf product = c * c.conjugate();
292 float m_squared = c.magnitudeSquared();
293
294 CHECK_IF_EQUAL( m_squared, std::abs(product.real()) );
295}
296
298{
299 // Rotate 90 deg
300 {
301 Complexf rotation = Complexf::make_rotation( Degreef(90.0f) );
302 Complexf encoded_point = Complexf::encode_point(0.0f, 1.0f);
303 Complexf transformed_point = rotation * encoded_point;
304
305 CHECK_IF_EQUAL( transformed_point.real(), -1.0f );
306 CHECK_IF_EQUAL( transformed_point.imaginary(), 0.0f );
307 }
308
309 {
310 Complexf rotation = Complexf::make_rotation( Degreef(90.0f) );
311 Complexf encoded_point = Complexf::encode_point(1.0f, 0.0f);
312 Complexf transformed_point = rotation * encoded_point;
313
314 CHECK_IF_EQUAL( transformed_point.real(), 0.0f );
315 CHECK_IF_EQUAL( transformed_point.imaginary(), 1.0f );
316 }
317}
318
320{
321 {
322 Complexf rotation_90 = Complexf::make_rotation( Degreef(90.0f) );
323 Complexf encoded_point = Complexf::encode_point(3.0f, 0.0f);
324 Complexf transformed_point = passively_rotate_encoded_point(rotation_90, encoded_point);
325
326 transformed_point = passively_rotate_encoded_point(rotation_90, transformed_point);
327
328 CHECK_IF_EQUAL( transformed_point.real(), -3.0f );
329 CHECK_IF_EQUAL( transformed_point.imaginary(), 0.0f );
330 }
331
332 // Same thing, but compose the rotations first
333 {
334 Complexf rotation_45 = Complexf::make_rotation( Degreef(45.0f) );
335 Complexf composed_rotation = compose_rotations( rotation_45, rotation_45 );
336 Complexf encoded_point = Complexf::encode_point(0.0f, 8.0f);
337 Complexf transformed_point = passively_rotate_encoded_point(composed_rotation, encoded_point);
338
339 CHECK_IF_EQUAL( transformed_point.real(), -8.0f );
340 CHECK_IF_EQUAL( transformed_point.imaginary(), 0.0f );
341 }
342}
343
345{
346 auto angle = 90.0_deg_f;
347 Complexf rotation = Complexf::make_rotation( angle );
348 Complexf exp0 = rotation.pow(0.0f);
349 Complexf exp_0_5 = rotation.pow(0.5f);
350 Complexf exp1 = rotation.pow(1.0f);
351 Complexf exp_2_0 = rotation.pow(2.0f);
352 Complexf exp_3_0 = rotation.pow(3.0f);
353 Complexf two_rotations_multiplied{ rotation * rotation };
354 Complexf three_rotations_multiplied{ rotation * rotation * rotation };
355
356 CHECK_IF_EQUAL( exp0, Complexf::identity() ); // Any number to the zero power should be 1
357 CHECK_IF_EQUAL( exp_0_5, Complexf::make_rotation( angle * 0.5f ) );
358 CHECK_IF_EQUAL( exp1, rotation );
359 CHECK_IF_EQUAL( exp_2_0, Complexf::make_rotation( angle * 2.0f ) );
360
361 // Check that a complex squared via pow() is identical to multiplying by itself
362 CHECK_IF_EQUAL( exp_2_0, two_rotations_multiplied );
363
364 CHECK_IF_EQUAL( exp_3_0, three_rotations_multiplied );
365}
366
368{
369 CHECK_IF_EQUAL( Complexf{1.0f}.exp().real(), std::exp(1.0f) );
370 CHECK_IF_EQUAL( Complexf{1.0f}.exp().imaginary(), 0.0f );
371
372 CHECK_IF_EQUAL( Complexf{2.0f}.exp().real(), std::exp(2.0f) );
373 CHECK_IF_EQUAL( Complexf{1.0f}.exp().imaginary(), 0.0f );
374
375 CHECK_IF_EQUAL( Complexf{3.2f}.exp().real(), std::exp(3.2f) );
376 CHECK_IF_EQUAL( Complexf{1.0f}.exp().imaginary(), 0.0f );
377}
378
380{
381 auto a{ Complexf::identity() };
382 auto b{ Complexf::make_rotation(36.3_deg_f) };
383 auto c{ Complexf::make_rotation(90.0_deg_f) };
384
385 CHECK_IF_EQUAL( log( exp(a) ), a );
386 CHECK_IF_EQUAL( exp( log(a) ), a );
387
388 CHECK_IF_EQUAL( log( exp(b) ), b );
389 CHECK_IF_EQUAL( exp( log(b) ), b );
390
391 CHECK_IF_EQUAL( log( exp(c) ), c );
392 CHECK_IF_EQUAL( exp( log(c) ), c );
393}
394
396{
397 Complexf begin = Complexf::identity();
398 Complexf end = Complexf::make_rotation( 90.0_deg_f );
399
400 // with only the endpoints
401 {
402 Complexf slerp_begin = slerp(begin, end, 0.0f);
403 Complexf slerp_end = slerp(begin, end, 1.0f);
404
405 CHECK_IF_EQUAL( slerp_begin, begin );
406 CHECK_IF_EQUAL( slerp_end, end );
407 }
408
409 // 0 to 90 in 10 deg increments
410 TestRotationAtRegularIntervals(begin, 90.0_deg_f, 9);
411
412 // 0 to 180 in 10 deg increments
413 TestRotationAtRegularIntervals(begin, 180.0_deg_f, 18);
414}
415#if 0
416void IsNaNIsTrueWhenAtLeastOneMemberIsNaN()
417{
418 assert( Quaternionf(NAN).isNaN() );
419 assert( Quaternionf(NAN, 0.0f, 0.0f, 0.0f).isNaN() );
420 assert( Quaternionf(3.2f, NAN, 0.0f, 0.0f).isNaN() );
421 assert( Quaternionf(3.2f, 0.0f, NAN, 0.0f).isNaN() );
422 assert( Quaternionf(3.2f, 0.0f, 0.0f, NAN).isNaN() );
423 assert( !Quaternionf(3.2f, 4.6f, 0.0f, 1.1f).isNaN() );
424}
425
427{
428 assert( Quaternionf(INFINITY).isInf() );
429 assert( Quaternionf(INFINITY, 0.0f, 0.0f, 0.0f).isInf() );
430 assert( Quaternionf(3.2f, INFINITY, 0.0f, 0.0f).isInf() );
431 assert( Quaternionf(3.2f, 0.0f, INFINITY, 0.0f).isInf() );
432 assert( Quaternionf(3.2f, 0.0f, 0.0f, INFINITY).isInf() );
433 assert( !Quaternionf(3.2f, 4.6f, 0.0f, 1.1f).isInf() );
434}
435
437{
438 Quaternionf result{ Quaternionf::identity() / 0.0f };
439
440 assert( result.isInf() );
441}
442#endif
444
487
488}
490
491int main(void)
492{
494 return EXIT_SUCCESS;
495}
int main(void)
void CHECK_IF_NOT_EQUAL(float input, float near_to, float tolerance=0.0002f)
Definition Checks.hpp:158
void CHECK_IF_EQUAL(float input, float near_to, float tolerance=0.0002f)
Definition Checks.hpp:127
bool approximately_equal_to(float input, float near_to, float tolerance=0.0002f)
void IUnitCoomplexIsDefined()
void DividingByAScalarDividesEachComponent()
void ISquaredIsNegativeOne()
void NormIsEquivalentToDistance()
void UnitComplexIsAsExpected()
void ExpAndLogAreInversesOfEachOther()
void ComplexAddsPerComponent()
void ZeroComplexIsAsExpected()
void DotProductMultiplesCorrespondingElementsAndThenSumsTheResultingValues()
void MakePureComplexSetsImaginaryToInputParameter()
void ConjugateInvertsTheImaginaryComponent()
void MagnitudeSquaredIsValueOfRealPartOfProductOfAComplexAndItsConjugate()
void InverseOfAUnitComplexIsItsConjugate()
void OperatorPlusAndMinusAreInverses()
void PerformTwoConsecutiveRotations()
void OperatorEqualsComparesMatchingComponents()
void MakePureComplexSetsRealComponentToZero()
void UnitComplexHasNormOfOne()
void TestRotationAtRegularIntervals(Complexf begin, Degreef amount_of_rotation, int num_equal_steps)
void UnitComplexIsNear1()
void MultiplyingByItsOwnInverseProducesUnity()
void MultiplyingByAScalarMultipliesEachComponent()
void OperatorNotEqualsIsOppositeOfEquals()
void ConjugateIsItsOwnInverse()
void MultiplyingAComplexByItsConjugateProducesAPureRealNumber()
void CopyOperatorIsImplemented()
void MakingARotationIsAccurate()
void ComplexIsConstructedAsExpected()
void HasOperatorNegate()
Definition Angle.hpp:16
void IsInfIsTrueWhenAtLeastOneMemberIsInf()