From 4fa47153bac8c40311b5c53ad7f333573f18bcb4 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Wed, 19 Apr 2017 13:49:44 +0200 Subject: [PATCH] Make Integer representation little endian --- source/tanya/math/mp.d | 246 ++++++++++++++---------------------- source/tanya/math/package.d | 10 +- 2 files changed, 103 insertions(+), 153 deletions(-) diff --git a/source/tanya/math/mp.d b/source/tanya/math/mp.d index 57a8d5c..024a0e4 100644 --- a/source/tanya/math/mp.d +++ b/source/tanya/math/mp.d @@ -129,12 +129,8 @@ struct Integer * Precondition: $(D_INLINECODE allocator !is null) */ this(R)(const Sign sign, R value, shared Allocator allocator = defaultAllocator) + @trusted if (isInputRange!R && hasLength!R && is(Unqual!(ElementType!R) == ubyte)) - out - { - assert(this.size == 0 || this.rep[0] > 0); - } - body { this(allocator); while (!value.empty && value.front == 0) @@ -144,7 +140,14 @@ struct Integer this.rep = allocator.resize(this.rep[0 .. this.size], value.length).ptr; this.size = value.length; this.sign = sign; - value.copy(this.rep[0 .. this.size]); + value.copy(this.rep[0 .. this.size].retro); + } + + private @nogc unittest + { + ubyte[5] range = [ 0x02, 0x11, 0x00, 0x00, 0x01 ]; + auto integer = Integer(Sign.positive, range[]); + assert(equal(range[].retro, integer.rep[0 .. integer.size])); } /** @@ -205,9 +208,9 @@ struct Integer big-endian format. */ mask = 0xff; ubyte shift; - for (auto i = this.size; i; --i, mask <<= 8, shift += 8) + for (size_t i; i < this.size; ++i, mask <<= 8, shift += 8) { - this.rep[i - 1] = cast(ubyte) ((absolute & mask) >> shift); + this.rep[i] = cast(ubyte) ((absolute & mask) >> shift); } } @@ -263,15 +266,15 @@ struct Integer { auto integer = Integer(1019); assert(integer.length == 2); - assert(integer.rep[0] == 0b00000011 && integer.rep[1] == 0b11111011); + assert(integer.rep[1] == 0b00000011 && integer.rep[0] == 0b11111011); integer = 3337; assert(integer.length == 2); - assert(integer.rep[0] == 0b00001101 && integer.rep[1] == 0b00001001); + assert(integer.rep[1] == 0b00001101 && integer.rep[0] == 0b00001001); integer = 688; assert(integer.length == 2); - assert(integer.rep[0] == 0b00000010 && integer.rep[1] == 0b10110000); + assert(integer.rep[1] == 0b00000010 && integer.rep[0] == 0b10110000); integer = 0; assert(integer.length == 0); @@ -283,10 +286,8 @@ struct Integer private void expand() nothrow @trusted @nogc { rep = allocator.resize(this.rep[0 .. this.size], this.size + 1).ptr; + this.rep[this.size] = 0x01; ++this.size; - auto target = this.rep[1 .. this.size].retro; - this.rep[0 .. this.size - 1].retro.copy(target); - this.rep[0] = 0x01; } /* @@ -295,11 +296,12 @@ struct Integer */ private void contract() nothrow @trusted @nogc { - const i = this.rep[0 .. this.size].countUntil!((const ref a) => a != 0); + const i = this.rep[0 .. this.size] + .retro + .countUntil!((const ref a) => a != 0); if (i > 0) { - this.rep[i .. this.size].copy(this.rep[0 .. this.size - i]); this.rep = allocator.resize(this.rep[0 .. this.size], this.size - i).ptr; this.size -= i; } @@ -315,28 +317,22 @@ struct Integer { if (summand.length > this.length) { - const delta = summand.size - this.size; - auto tmp = this.rep[0 .. this.size]; + this.rep = allocator.resize!ubyte(this.rep[0 .. this.size], summand.size).ptr; + this.rep[this.size .. summand.size].initializeAll(); - this.rep = allocator.resize!ubyte(null, summand.size).ptr; - tmp.copy(this.rep[delta .. summand.size]); - this.rep[0 .. delta].initializeAll(); - - allocator.deallocate(tmp[0 .. this.size]); this.size = summand.size; } bool carry; - size_t i = this.size; - size_t j = summand.size; + size_t i; + size_t j; do { uint sum; - --i; - if (j) + if (j < summand.size) { - --j; sum = this.rep[i] + summand.rep[j] + carry; + ++j; } else { @@ -346,7 +342,7 @@ struct Integer carry = sum > 0xff; this.rep[i] = cast(ubyte) sum; } - while (i); + while (++i < this.size); if (carry) { @@ -357,19 +353,18 @@ struct Integer private void subtract(const ref Integer subtrahend) nothrow @trusted @nogc { - size_t i = this.size; - size_t j = subtrahend.size; + size_t i; + size_t j; bool borrow; - while (i) + while (i < this.size) { int difference; - --i; - if (j) + if (j < subtrahend.size) { - --j; difference = this.rep[i] - subtrahend.rep[j] - borrow; + ++j; } else { @@ -377,29 +372,30 @@ struct Integer } borrow = difference < 0; this.rep[i] = cast(ubyte) difference; + + ++i; } - if (borrow && i > 0) + if (borrow && i < this.size && this.rep[i]) { - if (this.rep[i - 1]) // Don't borrow i - { - --this.rep[i - 1]; - } + --this.rep[i]; } contract(); } private int compare(const ref Integer that) const nothrow @trusted @nogc { - if (this.length > that.length) + if (length > that.length) { return 1; } - else if (this.length < that.length) + else if (length < that.length) { return -1; } - return this.rep[0 .. this.size].cmp(that.rep[0 .. that.size]); + return this.rep[0 .. this.size] + .retro + .cmp(that.rep[0 .. that.size].retro); } /** @@ -508,11 +504,6 @@ struct Integer * Returns: $(D_KEYWORD this). */ ref Integer opOpAssign(string op : "+")(const auto ref Integer operand) - out - { - assert(this.size == 0 || this.rep[0] > 0); - } - body { if (this.sign == operand.sign) { @@ -544,19 +535,19 @@ struct Integer auto h2 = Integer(3337); h1 += h2; assert(h1.length == 2); - assert(h1.rep[0] == 0x11 && h1.rep[1] == 0x04); + assert(h1.rep[1] == 0x11 && h1.rep[0] == 0x04); } { auto h1 = Integer(4356); auto h2 = Integer(2_147_483_647); - ubyte[4] expected = [0x80, 0x00, 0x11, 0x03]; + ubyte[4] expected = [ 0x03, 0x11, 0x00, 0x80 ]; h1 += h2; assert(h1.rep[0 .. h1.size] == expected); } { auto h1 = Integer(2147488003L); auto h2 = Integer(2_147_483_647); - ubyte[5] expected = [0x01, 0x00, 0x00, 0x11, 0x02]; + ubyte[5] expected = [ 0x02, 0x11, 0x00, 0x00, 0x01 ]; h1 += h2; assert(h1.rep[0 .. h1.size] == expected); } @@ -564,11 +555,6 @@ struct Integer /// Ditto. ref Integer opOpAssign(string op : "-")(const auto ref Integer operand) - out - { - assert(this.size == 0 || this.rep[0] > 0); - } - body { if (operand.sign == this.sign) { @@ -608,12 +594,12 @@ struct Integer h1 -= h2; assert(h1.length == 1); assert(h1.rep[0] == 0x01); - assert(h1.sign); + assert(h1.sign == Sign.negative); } { auto h1 = Integer(8589934590L); auto h2 = Integer(2147483647); - ubyte[5] expected = [0x01, 0x7f, 0xff, 0xff, 0xff]; + ubyte[5] expected = [ 0xff, 0xff, 0xff, 0x7f, 0x01 ]; h1 -= h2; assert(h1.rep[0 .. h1.size] == expected); @@ -621,7 +607,7 @@ struct Integer { auto h1 = Integer(6442450943); auto h2 = Integer(4294967294); - ubyte[4] expected = [0x80, 0x00, 0x00, 0x01]; + ubyte[4] expected = [ 0x01, 0x00, 0x00, 0x80 ]; h1 -= h2; assert(h1.rep[0 .. h1.size] == expected); } @@ -635,18 +621,13 @@ struct Integer /// Ditto. ref Integer opOpAssign(string op : "*")(const auto ref Integer operand) @trusted - out { - assert(this.size == 0 || this.rep[0] > 0); - } - body - { - size_t i = operand.size; + size_t i; if (this.length == 0) { return this; } - else if (i == 0) + else if (operand.length == 0) { this = 0; return this; @@ -657,7 +638,6 @@ struct Integer this = 0; do { - --i; for (ubyte mask = 0x01; mask; mask <<= 1) { if (mask & operand.rep[i]) @@ -666,8 +646,9 @@ struct Integer } temp <<= 1; } + ++i; } - while (i); + while (i < operand.size); this.sign = sign ? Sign.negative : Sign.positive; @@ -691,20 +672,14 @@ struct Integer /// Ditto. ref Integer opOpAssign(string op : "^^")(const auto ref Integer operand) @trusted - out { - assert(this.size == 0 || this.rep[0] > 0); - } - body - { - size_t i = operand.size; + size_t i; auto tmp1 = Integer(this, this.allocator); this = 1; do { - --i; for (ubyte mask = 0x01; mask; mask <<= 1) { if (operand.rep[i] & mask) @@ -715,8 +690,9 @@ struct Integer auto tmp2 = tmp1; tmp1 *= tmp2; } + ++i; } - while (i); + while (i < operand.size); return this; } @@ -732,7 +708,7 @@ struct Integer h1 = Integer(2342); h1 ^^= h2; - ubyte[6] expected = [0x1b, 0x5c, 0xab, 0x9c, 0x31, 0x10]; + ubyte[6] expected = [ 0x10, 0x31, 0x9c, 0xab, 0x5c, 0x1b ]; assert(h1.rep[0 .. h1.size] == expected); } @@ -743,10 +719,6 @@ struct Integer { assert(operand.length > 0, "Division by zero."); } - out - { - assert(this.size == 0 || this.rep[0] > 0); - } body { auto divisor = Integer(operand, this.allocator); @@ -774,7 +746,7 @@ struct Integer subtract(divisor); // dividend -= divisor static if (op == "/") { - quotient[bitPosition / 8] |= 0x80 >> (bitPosition % 8); + quotient[$ - 1 - bitPosition / 8] |= 0x80 >> (bitPosition % 8); } } if (bitSize != 0) @@ -823,11 +795,6 @@ struct Integer /// Ditto. ref Integer opOpAssign(string op : ">>")(const size_t operand) @trusted - out - { - assert(this.size == 0 || this.rep[0] > 0); - } - body { const step = operand / 8; @@ -843,20 +810,18 @@ struct Integer const bit = operand % 8; const delta = 8 - bit; - carry = cast(ubyte) (this.rep[0] << delta); - this.rep[0] = this.rep[0] >> bit; - if (rep[0]) + for (j = step; j < length - 1; ++i, ++j) { - ++j; + carry = cast(ubyte) (this.rep[i + 1] << delta); + this.rep[i] = (this.rep[i] >> bit) | carry; } - for (i = 1; i < this.length; ++i) + + this.rep[i] = this.rep[j] >> bit; + size_t newSize = length - step; + if (this.rep[i] == 0) { - immutable oldCarry = carry; - carry = cast(ubyte) (this.rep[i] << delta); - this.rep[j] = this.rep[i] >> bit | oldCarry; - ++j; + --newSize; } - const newSize = this.length - operand / 8 - (i == j ? 0 : 1); this.rep = allocator.resize(this.rep[0 .. this.size], newSize).ptr; this.size = newSize; @@ -868,21 +833,21 @@ struct Integer auto integer = Integer(4294967294); integer >>= 10; assert(integer.length == 3); - assert(integer.rep[0] == 0x3f && integer.rep[1] == 0xff && integer.rep[2] == 0xff); + assert(integer.rep[2] == 0x3f && integer.rep[1] == 0xff && integer.rep[0] == 0xff); integer = 27336704; integer >>= 1; assert(integer.length == 3); - assert(integer.rep[0] == 0xd0 && integer.rep[1] == 0x90 && integer.rep[2] == 0x00); + assert(integer.rep[2] == 0xd0 && integer.rep[1] == 0x90 && integer.rep[0] == 0x00); integer = 4294967294; integer >>= 20; assert(integer.length == 2); - assert(integer.rep[0] == 0x0f && integer.rep[1] == 0xff); + assert(integer.rep[1] == 0x0f && integer.rep[0] == 0xff); integer >>= 0; assert(integer.length == 2); - assert(integer.rep[0] == 0x0f && integer.rep[1] == 0xff); + assert(integer.rep[1] == 0x0f && integer.rep[0] == 0xff); integer >>= 20; assert(integer.length == 0); @@ -893,7 +858,7 @@ struct Integer integer = 1431655765; integer >>= 16; assert(integer.length == 2); - assert(integer.rep[0] == 0x55 && integer.rep[1] == 0x55); + assert(integer.rep[1] == 0x55 && integer.rep[0] == 0x55); integer >>= 16; assert(integer.length == 0); @@ -901,50 +866,45 @@ struct Integer /// Ditto. ref Integer opOpAssign(string op : "<<")(const size_t operand) @trusted - out { - assert(this.size == 0 || this.rep[0] > 0); - } - body - { - ubyte carry; auto i = this.length; size_t j; + size_t newSize; const bit = operand % 8; const delta = 8 - bit; + const step = operand / 8; - if (cast(ubyte) (this.rep[0] >> delta)) + auto carry = cast(ubyte) (this.rep[this.size - 1] >> delta); + if (carry != 0) { - const newSize = i + operand / 8 + 1; + newSize = length + step + 1; this.rep = allocator.resize(this.rep[0 .. this.size], newSize).ptr; this.size = newSize; - j = i + 1; + j = newSize - 1; + this.rep[j] = carry; } else { - const newSize = i + operand / 8; + newSize = length + step; this.rep = allocator.resize(this.rep[0 .. this.size], newSize).ptr; - j = i; + this.size = j = newSize; } - do + + --i, --j; + for (; i > 0; --i, --j) { - --i, --j; - const oldCarry = carry; - carry = rep[i] >> delta; - rep[j] = cast(ubyte) ((this.rep[i] << bit) | oldCarry); - } - while (i); - if (carry) - { - rep[0] = carry; + this.rep[i] = cast(ubyte) (this.rep[j] << bit) | (this.rep[j - 1] >> delta); } + this.rep[i] = cast(ubyte) (this.rep[j] << bit); + this.rep[0 .. step].fill(cast(ubyte) 0); + return this; } private @nogc unittest { auto integer = Integer(4294967295); - ubyte[5] expected = [0x01, 0xff, 0xff, 0xff, 0xfe]; + ubyte[5] expected = [ 0xfe, 0xff, 0xff, 0xff, 0x01 ]; integer <<= 1; assert(integer.rep[0 .. integer.size] == expected); } @@ -956,10 +916,9 @@ struct Integer } body { - auto p = this.rep + this.size; - while (p != this.rep) + for (ubyte* p = this.rep; p < this.rep + this.size; ++p) { - --p, --*p; + --*p; if (*p != ubyte.max) { break; @@ -970,16 +929,16 @@ struct Integer private void increment() nothrow @trusted @nogc { - auto p = this.rep + this.size; - while (p != this.rep) + ubyte* p; + for (p = this.rep; p < this.rep + this.size; ++p) { - --p, ++*p; + ++*p; if (*p > 0) { return; } } - if (p == this.rep) + if (p == this.rep + this.size) { expand(); } @@ -1054,11 +1013,6 @@ struct Integer /// Ditto. ref Integer opUnary(string op : "++")() - out - { - assert(this.size == 0 || this.rep[0] > 0); - } - body { if (this.sign) { @@ -1077,11 +1031,6 @@ struct Integer /// Ditto. ref Integer opUnary(string op : "--")() - out - { - assert(this.size == 0 || this.rep[0] > 0); - } - body { if (this.sign) { @@ -1108,11 +1057,11 @@ struct Integer integer = 511; ++integer; assert(integer.length == 2); - assert(integer.rep[0] == 0x02 && integer.rep[1] == 0x00); + assert(integer.rep[1] == 0x02 && integer.rep[0] == 0x00); --integer; assert(integer.length == 2); - assert(integer.rep[0] == 0x01 && integer.rep[1] == 0xff); + assert(integer.rep[1] == 0x01 && integer.rep[0] == 0xff); integer = 79; ++integer; @@ -1126,11 +1075,11 @@ struct Integer integer = 65535; ++integer; assert(integer.length == 3); - assert(integer.rep[0] == 0x01 && integer.rep[1] == 0x00 && integer.rep[2] == 0x00); + assert(integer.rep[2] == 0x01 && integer.rep[1] == 0x00 && integer.rep[0] == 0x00); --integer; assert(integer.length == 2); - assert(integer.rep[0] == 0xff && integer.rep[1] == 0xff); + assert(integer.rep[1] == 0xff && integer.rep[0] == 0xff); integer = -2; ++integer; @@ -1217,10 +1166,11 @@ struct Integer return 0; } T ret; - const(ubyte)* src = this.rep + this.size - 1; - for (ubyte shift; src >= this.rep && shift <= T.sizeof * 8; --src, shift += 8) + const(ubyte)* src = this.rep; + ubyte shift; + for (; src < this.rep + this.size && shift <= T.sizeof * 8; ++src, shift += 8) { - ret |= cast(T) (*src) << shift; + ret |= (cast(T) *src) << shift; } return ret; } diff --git a/source/tanya/math/package.d b/source/tanya/math/package.d index 994d5c7..fd5f2a2 100644 --- a/source/tanya/math/package.d +++ b/source/tanya/math/package.d @@ -87,21 +87,20 @@ in } body { - size_t i = y.length; + size_t i; auto tmp1 = Integer(x, x.allocator); auto result = Integer(x.allocator); - if (x.length == 0 && i != 0) + if (x.length == 0 && y.length != 0) { - i = 0; + i = y.length; } else { result = 1; } - while (i) + while (i < y.length) { - --i; for (ubyte mask = 0x01; mask; mask <<= 1) { if (y.rep[i] & mask) @@ -113,6 +112,7 @@ body tmp1 *= tmp2; tmp1 %= z; } + ++i; } return result; }