Optimize my code =)
bearophile
bearophileHUGS at lycos.com
Mon Feb 17 03:34:42 PST 2014
Robin:
> http://dpaste.dzfl.pl/3df8694eb47d
I think it's better to improve your code iteratively. First
starting with small simple things:
> this(size_t rows, size_t cols) nothrow pure {
=>
this(in size_t rows, in size_t cols) nothrow pure {
> this(ref const(Dimension) that) nothrow pure {
=>
this(const ref Dimension that) nothrow pure {
> ref Dimension opAssign(ref Dimension rhs) nothrow pure {
Is this method necessary?
> bool opEquals(ref const(Dimension) other) nothrow const {
Not necessary.
> size_t min() @property nothrow const {
> if (this.rows <= this.cols) return this.rows;
> else return this.cols;
> }
=> (I have changed its name to reduce my confusion
std.algorithm.min):
@property size_t minSide() const pure nothrow {
return (rows <= cols) ? rows : cols;
}
> size_t size() @property nothrow const {
=>
@property size_t size() @property pure nothrow {
> size_t offset(size_t row, size_t col) nothrow const {
=>
size_t offset(in size_t row, in size_t col) const pure nothrow {
> this(in size_t rows, in size_t cols, bool initialize = true)
> nothrow pure {
> this.dim = Dimension(rows, cols);
> this.data =
> minimallyInitializedArray!(typeof(this.data))(rows * cols);
> if (initialize) this.data[] = to!T(0);
> }
=>
this(in size_t rows, in size_t cols, in bool initialize =
true) nothrow pure {
...
if (initialize)
this.data[] = 0;
> /**
> *
> */
Sometimes I prefer to use just one line of code to reduce
vertical wasted space:
/// Move constructor. From rvalue.
> this(ref const(Matrix) that) {
=>
this(const ref Matrix that) pure {
> this.data = that.data.dup;
Currently array.dup is not nothrow. This will eventually be fixed.
> ref Matrix transpose() const {
> return Matrix(this).transposeAssign();
=>
ref Matrix transpose() const pure nothrow {
return Matrix(this).transposeAssign;
> ref Matrix transposeAssign() nothrow {
> size_t r, c;
> for (r = 0; r < this.dim.rows; ++r) {
> for (c = 0; c < r; ++c) {
> std.algorithm.swap(
> this.data[this.dim.offset(r, c)],
> this.data[this.dim.offset(c, r)]);
> }
> }
> return this;
> }
Use immutable foreach loops.
And even when you use for loops always define the loop variable
inside the for: "for (size_t r = 0; ...".
Also in general I suggest you to write a little less code.
A first try (not tested), but probably this can be done with much
less multiplications:
ref Matrix transposeAssign() pure nothrow {
foreach (immutable r; 0 .. dim.rows) {
foreach (immutable c; 0 .. r) {
swap(data[dim.offset(r, c)], data[dim.offset(c,
r)]);
}
}
return this;
}
> Matrix opMul(ref const(Matrix) other)
Never use old-style operator overloading in new D code. Use only
the new operator overloading style.
> auto s = Matrix(other).transposeAssign();
=>
> auto s = Matrix(other).transposeAssign;
> size_t r1, r2, c;
Ditto.
> foreach (ref T element; this.data) {
> element *= scalar;
> }
Try to use:
data[] *= scalar;
> for (auto i = 0; i < this.dim.size; ++i) {
> this.data[i] += other.data[i];
> }
Try to use:
data[] += other.data[];
> for (auto i = 0; i < this.dim.size; ++i) {
> this.data[i] -= other.data[i];
> }
Try to use:
data[] -= other.data[];
> bool opEquals(ref const(Matrix) other) nothrow const {
> if (this.dim != other.dim) {
> return false;
> }
> for (auto i = 0; i < this.dim.size; ++i) {
> if (this.data[i] != other.data[i]) return false;
> }
> return true;
> }
Try (in general try to write less code):
return dim == other.dim && data == other.data;
> auto stringBuilder = std.array.appender!string;
=>
Appender!string result;
> stringBuilder.put("Matrix: "
> ~ to!string(this.dim.rows) ~ " x " ~
> to!string(this.dim.cols)
=>
result ~= text("Matrix: ", dim.rows, " x ", dim.cols
> auto m = Matrix(rows, cols);
> for (auto i = 0; i < m.dim.min; ++i) {
> m[i, i] = 1;
> }
See the comment by John Colvin.
> auto generator = Random(unpredictableSeed);
What if I want to fill the matrix deterministically, with a given
seed? In general it's better to not add a random matrix method to
your matrix struct. Better to add an external free function that
uses UFCS and is more flexible and simpler to reason about.
> writeln("\tTime required: " ~ to!string(secs) ~ " secs, " ~
> to!string(msecs) ~ " msecs");
Use .text to strinify, but here you don't need to stringify at
all:
=>
writeln("\tTime required: ", secs, " secs, ", msecs, "
msecs");
> sw.reset();
=>
sw.reset;
> void multiplicationTest() {
In D there is also unittest {}. A benchmark is not exactly an
unit test, so do as you prefer.
Bye,
bearophile
More information about the Digitalmars-d-learn
mailing list