Fix subtraction of numbers with different signs

This commit is contained in:
Eugen Wissner 2016-12-08 18:30:22 +01:00
parent 77dca31261
commit a2dadda511
3 changed files with 62 additions and 43 deletions

View File

@ -3,14 +3,18 @@
[![Build Status](https://travis-ci.org/caraus-ecms/tanya.svg?branch=master)](https://travis-ci.org/caraus-ecms/tanya)
[![License](http://img.shields.io/badge/license-MPL2-blue.svg)](https://raw.githubusercontent.com/caraus-ecms/tanya/master/LICENSE)
tanya is a general purpose library for D programming language that doesn't rely on the Garbage Collector.
Tanya is a general purpose library for D programming language that doesn't
rely on the Garbage Collector.
# Overview
The library is currently in development.
The library consists of the following packages:
## Overview
Tanya consists of the following packages:
* `async`: Event loop.
* `containers`: Queue, Vector, Singly linked list.
* `container`: Queue, Vector, Singly linked list.
* `crypto`: Work in progress TLS implementation.
* `math`: Multiple precision integer and a set of functions.
* `memory`: Tools for manual memory management (allocator, reference counting, helper functions).
* `network`: URL-Parsing, sockets.

View File

@ -18,9 +18,12 @@ import std.range;
import std.traits;
import tanya.memory;
/**
* Mutliple precision integer.
*/
struct Integer
{
private RefCounted!(ubyte[]) rep;
private RefCounted!(ubyte[]) rep;
private bool sign;
private shared Allocator allocator;
@ -47,11 +50,7 @@ struct Integer
body
{
this(allocator);
T absolute = value;
immutable size = calculateSizeFromInt(absolute);
allocator.resizeArray(rep, size);
assignInt(absolute);
assignInt(value);
}
private @nogc unittest
@ -93,10 +92,10 @@ struct Integer
/*
* Figures out the minimum amount of space this value will take
* up in bytes. Set the sign.
* up in bytes and resizes the internal storage. Sets the sign.
*/
private ubyte calculateSizeFromInt(T)(ref T value)
pure nothrow @safe @nogc
private void assignInt(T)(in ref T value)
nothrow @safe @nogc
in
{
static assert(isIntegral!T);
@ -104,40 +103,36 @@ struct Integer
body
{
ubyte size = ulong.sizeof;
ulong mask;
static if (isSigned!T)
{
sign = value < 0 ? true : false;
value = abs(value);
immutable absolute = value.abs;
}
else
{
sign = false;
alias absolute = value;
}
for (ulong mask = 0xff00000000000000; mask >= 0xff; mask >>= 8)
for (mask = 0xff00000000000000; mask >= 0xff; mask >>= 8)
{
if (value & mask)
if (absolute & mask)
{
break;
}
--size;
}
return size;
}
/*
* Work backward through the int, masking off each byte
* (up to the first 0 byte) and copy it into the internal
* representation in big-endian format.
*/
private void assignInt(in ulong value)
pure nothrow @safe @nogc
{
ulong mask = 0xff;
allocator.resizeArray(rep.get, size);
/* Work backward through the int, masking off each byte (up to the
first 0 byte) and copy it into the internal representation in
big-endian format. */
mask = 0xff;
ushort shift;
for (auto i = length; i; --i, mask <<= 8, shift += 8)
for (auto i = rep.length; i; --i, mask <<= 8, shift += 8)
{
rep[i - 1] = cast(ubyte) ((value & mask) >> shift);
rep[i - 1] = cast(ubyte) ((absolute & mask) >> shift);
}
}
@ -153,12 +148,8 @@ struct Integer
ref Integer opAssign(T)(in T value) nothrow @safe @nogc
if (isIntegral!T)
{
T absolute = value;
immutable size = calculateSizeFromInt(absolute);
checkAllocator();
allocator.resizeArray(rep.get, size);
assignInt(absolute);
assignInt(value);
return this;
}
@ -278,8 +269,6 @@ struct Integer
uint sum;
uint carry = 0;
// Adding h2 to h1. If h2 is > h1 to begin with, resize h1
if (h.length > length)
{
auto tmp = allocator.makeArray!ubyte(h.length);
@ -311,7 +300,7 @@ struct Integer
{
// Still overflowed; allocate more space
auto tmp = allocator.makeArray!ubyte(length + 1);
tmp[1..$] = rep[0..length];
tmp[1 .. $] = rep[0..length];
tmp[0] = 0x01;
rep = tmp;
}
@ -373,6 +362,11 @@ struct Integer
*/
ref Integer opOpAssign(string op)(in Integer h) nothrow @safe @nogc
if ((op == "+") || (op == "-"))
out
{
assert(!rep.length || rep[0]);
}
body
{
checkAllocator();
static if (op == "+")
@ -414,7 +408,7 @@ struct Integer
}
else
{
subtract(h.rep);
add(h.rep);
}
}
return this;
@ -481,6 +475,11 @@ struct Integer
/// Ditto.
ref Integer opOpAssign(string op)(in Integer h) nothrow @safe @nogc
if (op == "*")
out
{
assert(!rep.length || rep[0]);
}
body
{
auto i = h.rep.length;
auto temp = Integer(this, allocator);
@ -598,6 +597,11 @@ struct Integer
/// Ditto.
ref Integer opOpAssign(string op)(in Integer exp) nothrow @safe @nogc
if (op == "^^")
out
{
assert(!rep.length || rep[0]);
}
body
{
auto i = exp.rep.length;
auto tmp1 = Integer(this, allocator);
@ -738,6 +742,11 @@ struct Integer
*/
ref Integer opUnary(string op)() nothrow @safe @nogc
if ((op == "++") || (op == "--"))
out
{
assert(!rep.length || rep[0]);
}
body
{
checkAllocator();
@ -878,6 +887,11 @@ struct Integer
*/
ref Integer opOpAssign(string op)(in size_t n) nothrow @safe @nogc
if (op == ">>")
out
{
assert(!rep.length || rep[0]);
}
body
{
immutable step = n / 8;
@ -950,6 +964,11 @@ struct Integer
/// Ditto.
ref Integer opOpAssign(string op)(in size_t n) nothrow @safe @nogc
if (op == "<<")
out
{
assert(!rep.length || rep[0]);
}
body
{
ubyte carry;
auto i = rep.length;

View File

@ -316,10 +316,6 @@ private unittest
* $(D_PSYMBOL RefCounted) using $(D_PARAM args) as the parameter list for
* the constructor of $(D_PARAM T).
*
* This function is more efficient than using $(D_PSYMBOL RefCounted)
* for the new objects directly, since $(D_PSYMBOL refCounted) allocates
* only once (the object and the internal storage are allocated at once).
*
* Params:
* T = Type of the constructed object.
* A = Types of the arguments to the constructor of $(D_PARAM T).