void math(ErrorContext &ec, int level) { ec.DESC("--- Arithmetic operators ---"); // Note that these tests depend heavily on previously tested operations! // They should not be run unless everything else checks out OK. if (!ec.ok()) { ec.DESC("one or more previous failures; skipping this section"); ec.result(false); return; } for (int pass = 1; pass <= level / 2; pass++) { // Make up some dimensions for these matrices. const int x = (pass > 1) ? (rnd(level) + 1) : 0; const int y = (pass > 1) ? (rnd(level) + 1) : 0; const int z = (pass > 1) ? (rnd(level) + 1) : 0; // These will be three random matrices. Matrix a(x, y); Matrix b(x, y); Matrix c(y, z); // These will be the correct results of arithmetic operations. Matrix a_plus_b(x, y); Matrix a_minus_b(x, y); Matrix a_times_c(x, z); // Fill in the values and results. for (int ix = 0; ix < x; ix++) { for (int iy = 0; iy < y; iy++) { const int va = rnd(); const int vb = rnd(); a.setelem(ix, iy, va); b.setelem(ix, iy, vb); a_plus_b.setelem(ix, iy, va + vb); a_minus_b.setelem(ix, iy, va - vb); } } for (int iy = 0; iy < y; iy++) { for (int iz = 0; iz < z; iz++) { const int vc = rnd(); c.setelem(iy, iz, vc); for (int ix = 0; ix < x; ix++) { a_times_c.setelem(ix, iz, a_times_c.getelem(ix, iz) + vc * a.getelem(ix, iy)); } } } // Set up read-only copies of the three reference matrices. const Matrix copy_a = a; const Matrix copy_b = b; const Matrix copy_c = c; // Check non-destructive addition. { ostringstream oss; oss << "(" << x << " by " << y << ") + (" << x << " by " << y << ")" << ", return value" << ends; ec.DESC(oss.str()); ec.result(copy_a + copy_b == a_plus_b); } // Ensure arguments were not altered. { ostringstream oss; oss << "(" << x << " by " << y << ") + (" << x << " by " << y << ")" << ", side effects" << ends; ec.DESC(oss.str()); ec.result(copy_a == a && copy_b == b); } // Check non-destructive subtraction. { ostringstream oss; oss << "(" << x << " by " << y << ") - (" << x << " by " << y << ")" << ", return value" << ends; ec.DESC(oss.str()); ec.result(copy_a - copy_b == a_minus_b); } // Ensure arguments were not altered. { ostringstream oss; oss << "(" << x << " by " << y << ") - (" << x << " by " << y << ")" << ", side effects" << ends; ec.DESC(oss.str()); ec.result(copy_a == a && copy_b == b); } // Check non-destructive multiplication. { ostringstream oss; oss << "(" << x << " by " << y << ") * (" << y << " by " << z << ")" << ", return value" << ends; ec.DESC(oss.str()); ec.result(copy_a * copy_c == a_times_c); } // Ensure arguments were not altered. { ostringstream oss; oss << "(" << x << " by " << y << ") * (" << y << " by " << z << ")" << ", side effects" << ends; ec.DESC(oss.str()); ec.result(copy_a == a && copy_c == c); } // Check destructive addition. { ostringstream oss; oss << "(" << x << " by " << y << ") += (" << x << " by " << y << ")" << ", return value" << ends; ec.DESC(oss.str()); ec.result((a_minus_b += copy_b) == copy_a); } // Ensure LHS was altered and RHS was not. { ostringstream oss; oss << "(" << x << " by " << y << ") += (" << x << " by " << y << ")" << ", side effects" << ends; ec.DESC(oss.str()); ec.result(a_minus_b == copy_a && copy_b == b); } // Check destructive subtraction. { ostringstream oss; oss << "(" << x << " by " << y << ") -= (" << x << " by " << y << ")" << ", return value" << ends; ec.DESC(oss.str()); ec.result((a_plus_b -= b) == copy_a); } // Ensure LHS was altered and RHS was not. { ostringstream oss; oss << "(" << x << " by " << y << ") -= (" << x << " by " << y << ")" << ", side effects" << ends; ec.DESC(oss.str()); ec.result(a_plus_b == copy_a && copy_b == b); } // Check destructive multiplication. { ostringstream oss; oss << "(" << x << " by " << y << ") *= (" << y << " by " << z << ")" << ", return value" << ends; ec.DESC(oss.str()); ec.result((a *= copy_c) == a_times_c); } // Ensure LHS was altered and RHS was not. { ostringstream oss; oss << "(" << x << " by " << y << ") *= (" << y << " by " << z << ")" << ", side effects" << ends; ec.DESC(oss.str()); ec.result(a == a_times_c && copy_c == c); } } }