summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2017-04-20 17:32:29 +0200
committerEugen Wissner <belka@caraus.de>2017-04-20 17:32:29 +0200
commit3d64d59ba9c706b7cbab1d2a79f8896e024cc2de (patch)
treecd171ae24abfe399e1ad963ec77bdc1953eab48f
parent4635835a991164a54b425ee9b35427957623589e (diff)
parent8725ec5f20356a31b5292abb9eb3a18ec9a7d93c (diff)
downloadtanya-3d64d59ba9c706b7cbab1d2a79f8896e024cc2de.tar.gz
Merge branch 'master' of github.com:caraus-ecms/tanya
-rw-r--r--source/tanya/math/mp.d246
-rw-r--r--source/tanya/math/package.d10
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(null, summand.size).ptr;
- tmp.copy(this.rep[delta .. summand.size]);
- this.rep[0 .. delta].initializeAll();
+ this.rep = allocator.resize!ubyte(this.rep[0 .. this.size], summand.size).ptr;
+ this.rep[this.size .. summand.size].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;
- const oldCarry = carry;
- carry = rep[i] >> delta;
- rep[j] = cast(ubyte) ((this.rep[i] << bit) | oldCarry);
- }
- while (i);
- if (carry)
+
+ --i, --j;
+ for (; i > 0; --i, --j)
{
- 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;
}