2
0
Эх сурвалжийг харах

BigInt improvments. Stop Lua test (#12319)

* Add BigInteger type

* Change sign to return 1 for positive,0 for zero
flashultra 1 өдөр өмнө
parent
commit
0db606040b

+ 3 - 3
std/haxe/math/bigint/BigInt.hx

@@ -170,13 +170,13 @@ abstract BigInt(BigInt_) {
 	}
 
 	/**
-		Creates a `BigInt` from a hexadecimal string. Assumes signed representation.
-		This is a shorthand for `fromHexSigned(value)`.
+		Creates a `BigInt` from a hexadecimal string. Assumes unsigned representation.
+		This is a shorthand for `fromHexUnsigned(value)`.
 		@param value The hexadecimal string.
 		@return A new `BigInt` instance.
 	**/
 	public static inline function fromHex(value:String):BigInt {
-		return fromHexSigned(value);
+		return fromHexUnsigned(value);
 	}
 
 	/**

+ 213 - 65
std/haxe/math/bigint/BigIntArithmetic.hx

@@ -42,7 +42,7 @@ class BigIntArithmetic {
 	**/
 	public static function compareInt(a:BigInt_, b:Int):Int {
 		if (a.m_count > 1) {
-			return (a.sign() << 1) + 1;
+			return a.sign();
 		}
 		var x:Int = a.m_data.get(0);
 		var lt:Int = (x - b) ^ ((x ^ b) & ((x - b) ^ x)); // "Hacker's Delight" p. 23
@@ -59,20 +59,20 @@ class BigIntArithmetic {
 	**/
 	public static function compare(a:BigInt_, b:BigInt_):Int {
 		if (a != b) {
-			var c:Int = (a.sign() & 2) + (b.sign() & 1);
+			var c:Int = (a.sign() & 7) + (b.sign() & 3);
 			switch (c) {
-				case 0: // a and b are positive
+				case 1, 2: // a and b are positive
 					if (a.m_count > b.m_count) {
 						return 1;
 					}
 					if (a.m_count < b.m_count) {
 						return -1;
 					}
-				case 1: // a is positive, b is negative
+				case 3, 4: // a is positive, b is negative
 					return 1;
-				case 2: // a is negative, b is positive
+				case 7, 8: // a is negative, b is positive
 					return -1;
-				case 3: // a and b are negative
+				case 10: // a and b are negative
 					if (a.m_count > b.m_count) {
 						return -1;
 					}
@@ -137,7 +137,7 @@ class BigIntArithmetic {
 			var o1 = (operand1.m_count > operand2.m_count) ? operand1 : operand2;
 			var o2 = (operand1.m_count > operand2.m_count) ? operand2 : operand1;
 			result.ensureCapacity(o1.m_count + 1, (result == operand1) || (result == operand2));
-			var s:Int = o2.sign();
+			var s:Int = (o2.sign() == -1) ? -1 : 0;
 			for (i in 0...o2.m_count) {
 				x = o1.m_data.get(i);
 				y = o2.m_data.get(i);
@@ -226,7 +226,7 @@ class BigIntArithmetic {
 		} else if (operand1.m_count > operand2.m_count) {
 			// operand1 is longer
 			result.ensureCapacity(operand1.m_count + 1, (result == operand1) || (result == operand2));
-			var s:Int = operand2.sign();
+			var s:Int = (operand2.sign() == -1) ? -1 : 0;
 			for (i in 0...operand2.m_count) {
 				x = operand1.m_data.get(i);
 				y = operand2.m_data.get(i);
@@ -245,7 +245,7 @@ class BigIntArithmetic {
 		} else {
 			// operand2 is longer
 			result.ensureCapacity(operand2.m_count + 1, (result == operand1) || (result == operand2));
-			var s:Int = operand1.sign();
+			var s:Int = (operand1.sign() == -1) ? -1 : 0;
 			for (i in 0...operand1.m_count) {
 				x = operand1.m_data.get(i);
 				y = operand2.m_data.get(i);
@@ -333,7 +333,7 @@ class BigIntArithmetic {
 		or `operand2`; however, `operand1` and `operand2` may be the
 		same object.
 	**/
-	public static function multiply(result:MutableBigInt_, operand1:BigInt_, operand2:BigInt_):Void {
+	private static function multiplyTraditional(result:MutableBigInt_, operand1:BigInt_, operand2:BigInt_):Void {
 		// Implements Figure 8-1 (p. 172) from "Hacker's Delight", Second Edition; Henry S. Warren, Jr.; 2013.
 
 		if ((operand1 == result) || (operand2 == result)) {
@@ -345,11 +345,6 @@ class BigIntArithmetic {
 			return;
 		}
 
-		if ((operand1.bitLength() >= 2500) && (operand2.bitLength() >= 2500)) {
-			multiplyKaratsuba(result, operand1, operand2);
-			return;
-		}
-
 		var resultSize:Int = operand1.m_count + operand2.m_count;
 		result.ensureCapacity(resultSize, false); // always overwrite result
 		for (i in 0...resultSize) {
@@ -437,7 +432,17 @@ class BigIntArithmetic {
 	**/
 	public static function divide(dividend:BigInt_, divisor:BigInt_, quotientOut:MutableBigInt_, remainderOut:MutableBigInt_,
 			work:MutableBigInt_ = null):Void {
-		var c:Int = (dividend.sign() & 2) + (divisor.sign() & 1);
+		var dividendSign = dividend.sign();
+		var divisorSign = divisor.sign();
+
+		// Create a combined case value: 0 = both positive, 1 = dividend positive/divisor negative,
+		// 2 = dividend negative/divisor positive, 3 = both negative
+		var c:Int = 0;
+		if (dividendSign == -1)
+			c += 2;
+		if (divisorSign == -1)
+			c += 1;
+			
 		switch (c) {
 			case 0: // dividend positive, divisor positive
 				multiwordUnsignedDivide(dividend, divisor, quotientOut, remainderOut, work);
@@ -580,7 +585,7 @@ class BigIntArithmetic {
 		var whole:Int = operand2 >> 5; // whole digits portion
 		var n:Int = operand2 & 0x1f; // sub digit poortion
 		if (whole >= operand1.m_count) {
-			result.m_data.set(0, operand1.sign());
+			result.m_data.set(0, (operand1.sign() == -1) ? -1 : 0);
 			result.m_count = 1;
 		} else if (n > 0) {
 			MultiwordArithmetic._asr32(result.m_data, operand1.m_data, operand1.m_count, whole, n);
@@ -615,9 +620,9 @@ class BigIntArithmetic {
 	public static inline function bitwiseAnd(operand1:BigInt_, operand2:BigInt_):BigInt_ {
 		var result:MutableBigInt_ = new MutableBigInt_();
 		if ((operand1.m_count > operand2.m_count)) {
-			result.m_count = (operand2.sign() == 0) ? operand2.m_count : operand1.m_count;
+			result.m_count = (operand2.sign() == 1) ? operand2.m_count : operand1.m_count;
 		} else {
-			result.m_count = (operand1.sign() == 0) ? operand1.m_count : operand2.m_count;
+			result.m_count = (operand1.sign() == 1) ? operand1.m_count : operand2.m_count;
 		}
 		result.ensureCapacity(result.m_count, false);
 		for (i in 0...result.m_count) {
@@ -640,8 +645,8 @@ class BigIntArithmetic {
 		var result:MutableBigInt_ = new MutableBigInt_();
 		result.m_count = (operand1.m_count > operand2.m_count) ? operand1.m_count : operand2.m_count;
 		result.ensureCapacity(result.m_count, false);
-		var operand1Positive:Bool = operand1.sign() == 0;
-		var operand2Positive:Bool = operand2.sign() == 0;
+		var operand1Positive:Bool = operand1.sign() == 1;
+		var operand2Positive:Bool = operand2.sign() == 1;
 		for (i in 0...result.m_count) {
 			if (i > (operand1.m_count - 1)) {
 				result.m_data.set(i, (operand1Positive ? operand2.m_data.get(i) : 0xffffffff));
@@ -663,8 +668,8 @@ class BigIntArithmetic {
 		var result:MutableBigInt_ = new MutableBigInt_();
 		result.m_count = (operand1.m_count > operand2.m_count) ? operand1.m_count : operand2.m_count;
 		result.ensureCapacity(result.m_count, false);
-		var operand1Positive:Bool = operand1.sign() == 0;
-		var operand2Positive:Bool = operand2.sign() == 0;
+		var operand1Positive:Bool = operand1.sign() == 1;
+		var operand2Positive:Bool = operand2.sign() == 1;
 		for (i in 0...result.m_count) {
 			if (i > (operand1.m_count - 1)) {
 				result.m_data.set(i, (operand1Positive ? operand2.m_data.get(i) : (operand2.m_data.get(i) ^ 0xffffffff)));
@@ -701,47 +706,6 @@ class BigIntArithmetic {
 		return (input.m_count << 5) - BigIntHelper.nlz(input.m_data.get(input.m_count - 1));
 	}
 
-	/**
-		Multiply two big integers using the Karatsuba algorithm for performance.
-		@param result The `MutableBigInt_` to store the product.
-		@param x The first operand.
-		@param y The second operand.
-	**/
-	public static function multiplyKaratsuba(result:MutableBigInt_, x:BigInt_, y:BigInt_):Void {
-		var n = (x.bitLength() > y.bitLength()) ? x.bitLength() : y.bitLength();
-		if (n < 2500) {
-			multiply(result, x, y);
-			return;
-		}
-		n = (n + 1) >> 1;
-		var b = new MutableBigInt_();
-		arithmeticShiftRight(b, x, n);
-		var a = new MutableBigInt_();
-		arithmeticShiftLeft(a, b, n);
-		subtract(a, x, a);
-		var d = new MutableBigInt_();
-		arithmeticShiftRight(d, y, n);
-		var c = new MutableBigInt_();
-		arithmeticShiftLeft(c, d, n);
-		subtract(c, y, c);
-		var ac = new MutableBigInt_();
-		multiplyKaratsuba(ac, a, c);
-		var bd = new MutableBigInt_();
-		multiplyKaratsuba(bd, b, d);
-		var abcd = new MutableBigInt_();
-		add(a, a, b);
-		add(c, c, d);
-		multiplyKaratsuba(abcd, a, c);
-		var op1 = new MutableBigInt_();
-		arithmeticShiftLeft(op1, bd, 2 * n);
-		var op2 = new MutableBigInt_();
-		subtract(op2, abcd, ac);
-		subtract(op2, op2, bd);
-		arithmeticShiftLeft(op2, op2, n);
-		add(op2, ac, op2);
-		add(result, op1, op2);
-	}
-
 	//-----------------------------------------------------------------------
 	// Private helpers
 	//-----------------------------------------------------------------------
@@ -794,4 +758,188 @@ class BigIntArithmetic {
 			output.set(outputOffset + i, input.get(inputOffset + i));
 		}
 	}
-}
+	
+	private static function nextPowerOfTwo(value:Int):Int {
+		if (value <= 0)
+			return 1;
+		value--;
+		value |= value >> 1;
+		value |= value >> 2;
+		value |= value >> 4;
+		value |= value >> 8;
+		value |= value >> 16;
+		return value + 1;
+	}
+
+	private static function splitAtPowerOfTwo(value:BigInt_, splitBits:Int, high:MutableBigInt_, low:MutableBigInt_):Void {
+		if (splitBits <= 0) {
+			high.setFromInt(0);
+			low.copyFrom(value);
+			return;
+		}
+
+		var wordBoundary:Int = splitBits >> 5;
+		var bitOffset:Int = splitBits & 0x1f; // modulo 32
+
+		if (wordBoundary >= value.m_count) {
+			high.setFromInt(0);
+			low.copyFrom(value);
+			return;
+		}
+
+		low.ensureCapacity(wordBoundary + 1, false);
+
+		// Copy the lower words
+		for (i in 0...wordBoundary) {
+			low.m_data.set(i, value.m_data.get(i));
+		}
+
+		if (bitOffset > 0 && wordBoundary < value.m_count) {
+			var mask:Int = (1 << bitOffset) - 1;
+			low.m_data.set(wordBoundary, value.m_data.get(wordBoundary) & mask);
+			low.m_count = wordBoundary + 1;
+		} else {
+			low.m_count = wordBoundary;
+		}
+		
+		// Ensure low part is always treated as positive
+		// by adding a leading zero if the most significant bit is set
+		if (low.m_count > 0 && low.m_data.get(low.m_count - 1) < 0) {
+			low.ensureCapacity(low.m_count + 1, false);
+			low.m_data.set(low.m_count, 0);
+			low.m_count++;
+		}
+		
+		low.compact();
+
+		BigIntArithmetic.arithmeticShiftRight(high, value, splitBits);
+	}
+	
+	public static function multiply(result:MutableBigInt_, operand1:BigInt_, operand2:BigInt_):Void {
+		if ((operand1 == result) || (operand2 == result)) {
+			throw new BigIntException(BigIntError.INVALID_ARGUMENT);
+		}
+
+		if (operand1.isZero() || operand2.isZero()) {
+			result.setFromInt(0);
+			return;
+		}
+
+		var bitLength1 = operand1.bitLength();
+		var bitLength2 = operand2.bitLength();
+
+		if (bitLength1 < 512 || bitLength2 < 512) {
+			BigIntArithmetic.multiplyTraditional(result, operand1, operand2);
+			return;
+		}
+
+		var maxBits = (bitLength1 > bitLength2) ? bitLength1 : bitLength2;
+		var splitBits = nextPowerOfTwo(maxBits >> 1);
+
+		if (splitBits < 256)
+			splitBits = 256;
+
+		multiplyKaratsuba(result, operand1, operand2, splitBits);
+	}
+	
+	private static function multiplyKaratsuba(result:MutableBigInt_, x:BigInt_, y:BigInt_, splitBits:Int):Void {
+		if (x.bitLength() < 512 || y.bitLength() < 512) {
+			BigIntArithmetic.multiplyTraditional(result, x, y);
+			return;
+		}
+
+		var x1 = new MutableBigInt_();
+		var x0 = new MutableBigInt_();
+		splitAtPowerOfTwo(x, splitBits, x1, x0);
+
+		var y1 = new MutableBigInt_();
+		var y0 = new MutableBigInt_();
+		splitAtPowerOfTwo(y, splitBits, y1, y0);
+
+		var z2 = new MutableBigInt_(); // x1 * y1
+		var z0 = new MutableBigInt_(); // x0 * y0
+		var z1 = new MutableBigInt_(); // (x1 + x0) * (y1 + y0) - z2 - z0
+
+		//  z2 = x1 * y1
+		multiplyKaratsuba(z2, x1, y1, splitBits >> 1);
+
+		//  z0 = x0 * y0
+		multiplyKaratsuba(z0, x0, y0, splitBits >> 1);
+
+		//  z1 = (x1 + x0) * (y1 + y0) - z2 - z0
+		var sum_x = new MutableBigInt_();
+		var sum_y = new MutableBigInt_();
+		BigIntArithmetic.add(sum_x, x1, x0);
+		BigIntArithmetic.add(sum_y, y1, y0);
+
+		multiplyKaratsuba(z1, sum_x, sum_y, splitBits >> 1);
+		BigIntArithmetic.subtract(z1, z1, z2);
+		BigIntArithmetic.subtract(z1, z1, z0);
+
+		// result = z2 * 2^(2*splitBits) + z1 * 2^splitBits + z0
+		var temp1 = new MutableBigInt_();
+		var temp2 = new MutableBigInt_();
+
+		// z2 * 2^(2*splitBits)
+		BigIntArithmetic.arithmeticShiftLeft(temp1, z2, 2 * splitBits);
+
+		// z1 * 2^splitBits
+		BigIntArithmetic.arithmeticShiftLeft(temp2, z1, splitBits);
+
+		BigIntArithmetic.add(result, temp1, temp2);
+		BigIntArithmetic.add(result, result, z0);
+	}
+	
+	/**
+		Squaring operation using power-of-two splitting.
+		@param result The output BigInt for the square
+		@param operand The operand to square
+	**/
+	public static function square(result:MutableBigInt_, operand:BigInt_):Void {
+		if (operand == result) {
+			throw new BigIntException(BigIntError.INVALID_ARGUMENT);
+		}
+
+		if (operand.isZero()) {
+			result.setFromInt(0);
+			return;
+		}
+
+		var bitLength = operand.bitLength();
+
+		if (bitLength < 512) {
+			BigIntArithmetic.multiplyTraditional(result, operand, operand);
+			return;
+		}
+
+		var splitBits = nextPowerOfTwo(bitLength >> 1);
+		if (splitBits < 256)
+			splitBits = 256;
+
+		var high = new MutableBigInt_();
+		var low = new MutableBigInt_();
+		splitAtPowerOfTwo(operand, splitBits, high, low);
+
+		// Calculate (high + low)^2 = high^2 + 2*high*low + low^2
+		var highSquared = new MutableBigInt_();
+		var lowSquared = new MutableBigInt_();
+		var crossProduct = new MutableBigInt_();
+
+		square(highSquared, high);
+		square(lowSquared, low);
+
+		// Calculate 2 * high * low
+		multiplyKaratsuba(crossProduct, high, low, splitBits >> 1);
+		BigIntArithmetic.arithmeticShiftLeft(crossProduct, crossProduct, 1);
+
+		// Combine results: result = high^2 * 2^(2*splitBits) + 2*high*low * 2^splitBits + low^2
+		var temp1 = new MutableBigInt_();
+		var temp2 = new MutableBigInt_();
+
+		BigIntArithmetic.arithmeticShiftLeft(temp1, highSquared, 2 * splitBits);
+		BigIntArithmetic.arithmeticShiftLeft(temp2, crossProduct, splitBits);
+
+		BigIntArithmetic.add(result, temp1, temp2);
+		BigIntArithmetic.add(result, result, lowSquared);
+	}
+}

+ 4 - 3
std/haxe/math/bigint/BigInt_.hx

@@ -123,10 +123,11 @@ class BigInt_ {
 
 	/**
 		Retrieve the sign value of this big integer.
-		@return 0 if positive or zero, -1 if negative.
+		@return 1 if positive , 0 if zero, -1 if negative.
 	**/
 	public inline function sign():Int {
-		return (m_data.get(m_count - 1) >> 31 != 0) ? -1 : 0;
+		if ( m_count == 1 && m_data.get(0) == 0) return 0;
+		return (m_data.get(m_count - 1) >> 31 != 0) ? -1 : 1;
 	}
 
 	/**
@@ -514,7 +515,7 @@ class BigInt_ {
 	**/
 	public function square():BigInt_ {
 		var r:MutableBigInt_ = new MutableBigInt_();
-		BigIntArithmetic.multiply(r, this, this);
+		BigIntArithmetic.square(r, this);
 		return r;
 	}
 

+ 100 - 45
std/haxe/math/bigint/MutableBigInt_.hx

@@ -81,43 +81,57 @@ class MutableBigInt_ extends BigInt_ {
 		if ((value == null) || (value.length < 1)) {
 			throw new BigIntException(BigIntError.INVALID_ARGUMENT);
 		}
-		var negate = value.charCodeAt(0) == 0x2d;
+
+		var negate = value.charCodeAt(0) == 0x2d; // '-' character
 		var index = negate ? 1 : 0;
+
 		if (value.length <= index) {
 			throw new BigIntException(BigIntError.INVALID_ARGUMENT);
 		}
-		if ( value.charCodeAt(index) ==  0x30) {
-			if ( value.charCodeAt(index+1) ==  0x62 ) { // binary
+
+		if (value.charCodeAt(index) == 0x30) { // '0'
+			if (value.charCodeAt(index + 1) == 0x62) { // 'b' - binary
 				radix = 2;
-				index +=2;
-			} else if ( value.charCodeAt(index+1) ==  0x6F ) { //octal
+				index += 2;
+			} else if (value.charCodeAt(index + 1) == 0x6F) { // 'o' - octal
 				radix = 8;
-				index +=2;
-			} else if ( value.charCodeAt(index+1) ==  0x78 ) { // hex
-				setFromHexSigned((negate?"-":"")+value.substr(index+2));
+				index += 2;
+			} else if (value.charCodeAt(index + 1) == 0x78) { // 'x' - hex
+				_setFromHex(value.substr(index + 2), false);
+				if (negate) {
+					BigIntArithmetic.negate(this, this);
+				}
 				return;
 			}
 		}
-		if (radix == 16) { 
-			setFromHexSigned(value);
+
+		if (radix == 16) {
+			_setFromHex(value.substr(index), false);
+			if (negate) {
+				BigIntArithmetic.negate(this, this);
+			}
 			return;
 		}
+
 		this.setFromInt(0);
 		var t = new MutableBigInt_();
 		var endDigit:Int = 57;
-		var extraEndDigit:Int=0;
-		if (  radix <= 10 ) {
-			endDigit =  48 + radix-1;
+		var extraEndDigit:Int = 0;
+
+		if (radix <= 10) {
+			endDigit = 48 + radix - 1;
 		} else {
-			extraEndDigit =  radix-11;
+			extraEndDigit = radix - 11;
 		}
+
 		for (i in index...value.length) {
 			var c = value.charCodeAt(i);
-			if ( ((48 <= c) && (c <= endDigit)) || (radix > 10 && ( (65<=c && c<=(65+extraEndDigit)) || (97<=c && c<=(97+extraEndDigit)) ) ) ) {
+			if (((48 <= c) && (c <= endDigit))
+				|| (radix > 10 && ((65 <= c && c <= (65 + extraEndDigit)) || (97 <= c && c <= (97 + extraEndDigit))))) {
 				BigIntArithmetic.multiplyInt(t, this, radix);
-				if ( c <= endDigit) {
+				if (c <= endDigit) {
 					BigIntArithmetic.addInt(this, t, c - 48);
-				} else if (c<=(65+extraEndDigit)) {
+				} else if (c <= (65 + extraEndDigit)) {
 					BigIntArithmetic.addInt(this, t, c - 55);
 				} else {
 					BigIntArithmetic.addInt(this, t, c - 87);
@@ -126,6 +140,7 @@ class MutableBigInt_ extends BigInt_ {
 				throw new BigIntException(BigIntError.INVALID_ARGUMENT);
 			}
 		}
+
 		if (negate) {
 			BigIntArithmetic.negate(this, this);
 		}
@@ -420,46 +435,86 @@ class MutableBigInt_ extends BigInt_ {
 		if (value == null) {
 			throw new BigIntException(BigIntError.INVALID_ARGUMENT);
 		}
+
 		var index = value.length;
 		if (index <= 0) {
 			throw new BigIntException(BigIntError.INVALID_ARGUMENT);
 		}
+
+		var hexDigitCount = 0;
+		for (i in 0...index) {
+			var c = value.charCodeAt(i);
+			if (c != 32) { // check for a space
+				hexDigitCount++;
+			}
+		}
+
+		var wordsNeeded = (hexDigitCount + 7) >> 3;
+
+		// For unsigned, we need an extra word if the top bit is set
 		var extra:Int = signed ? 0 : 1;
-		ensureCapacity(((index + 7) >> 3) + extra, false);
-		var pos = -1;
-		var bit:Int = 32;
-		var c:Int32 = 0;
-		while (index > 0) {
-			c = value.charCodeAt(--index);
-			if ((48 <= c) && (c <= 57)) {
-				c -= 48;
-			} else if ((65 <= c) && (c <= 70)) {
-				c -= 55;
-			} else if ((97 <= c) && (c <= 102)) {
-				c -= 87;
-			} else if (c == 32) {
+		ensureCapacity(wordsNeeded + extra, false);
+
+		for (i in 0...wordsNeeded + extra) {
+			m_data.set(i, 0);
+		}
+
+		var wordIndex = 0;
+		var currentWord:Int32 = 0;
+		var bitsInCurrentWord = 0;
+
+		var charIndex = index - 1;
+		while (charIndex >= 0) {
+			var c:Int = value.charCodeAt(charIndex);
+			var digit:Int;
+
+			if ((48 <= c) && (c <= 57)) { // '0'-'9'
+				digit = c - 48;
+			} else if ((65 <= c) && (c <= 70)) { // 'A'-'F'
+				digit = c - 55;
+			} else if ((97 <= c) && (c <= 102)) { // 'a'-'f'
+				digit = c - 87;
+			} else if (c == 32) { // space - skip
+				charIndex--;
 				continue;
 			} else {
 				throw new BigIntException(BigIntError.INVALID_ARGUMENT);
 			}
-			if (bit >= 32) {
-				m_data.set(++pos, 0);
-				bit = 0;
+
+			currentWord |= (digit << bitsInCurrentWord);
+			bitsInCurrentWord += 4;
+
+			if (bitsInCurrentWord >= 32) {
+				m_data.set(wordIndex++, currentWord);
+				currentWord = 0;
+				bitsInCurrentWord = 0;
+			}
+
+			charIndex--;
+		}
+
+		if (bitsInCurrentWord > 0) {
+			if (signed) {
+				var topBit = bitsInCurrentWord - 1;
+				if ((currentWord & (1 << topBit)) != 0) {
+					// Negative number - extend sign bits
+					var mask:Int32 = ~((1 << bitsInCurrentWord) - 1);
+					currentWord |= mask;
+				}
 			}
-			m_data.set(pos, m_data.get(pos) | (c << bit));
-			bit += 4;
-		}
-		// Sign extend
-		m_count = pos + 1;
-		if (signed) {
-			c = ((c & 8) != 0) ? 15 : 0;
-			while (bit < 32) {
-				m_data.set(pos, m_data.get(pos) | (c << bit));
-				bit += 4;
+			m_data.set(wordIndex++, currentWord);
+		}
+
+		m_count = wordIndex;
+
+		// For unsigned,do not interpret as negative
+		if (!signed && m_count > 0) {
+			var topWord = m_data.get(m_count - 1);
+			if (topWord < 0) {
+				m_data.set(m_count++, 0);
 			}
-		} else if (m_data.get(pos) < 0) {
-			m_data.set(m_count++, 0);
 		}
+
 		compact();
 	}
 

+ 123 - 123
tests/unit/src/unit/TestBigInt.hx

@@ -160,10 +160,10 @@ class TestBigInt extends Test {
 		checkCompareInt(0, 2147483647, 2147483647);
 
 		// equality, multi-word
-		checkCompare(0, BigInt.fromHex("12345678 9abcdef0"), BigInt.fromHex("12345678 9abcdef0"));
-		checkCompare(0, BigInt.fromHex("f2345678 9abcdef0"), BigInt.fromHex("f2345678 9abcdef0"));
-		checkCompare(0, BigInt.fromHex("12345678 9abcdef0 12345678"), BigInt.fromHex("12345678 9abcdef0 12345678"));
-		checkCompare(0, BigInt.fromHex("f2345678 9abcdef0 12345678"), BigInt.fromHex("f2345678 9abcdef0 12345678"));
+		checkCompare(0, BigInt.fromHexSigned("12345678 9abcdef0"), BigInt.fromHexSigned("12345678 9abcdef0"));
+		checkCompare(0, BigInt.fromHexSigned("f2345678 9abcdef0"), BigInt.fromHexSigned("f2345678 9abcdef0"));
+		checkCompare(0, BigInt.fromHexSigned("12345678 9abcdef0 12345678"), BigInt.fromHexSigned("12345678 9abcdef0 12345678"));
+		checkCompare(0, BigInt.fromHexSigned("f2345678 9abcdef0 12345678"), BigInt.fromHexSigned("f2345678 9abcdef0 12345678"));
 
 		// less than, single-word
 		checkCompareInt(-1, 0, 1);
@@ -179,17 +179,17 @@ class TestBigInt extends Test {
 		checkCompareInt(-1, -1, 2147483647);
 
 		// less than, multi-word, same length
-		checkCompare(-1, BigInt.fromHex("12345678 9abcdeef"), BigInt.fromHex("12345678 9abcdef0"));
-		checkCompare(-1, BigInt.fromHex("12345677 9abcdef0"), BigInt.fromHex("12345678 9abcdef0"));
-		checkCompare(-1, BigInt.fromHex("f2345678 9abcdef0"), BigInt.fromHex("12345678 9abcdef0"));
-		checkCompare(-1, BigInt.fromHex("f2345678 9abcdeef"), BigInt.fromHex("f2345678 9abcdef0"));
-		checkCompare(-1, BigInt.fromHex("f2345677 9abcdef0"), BigInt.fromHex("f2345678 9abcdef0"));
+		checkCompare(-1, BigInt.fromHexSigned("12345678 9abcdeef"), BigInt.fromHexSigned("12345678 9abcdef0"));
+		checkCompare(-1, BigInt.fromHexSigned("12345677 9abcdef0"), BigInt.fromHexSigned("12345678 9abcdef0"));
+		checkCompare(-1, BigInt.fromHexSigned("f2345678 9abcdef0"), BigInt.fromHexSigned("12345678 9abcdef0"));
+		checkCompare(-1, BigInt.fromHexSigned("f2345678 9abcdeef"), BigInt.fromHexSigned("f2345678 9abcdef0"));
+		checkCompare(-1, BigInt.fromHexSigned("f2345677 9abcdef0"), BigInt.fromHexSigned("f2345678 9abcdef0"));
 
 		// less than, multi-word, different length
-		checkCompare(-1, BigInt.fromHex("12345678 9abcdef0"), BigInt.fromHex("00000001 12345678 9abcdef0"));
-		checkCompare(-1, BigInt.fromHex("f2345678 9abcdef0"), BigInt.fromHex("00000001 12345678 9abcdef0"));
-		checkCompare(-1, BigInt.fromHex("fffffffe 12345678 9abcdef0"), BigInt.fromHex("12345678 9abcdef0"));
-		checkCompare(-1, BigInt.fromHex("fffffffe 12345678 9abcdef0"), BigInt.fromHex("f2345678 9abcdef0"));
+		checkCompare(-1, BigInt.fromHexSigned("12345678 9abcdef0"), BigInt.fromHexSigned("00000001 12345678 9abcdef0"));
+		checkCompare(-1, BigInt.fromHexSigned("f2345678 9abcdef0"), BigInt.fromHexSigned("00000001 12345678 9abcdef0"));
+		checkCompare(-1, BigInt.fromHexSigned("fffffffe 12345678 9abcdef0"), BigInt.fromHexSigned("12345678 9abcdef0"));
+		checkCompare(-1, BigInt.fromHexSigned("fffffffe 12345678 9abcdef0"), BigInt.fromHexSigned("f2345678 9abcdef0"));
 
 		// greater than, single-word
 		checkCompareInt(1, 1, 0);
@@ -200,19 +200,19 @@ class TestBigInt extends Test {
 		checkCompareInt(1, -2147483647, -2147483648);
 
 		// greater than, multi-word, same length
-		checkCompare(1, BigInt.fromHex("12345678 9abcdef1"), BigInt.fromHex("12345678 9abcdef0"));
-		checkCompare(1, BigInt.fromHex("12345679 9abcdef0"), BigInt.fromHex("12345678 9abcdef0"));
-		checkCompare(1, BigInt.fromHex("12345678 9abcdef0"), BigInt.fromHex("f2345678 9abcdef0"));
-		checkCompare(1, BigInt.fromHex("f2345678 9abcdef1"), BigInt.fromHex("f2345678 9abcdef0"));
-		checkCompare(1, BigInt.fromHex("f2345679 9abcdef0"), BigInt.fromHex("f2345678 9abcdef0"));
+		checkCompare(1, BigInt.fromHexSigned("12345678 9abcdef1"), BigInt.fromHexSigned("12345678 9abcdef0"));
+		checkCompare(1, BigInt.fromHexSigned("12345679 9abcdef0"), BigInt.fromHexSigned("12345678 9abcdef0"));
+		checkCompare(1, BigInt.fromHexSigned("12345678 9abcdef0"), BigInt.fromHexSigned("f2345678 9abcdef0"));
+		checkCompare(1, BigInt.fromHexSigned("f2345678 9abcdef1"), BigInt.fromHexSigned("f2345678 9abcdef0"));
+		checkCompare(1, BigInt.fromHexSigned("f2345679 9abcdef0"), BigInt.fromHexSigned("f2345678 9abcdef0"));
 
 		// greater than, multi-word, different length
-		checkCompare(1, BigInt.fromHex("00000001 12345678 9abcdef0"), BigInt.fromHex("12345678 9abcdef0"));
-		checkCompare(1, BigInt.fromHex("00000001 12345678 9abcdef0"), BigInt.fromHex("f2345678 9abcdef0"));
-		checkCompare(1, BigInt.fromHex("12345678 9abcdef0"), BigInt.fromHex("fffffffe 12345678 9abcdef0"));
-		checkCompare(1, BigInt.fromHex("f2345678 9abcdef0"), BigInt.fromHex("fffffffe 12345678 9abcdef0"));
+		checkCompare(1, BigInt.fromHexSigned("00000001 12345678 9abcdef0"), BigInt.fromHexSigned("12345678 9abcdef0"));
+		checkCompare(1, BigInt.fromHexSigned("00000001 12345678 9abcdef0"), BigInt.fromHexSigned("f2345678 9abcdef0"));
+		checkCompare(1, BigInt.fromHexSigned("12345678 9abcdef0"), BigInt.fromHexSigned("fffffffe 12345678 9abcdef0"));
+		checkCompare(1, BigInt.fromHexSigned("f2345678 9abcdef0"), BigInt.fromHexSigned("fffffffe 12345678 9abcdef0"));
 
-		checkCompare(1, BigInt.fromHex("00000001 ffffffff"), BigInt.fromHex("00000001 00000000"));
+		checkCompare(1, BigInt.fromHexSigned("00000001 ffffffff"), BigInt.fromHexSigned("00000001 00000000"));
 	}
 
 	private function checkCompareInt(expected:Int, a:Int, b:Int):Void {
@@ -284,7 +284,7 @@ class TestBigInt extends Test {
 		checkCompareSingle(expected, a, b);
 		checkCompareSingle(-expected, -a, -b);
 		if ((expected != 0) && (a.sign() == b.sign())) {
-			var s:Int = (a.sign() << 1) + 1;
+			var s:Int = a.sign();
 			checkCompareSingle(-s, -a, b);
 			checkCompareSingle(s, a, -b);
 		}
@@ -447,7 +447,7 @@ class TestBigInt extends Test {
 
 		// check quotient overlaps with dividend, special case 3
 		quotient = 11;
-		BigIntArithmetic.divide(quotient, BigInt.fromHex("1 00000000"), quotient, remainder);
+		BigIntArithmetic.divide(quotient, BigInt.fromHexSigned("1 00000000"), quotient, remainder);
 		eq("0", quotient.toString());
 		eq("11", remainder.toString());
 
@@ -476,7 +476,7 @@ class TestBigInt extends Test {
 		eq("0", remainder.toString());
 
 		// check quotient overlaps with divisor, special case 3
-		quotient = BigInt.fromHex("1 00000000");
+		quotient = BigInt.fromHexSigned("1 00000000");
 		BigIntArithmetic.divide(BigInt.fromInt(11), quotient, quotient, remainder);
 		eq("0", quotient.toString());
 		eq("11", remainder.toString());
@@ -507,7 +507,7 @@ class TestBigInt extends Test {
 
 		// check remainder overlaps with dividend, special case 3
 		remainder = 11;
-		BigIntArithmetic.divide(remainder, BigInt.fromHex("1 00000000"), quotient, remainder);
+		BigIntArithmetic.divide(remainder, BigInt.fromHexSigned("1 00000000"), quotient, remainder);
 		eq("0", quotient.toString());
 		eq("11", remainder.toString());
 
@@ -536,7 +536,7 @@ class TestBigInt extends Test {
 		eq("0", remainder.toString());
 
 		// check remainder overlaps with divisor, special case 3
-		remainder = BigInt.fromHex("1 00000000");
+		remainder = BigInt.fromHexSigned("1 00000000");
 		BigIntArithmetic.divide(BigInt.fromInt(11), remainder, quotient, remainder);
 		eq("0", quotient.toString());
 		eq("11", remainder.toString());
@@ -608,11 +608,11 @@ class TestBigInt extends Test {
 		checkLinearEqInt(BigInt.fromInt(5), 3, BigInt.fromInt(1), 2);
 		checkLinearEqInt(BigInt.fromInt(6), 3, BigInt.fromInt(2), 0);
 		checkLinearEqInt(BigInt.fromInt(6), 2, BigInt.fromInt(3), 0);
-		checkLinearEqInt(BigInt.fromHex("12A05F2001"), 81, BigInt.fromInt(987654321), 0);
+		checkLinearEqInt(BigInt.fromHexSigned("12A05F2001"), 81, BigInt.fromInt(987654321), 0);
 
-		checkLinearEq(BigInt.fromHex("0 fffffffe 00000001"), BigInt.fromHex("0 ffffffff"), BigInt.fromHex("0 ffffffff"),
+		checkLinearEq(BigInt.fromHexSigned("0 fffffffe 00000001"), BigInt.fromHexSigned("0 ffffffff"), BigInt.fromHexSigned("0 ffffffff"),
 			BigInt.fromInt(0)); // exercises qhat = 65536
-		checkLinearEq(BigInt.fromHex("00003fff c0000000 7fff8000 00000000"), BigInt.fromHex("7fff8000 00000000"), BigInt.fromHex("00008000 00000001"),
+		checkLinearEq(BigInt.fromHexSigned("00003fff c0000000 7fff8000 00000000"), BigInt.fromHexSigned("7fff8000 00000000"), BigInt.fromHexSigned("00008000 00000001"),
 			BigInt.fromInt(0));
 
 		checkLinearEqInt(BigInt.fromInt(2147483647), 1, BigInt.fromInt(2147483647), 0);
@@ -628,59 +628,59 @@ class TestBigInt extends Test {
 
 		checkLinearEqInt(BigInt.fromInt(2147483647), 2147483647, BigInt.fromInt(1), 0); // exercises use of uninitialized quotient data
 
-		checkLinearEqInt(BigInt.fromHex("100000000"), 1, BigInt.fromHex("100000000"), 0);
-		checkLinearEqInt(BigInt.fromHex("100000000"), 10, BigInt.fromInt(429496729), 6);
-		checkLinearEqInt(BigInt.fromHex("100000000"), 100, BigInt.fromInt(42949672), 96);
-		checkLinearEqInt(BigInt.fromHex("100000000"), 1000, BigInt.fromInt(4294967), 296);
-		checkLinearEqInt(BigInt.fromHex("100000000"), 10000, BigInt.fromInt(429496), 7296);
-		checkLinearEqInt(BigInt.fromHex("100000000"), 100000, BigInt.fromInt(42949), 67296); // exercises rhat >= 65536
-		checkLinearEqInt(BigInt.fromHex("100000000"), 1000000, BigInt.fromInt(4294), 967296);
-		checkLinearEqInt(BigInt.fromHex("100000000"), 10000000, BigInt.fromInt(429), 4967296);
-		checkLinearEqInt(BigInt.fromHex("100000000"), 100000000, BigInt.fromInt(42), 94967296);
-		checkLinearEqInt(BigInt.fromHex("100000000"), 1000000000, BigInt.fromInt(4), 294967296);
-		checkLinearEq(BigInt.fromHex("100000000"), BigInt.fromHex("2540BE400"), BigInt.fromInt(0), BigInt.fromHex("100000000"));
-
-		checkLinearEqInt(BigInt.fromHex("08000"), 1, BigInt.fromHex("08000"), 0);
-		checkLinearEqInt(BigInt.fromHex("080000000"), 1, BigInt.fromHex("080000000"), 0);
-		checkLinearEqInt(BigInt.fromHex("0800000000000"), 1, BigInt.fromHex("0800000000000"), 0);
-		checkLinearEqInt(BigInt.fromHex("08000000000000000"), 1, BigInt.fromHex("08000000000000000"), 0);
-		checkLinearEqInt(BigInt.fromHex("10001"), 2, BigInt.fromHex("08000"), 1);
-		checkLinearEqInt(BigInt.fromHex("100000001"), 2, BigInt.fromHex("080000000"), 1);
-		checkLinearEqInt(BigInt.fromHex("1000000000001"), 2, BigInt.fromHex("0800000000000"), 1);
-		checkLinearEqInt(BigInt.fromHex("10000000000000001"), 2, BigInt.fromHex("08000000000000000"), 1);
-
-		checkLinearEqInt(BigInt.fromHex("0ffffffff"), 1, BigInt.fromHex("0ffffffff"), 0);
-		checkLinearEqInt(BigInt.fromHex("0ffffffffffffffff"), 1, BigInt.fromHex("0ffffffffffffffff"), 0);
-		checkLinearEqInt(BigInt.fromHex("0ffffffffffffffffffffffff"), 1, BigInt.fromHex("0ffffffffffffffffffffffff"), 0);
-		checkLinearEqInt(BigInt.fromHex("0ffffffff"), 2, BigInt.fromHex("07fffffff"), 1);
-		checkLinearEqInt(BigInt.fromHex("0ffffffffffffffff"), 2, BigInt.fromHex("07fffffffffffffff"), 1);
-		checkLinearEqInt(BigInt.fromHex("0ffffffffffffffffffffffff"), 2, BigInt.fromHex("07fffffffffffffffffffffff"), 1);
+		checkLinearEqInt(BigInt.fromHexSigned("100000000"), 1, BigInt.fromHexSigned("100000000"), 0);
+		checkLinearEqInt(BigInt.fromHexSigned("100000000"), 10, BigInt.fromInt(429496729), 6);
+		checkLinearEqInt(BigInt.fromHexSigned("100000000"), 100, BigInt.fromInt(42949672), 96);
+		checkLinearEqInt(BigInt.fromHexSigned("100000000"), 1000, BigInt.fromInt(4294967), 296);
+		checkLinearEqInt(BigInt.fromHexSigned("100000000"), 10000, BigInt.fromInt(429496), 7296);
+		checkLinearEqInt(BigInt.fromHexSigned("100000000"), 100000, BigInt.fromInt(42949), 67296); // exercises rhat >= 65536
+		checkLinearEqInt(BigInt.fromHexSigned("100000000"), 1000000, BigInt.fromInt(4294), 967296);
+		checkLinearEqInt(BigInt.fromHexSigned("100000000"), 10000000, BigInt.fromInt(429), 4967296);
+		checkLinearEqInt(BigInt.fromHexSigned("100000000"), 100000000, BigInt.fromInt(42), 94967296);
+		checkLinearEqInt(BigInt.fromHexSigned("100000000"), 1000000000, BigInt.fromInt(4), 294967296);
+		checkLinearEq(BigInt.fromHexSigned("100000000"), BigInt.fromHexSigned("2540BE400"), BigInt.fromInt(0), BigInt.fromHexSigned("100000000"));
+
+		checkLinearEqInt(BigInt.fromHexSigned("08000"), 1, BigInt.fromHexSigned("08000"), 0);
+		checkLinearEqInt(BigInt.fromHexSigned("080000000"), 1, BigInt.fromHexSigned("080000000"), 0);
+		checkLinearEqInt(BigInt.fromHexSigned("0800000000000"), 1, BigInt.fromHexSigned("0800000000000"), 0);
+		checkLinearEqInt(BigInt.fromHexSigned("08000000000000000"), 1, BigInt.fromHexSigned("08000000000000000"), 0);
+		checkLinearEqInt(BigInt.fromHexSigned("10001"), 2, BigInt.fromHexSigned("08000"), 1);
+		checkLinearEqInt(BigInt.fromHexSigned("100000001"), 2, BigInt.fromHexSigned("080000000"), 1);
+		checkLinearEqInt(BigInt.fromHexSigned("1000000000001"), 2, BigInt.fromHexSigned("0800000000000"), 1);
+		checkLinearEqInt(BigInt.fromHexSigned("10000000000000001"), 2, BigInt.fromHexSigned("08000000000000000"), 1);
+
+		checkLinearEqInt(BigInt.fromHexSigned("0ffffffff"), 1, BigInt.fromHexSigned("0ffffffff"), 0);
+		checkLinearEqInt(BigInt.fromHexSigned("0ffffffffffffffff"), 1, BigInt.fromHexSigned("0ffffffffffffffff"), 0);
+		checkLinearEqInt(BigInt.fromHexSigned("0ffffffffffffffffffffffff"), 1, BigInt.fromHexSigned("0ffffffffffffffffffffffff"), 0);
+		checkLinearEqInt(BigInt.fromHexSigned("0ffffffff"), 2, BigInt.fromHexSigned("07fffffff"), 1);
+		checkLinearEqInt(BigInt.fromHexSigned("0ffffffffffffffff"), 2, BigInt.fromHexSigned("07fffffffffffffff"), 1);
+		checkLinearEqInt(BigInt.fromHexSigned("0ffffffffffffffffffffffff"), 2, BigInt.fromHexSigned("07fffffffffffffffffffffff"), 1);
 
 		// exercise quotient with high bit set when length of divisor == length of dividend and divisor >= 65536
-		checkLinearEq(BigInt.fromHex("4000000000000000"), BigInt.fromHex("080000000"), BigInt.fromHex("080000000"),
+		checkLinearEq(BigInt.fromHexSigned("4000000000000000"), BigInt.fromHexSigned("080000000"), BigInt.fromHexSigned("080000000"),
 			BigInt.fromInt(0)); // exercises uninitialized work data
-		checkLinearEq(BigInt.fromHex("4000000080000000"), BigInt.fromHex("080000001"), BigInt.fromHex("080000000"), BigInt.fromInt(0));
-		checkLinearEq(BigInt.fromHex("4000000100000000"), BigInt.fromHex("080000001"), BigInt.fromHex("080000000"), BigInt.fromHex("080000000"));
-		checkLinearEq(BigInt.fromHex("40000000ffffffff"), BigInt.fromHex("080000001"), BigInt.fromHex("080000000"), BigInt.fromHex("7fffffff"));
-		checkLinearEq(BigInt.fromHex("4000000100000001"), BigInt.fromHex("080000001"), BigInt.fromHex("080000001"), BigInt.fromInt(0));
+		checkLinearEq(BigInt.fromHexSigned("4000000080000000"), BigInt.fromHexSigned("080000001"), BigInt.fromHexSigned("080000000"), BigInt.fromInt(0));
+		checkLinearEq(BigInt.fromHexSigned("4000000100000000"), BigInt.fromHexSigned("080000001"), BigInt.fromHexSigned("080000000"), BigInt.fromHexSigned("080000000"));
+		checkLinearEq(BigInt.fromHexSigned("40000000ffffffff"), BigInt.fromHexSigned("080000001"), BigInt.fromHexSigned("080000000"), BigInt.fromHexSigned("7fffffff"));
+		checkLinearEq(BigInt.fromHexSigned("4000000100000001"), BigInt.fromHexSigned("080000001"), BigInt.fromHexSigned("080000001"), BigInt.fromInt(0));
 
-		checkLinearEq(BigInt.fromHex("08000"), BigInt.fromHex("0800000001"), BigInt.fromHex("0"), BigInt.fromHex("08000"));
+		checkLinearEq(BigInt.fromHexSigned("08000"), BigInt.fromHexSigned("0800000001"), BigInt.fromHexSigned("0"), BigInt.fromHexSigned("08000"));
 		// these exercise the qhat reduction path
-		checkLinearEq(BigInt.fromHex("080000000"), BigInt.fromHex("080000001"), BigInt.fromHex("0"), BigInt.fromHex("080000000"));
-		checkLinearEq(BigInt.fromHex("0800080010000"), BigInt.fromHex("080000001"), BigInt.fromHex("10000"), BigInt.fromHex("080000000"));
-		checkLinearEq(BigInt.fromHex("0800100010001"), BigInt.fromHex("080000001"), BigInt.fromHex("10001"), BigInt.fromHex("080000000"));
-		checkLinearEq(BigInt.fromHex("08000000180000000"), BigInt.fromHex("080000001"), BigInt.fromHex("100000000"), BigInt.fromHex("080000000"));
-		checkLinearEq(BigInt.fromHex("08000000200000001"), BigInt.fromHex("080000001"), BigInt.fromHex("100000001"), BigInt.fromHex("080000000"));
+		checkLinearEq(BigInt.fromHexSigned("080000000"), BigInt.fromHexSigned("080000001"), BigInt.fromHexSigned("0"), BigInt.fromHexSigned("080000000"));
+		checkLinearEq(BigInt.fromHexSigned("0800080010000"), BigInt.fromHexSigned("080000001"), BigInt.fromHexSigned("10000"), BigInt.fromHexSigned("080000000"));
+		checkLinearEq(BigInt.fromHexSigned("0800100010001"), BigInt.fromHexSigned("080000001"), BigInt.fromHexSigned("10001"), BigInt.fromHexSigned("080000000"));
+		checkLinearEq(BigInt.fromHexSigned("08000000180000000"), BigInt.fromHexSigned("080000001"), BigInt.fromHexSigned("100000000"), BigInt.fromHexSigned("080000000"));
+		checkLinearEq(BigInt.fromHexSigned("08000000200000001"), BigInt.fromHexSigned("080000001"), BigInt.fromHexSigned("100000001"), BigInt.fromHexSigned("080000000"));
 
 		// this exercises long division with a quotient with high bit set
-		checkLinearEq(BigInt.fromHex("08000000180000000"), BigInt.fromHex("100000000"), BigInt.fromHex("080000001"), BigInt.fromHex("080000000"));
+		checkLinearEq(BigInt.fromHexSigned("08000000180000000"), BigInt.fromHexSigned("100000000"), BigInt.fromHexSigned("080000001"), BigInt.fromHexSigned("080000000"));
 
 		// these exercise the "add back" path
-		checkLinearEq(BigInt.fromHex("7fff800000000000"), BigInt.fromHex("0800000000001"), BigInt.fromHex("0fffe"), BigInt.fromHex("7fffffff0002"));
-		checkLinearEq(BigInt.fromHex("7fffffff800000010000000000000000"), BigInt.fromHex("0800000008000000200000005"), BigInt.fromHex("0fffffffd"),
-			BigInt.fromHex("080000000800000010000000f"));
+		checkLinearEq(BigInt.fromHexSigned("7fff800000000000"), BigInt.fromHexSigned("0800000000001"), BigInt.fromHexSigned("0fffe"), BigInt.fromHexSigned("7fffffff0002"));
+		checkLinearEq(BigInt.fromHexSigned("7fffffff800000010000000000000000"), BigInt.fromHexSigned("0800000008000000200000005"), BigInt.fromHexSigned("0fffffffd"),
+			BigInt.fromHexSigned("080000000800000010000000f"));
 
-		checkLinearEq(BigInt.fromInt(1), BigInt.fromHex("100000000"), BigInt.fromInt(0), BigInt.fromInt(1));
+		checkLinearEq(BigInt.fromInt(1), BigInt.fromHexSigned("100000000"), BigInt.fromInt(0), BigInt.fromInt(1));
 	}
 
 	private function checkLinearEqInt(y:BigInt, a:Int, x:BigInt, b:Int):Void {
@@ -826,10 +826,10 @@ class TestBigInt extends Test {
 		checkEquality(BigInt.fromInt(1), BigInt.fromInt(1), true);
 		checkEquality(BigInt.fromInt(0x12345678), BigInt.fromInt(0x12345678), true);
 		checkEquality(BigInt.fromInt(0x12345678), BigInt.fromInt(0x12345670), false);
-		checkEquality(BigInt.fromHex("1234567800000000"), BigInt.fromInt(0), false);
-		checkEquality(BigInt.fromHex("1234567800000000"), BigInt.fromHex("1234567800000000"), true);
-		checkEquality(BigInt.fromHex("1234567800000000"), BigInt.fromHex("11234567800000000"), false);
-		checkEquality(BigInt.fromHex("1234567800000000"), BigInt.fromHex("123456780000000"), false);
+		checkEquality(BigInt.fromHexSigned("1234567800000000"), BigInt.fromInt(0), false);
+		checkEquality(BigInt.fromHexSigned("1234567800000000"), BigInt.fromHexSigned("1234567800000000"), true);
+		checkEquality(BigInt.fromHexSigned("1234567800000000"), BigInt.fromHexSigned("11234567800000000"), false);
+		checkEquality(BigInt.fromHexSigned("1234567800000000"), BigInt.fromHexSigned("123456780000000"), false);
 	}
 
 	private function checkEquality(a:BigInt, b:BigInt, expected:Bool):Void {
@@ -857,23 +857,23 @@ class TestBigInt extends Test {
 		checkAddInt(BigInt.fromInt(-1), 2, BigInt.fromInt(1));
 		checkAddInt(BigInt.fromInt(-1), -1, BigInt.fromInt(-2));
 
-		checkAddInt(BigInt.fromHex("000000000000000007fffffff"), 1, BigInt.fromHex("0000000000000000080000000"));
-		checkAddInt(BigInt.fromHex("0000000007fffffffffffffff"), 1, BigInt.fromHex("0000000008000000000000000"));
-		checkAddInt(BigInt.fromHex("07fffffffffffffffffffffff"), 1, BigInt.fromHex("0800000000000000000000000"));
-		checkAddInt(BigInt.fromHex("0ffffffffffffffffffffffff"), 1, BigInt.fromHex("1000000000000000000000000"));
-		checkAddInt(BigInt.fromHex("0fffffffffffffffeffffffff"), 1, BigInt.fromHex("0ffffffffffffffff00000000"));
+		checkAddInt(BigInt.fromHexSigned("000000000000000007fffffff"), 1, BigInt.fromHexSigned("0000000000000000080000000"));
+		checkAddInt(BigInt.fromHexSigned("0000000007fffffffffffffff"), 1, BigInt.fromHexSigned("0000000008000000000000000"));
+		checkAddInt(BigInt.fromHexSigned("07fffffffffffffffffffffff"), 1, BigInt.fromHexSigned("0800000000000000000000000"));
+		checkAddInt(BigInt.fromHexSigned("0ffffffffffffffffffffffff"), 1, BigInt.fromHexSigned("1000000000000000000000000"));
+		checkAddInt(BigInt.fromHexSigned("0fffffffffffffffeffffffff"), 1, BigInt.fromHexSigned("0ffffffffffffffff00000000"));
 
-		checkAdd(BigInt.fromHex("0ffffffffffffffff00000000"), BigInt.fromHex("100000000"), BigInt.fromHex("1000000000000000000000000"));
-		checkAdd(BigInt.fromHex("0ffffffff0000000000000000"), BigInt.fromHex("10000000000000000"), BigInt.fromHex("1000000000000000000000000"));
+		checkAdd(BigInt.fromHexSigned("0ffffffffffffffff00000000"), BigInt.fromHexSigned("100000000"), BigInt.fromHexSigned("1000000000000000000000000"));
+		checkAdd(BigInt.fromHexSigned("0ffffffff0000000000000000"), BigInt.fromHexSigned("10000000000000000"), BigInt.fromHexSigned("1000000000000000000000000"));
 
-		checkAdd(BigInt.fromHex("12345678"), BigInt.fromHex("11111111"), BigInt.fromHex("23456789"));
-		checkAdd(BigInt.fromHex("1234567812345678"), BigInt.fromHex("1111111111111111"), BigInt.fromHex("2345678923456789"));
-		checkAdd(BigInt.fromHex("123456781234567812345678"), BigInt.fromHex("111111111111111111111111"), BigInt.fromHex("234567892345678923456789"));
-		checkAdd(BigInt.fromHex("1234567812345678"), BigInt.fromHex("11111111"), BigInt.fromHex("1234567823456789"));
-		checkAdd(BigInt.fromHex("123456781234567812345678"), BigInt.fromHex("11111111"), BigInt.fromHex("123456781234567823456789"));
-		checkAdd(BigInt.fromHex("1234567812345678"), BigInt.fromHex("1111111100000000"), BigInt.fromHex("2345678912345678"));
-		checkAdd(BigInt.fromHex("123456781234567812345678"), BigInt.fromHex("111111110000000000000000"), BigInt.fromHex("234567891234567812345678"));
-		checkAdd(BigInt.fromHex("123456781234567812345678"), BigInt.fromHex("111111110000000011111111"), BigInt.fromHex("234567891234567823456789"));
+		checkAdd(BigInt.fromHexSigned("12345678"), BigInt.fromHexSigned("11111111"), BigInt.fromHexSigned("23456789"));
+		checkAdd(BigInt.fromHexSigned("1234567812345678"), BigInt.fromHexSigned("1111111111111111"), BigInt.fromHexSigned("2345678923456789"));
+		checkAdd(BigInt.fromHexSigned("123456781234567812345678"), BigInt.fromHexSigned("111111111111111111111111"), BigInt.fromHexSigned("234567892345678923456789"));
+		checkAdd(BigInt.fromHexSigned("1234567812345678"), BigInt.fromHexSigned("11111111"), BigInt.fromHexSigned("1234567823456789"));
+		checkAdd(BigInt.fromHexSigned("123456781234567812345678"), BigInt.fromHexSigned("11111111"), BigInt.fromHexSigned("123456781234567823456789"));
+		checkAdd(BigInt.fromHexSigned("1234567812345678"), BigInt.fromHexSigned("1111111100000000"), BigInt.fromHexSigned("2345678912345678"));
+		checkAdd(BigInt.fromHexSigned("123456781234567812345678"), BigInt.fromHexSigned("111111110000000000000000"), BigInt.fromHexSigned("234567891234567812345678"));
+		checkAdd(BigInt.fromHexSigned("123456781234567812345678"), BigInt.fromHexSigned("111111110000000011111111"), BigInt.fromHexSigned("234567891234567823456789"));
 	}
 
 	private function checkAddInt(a:BigInt, b:Int, expected:BigInt):Void {
@@ -942,11 +942,11 @@ class TestBigInt extends Test {
 		eq("1", (-BigInt.fromInt(-1)).toString());
 		eq(BigInt.fromInt(-100).toString(), (-BigInt.fromInt(100)).toString());
 		eq("100", (-BigInt.fromInt(-100)).toString());
-		eq(BigInt.fromHex("080000000").toHex(), (-BigInt.fromInt(-2147483648)).toHex());
-		eq(BigInt.fromInt(-2147483648).toHex(), (-BigInt.fromHex("080000000")).toHex());
-		eq(BigInt.fromHex("08000000000000000").toHex(), (-BigInt.fromHex("8000000000000000")).toHex());
-		eq(BigInt.fromHex("8000000000000000").toHex(), (-BigInt.fromHex("08000000000000000")).toHex());
-		eq(BigInt.fromHex("edcba98800000000").toHex(), (-BigInt.fromHex("1234567800000000")).toHex());
+		eq(BigInt.fromHexSigned("080000000").toHex(), (-BigInt.fromInt(-2147483648)).toHex());
+		eq(BigInt.fromInt(-2147483648).toHex(), (-BigInt.fromHexSigned("080000000")).toHex());
+		eq(BigInt.fromHexSigned("08000000000000000").toHex(), (-BigInt.fromHexSigned("8000000000000000")).toHex());
+		eq(BigInt.fromHexSigned("8000000000000000").toHex(), (-BigInt.fromHexSigned("08000000000000000")).toHex());
+		eq(BigInt.fromHexSigned("edcba98800000000").toHex(), (-BigInt.fromHexSigned("1234567800000000")).toHex());
 	}
 
 	public function bigIntFromString():Void {
@@ -985,8 +985,8 @@ class TestBigInt extends Test {
 		eq("7fffffff", BigInt.fromString("02147483647").toHex());
 		eq(BigInt.fromInt(-2147483648).toHex(), BigInt.fromString("-2147483648").toHex());
 		eq(BigInt.fromInt(-2147483648).toHex(), BigInt.fromString("-02147483648").toHex());
-		eq(BigInt.fromHex("080000000").toHex(), BigInt.fromString("2147483648").toHex());
-		eq(BigInt.fromHex("f7fffffff").toHex(), BigInt.fromString("-2147483649").toHex());
+		eq(BigInt.fromHexSigned("080000000").toHex(), BigInt.fromString("2147483648").toHex());
+		eq(BigInt.fromHexSigned("f7fffffff").toHex(), BigInt.fromString("-2147483649").toHex());
 
 		var a:MutableBigInt = 1;
 		for (i in 0...96) {
@@ -1010,7 +1010,7 @@ class TestBigInt extends Test {
 		eq(BigInt.fromInt(-100).toHex(), BigInt.fromBytes(Bytes.ofHex("ffffff9c")).toHex());
 		eq("7fffffff", BigInt.fromBytes(Bytes.ofHex("7fffffff")).toHex());
 		eq(BigInt.fromInt(-2147483648).toHex(), BigInt.fromBytes(Bytes.ofHex("80000000")).toHex());
-		eq(BigInt.fromHex("f7fffffff").toHex(), BigInt.fromBytes(Bytes.ofHex("ffffffff7fffffff")).toHex());
+		eq(BigInt.fromHexSigned("f7fffffff").toHex(), BigInt.fromBytes(Bytes.ofHex("ffffffff7fffffff")).toHex());
 	}
 
 	public function bigIntArithmeticShiftLeftAssignDoesntClobber():Void {
@@ -1053,23 +1053,23 @@ class TestBigInt extends Test {
 		}
 
 		asl(BigInt.ONE, 1, BigInt.fromInt(2));
-		asl(BigInt.ONE, 31, BigInt.fromHex("080000000"));
-		asl(BigInt.fromHex("080000000"), 1, BigInt.fromHex("100000000"));
+		asl(BigInt.ONE, 31, BigInt.fromHexSigned("080000000"));
+		asl(BigInt.fromHexSigned("080000000"), 1, BigInt.fromHexSigned("100000000"));
 
 		var sb = new StringBuf();
 		sb.add("1");
 		for (i in 0...100) {
-			asl(BigInt.ONE, i * 4, BigInt.fromHex(sb.toString()));
+			asl(BigInt.ONE, i * 4, BigInt.fromHexSigned(sb.toString()));
 			sb.add("0");
 		}
 		sb = new StringBuf();
 		sb.add("08");
 		for (i in 0...100) {
-			asl(BigInt.ONE, i * 4 + 3, BigInt.fromHex(sb.toString()));
+			asl(BigInt.ONE, i * 4 + 3, BigInt.fromHexSigned(sb.toString()));
 			sb.add("0");
 		}
 
-		asl(BigInt.fromHex("08000000180000000"), 15, BigInt.fromHex("40000000c00000000000"));
+		asl(BigInt.fromHexSigned("08000000180000000"), 15, BigInt.fromHexSigned("40000000c00000000000"));
 	}
 
 	private function asl(a:BigInt, b:Int, expected:BigInt):Void {
@@ -1097,14 +1097,14 @@ class TestBigInt extends Test {
 
 	public function bigIntSign():Void {
 		eq(0, BigInt.ZERO.sign());
-		eq(0, BigInt.ONE.sign());
+		eq(1, BigInt.ONE.sign());
 		eq(-1, BigInt.MINUS_ONE.sign());
-		eq(0, BigInt.fromInt(2147483647).sign());
+		eq(1, BigInt.fromInt(2147483647).sign());
 		eq(-1, BigInt.fromInt(-2147483648).sign());
 	}
 
 	public function bigIntSetFromIntWithLargeLength():Void {
-		var x:MutableBigInt = BigInt.fromHex("1 00000000");
+		var x:MutableBigInt = BigInt.fromHexSigned("1 00000000");
 		x <<= 1; // make it owned
 		var y:MutableBigInt_ = x;
 		y.setFromInt(11);
@@ -1116,22 +1116,22 @@ class TestBigInt extends Test {
 		eq("00000001", BigInt.ONE.toHex());
 		eq("ffffffff", BigInt.MINUS_ONE.toHex());
 
-		eq("0", BigInt.fromHex("0").toString());
-		eq("1", BigInt.fromHex("1").toString());
-		eq(BigInt.fromInt(-1).toHex(), BigInt.fromHex("f").toHex());
+		eq("0", BigInt.fromHexSigned("0").toString());
+		eq("1", BigInt.fromHexSigned("1").toString());
+		eq(BigInt.fromInt(-1).toHex(), BigInt.fromHexSigned("f").toHex());
 
 		try {
-			var x = BigInt.fromHex(null);
+			var x = BigInt.fromHexSigned(null);
 		} catch (e) {
 			eq(e.message, BigIntError.INVALID_ARGUMENT);
 		}
 		try {
-			var x = BigInt.fromHex("");
+			var x = BigInt.fromHexSigned("");
 		} catch (e) {
 			eq(e.message, BigIntError.INVALID_ARGUMENT);
 		}
 		try {
-			var x = BigInt.fromHex("0q0");
+			var x = BigInt.fromHexSigned("0q0");
 		} catch (e) {
 			eq(e.message, BigIntError.INVALID_ARGUMENT);
 		}
@@ -1147,10 +1147,10 @@ class TestBigInt extends Test {
 			checkHexString(sb.toString());
 		}
 
-		eq("2147483647", BigInt.fromHex("07fffffff").toString());
-		eq("-2147483648", BigInt.fromHex("f80000000").toString());
+		eq("2147483647", BigInt.fromHexSigned("07fffffff").toString());
+		eq("-2147483648", BigInt.fromHexSigned("f80000000").toString());
 
-		eq("-2147483648", BigInt.fromHex("8000 0000").toString());
+		eq("-2147483648", BigInt.fromHexSigned("8000 0000").toString());
 
 		eq(BigInt.fromHexSigned("080000000").toHex(), BigInt.fromHexUnsigned("80000000").toHex());
 		eq(BigInt.fromHexSigned("0ffffffff").toHex(), BigInt.fromHexUnsigned("ffffffff").toHex());
@@ -1158,7 +1158,7 @@ class TestBigInt extends Test {
 	}
 
 	private function checkHexString(value:String):Void {
-		var bi = BigInt.fromHex(value);
+		var bi = BigInt.fromHexSigned(value);
 		eq(value.toLowerCase(), bi.toHex().toLowerCase());
 		var by = bi.toBytes();
 		eq(by.toHex().toLowerCase(), bi.toHex().toLowerCase());
@@ -1187,7 +1187,7 @@ class TestBigInt extends Test {
 			s = s + "0";
 			checkDecString(s);
 		}
-		eq("1512366075204170929049582354406559215", BigInt.fromHex("01234567 89abcdef 01234567 89abcdef").toString());
+		eq("1512366075204170929049582354406559215", BigInt.fromHexSigned("01234567 89abcdef 01234567 89abcdef").toString());
 		#end
 	}
 
@@ -1201,7 +1201,7 @@ class TestBigInt extends Test {
 
 	public function testBigIntTools() {
 		// Test makes copy
-		var a:MutableBigInt = BigInt.fromHex("123456789abcdef0");
+		var a:MutableBigInt = BigInt.fromHexSigned("123456789abcdef0");
 		var b = BigIntTools.parseValueUnsigned(a);
 		eq("123456789abcdef0", b.toHex());
 		a.clear();
@@ -1233,9 +1233,9 @@ class TestBigInt extends Test {
 		t(BigIntTools.isBigInt(b1));
 
 		// Test parse
-		eq(BigInt.fromHex("123456789abcdef0").toHex(), BigIntTools.parseValueUnsigned("0x123456789abcdef0").toHex());
+		eq(BigInt.fromHexSigned("123456789abcdef0").toHex(), BigIntTools.parseValueUnsigned("0x123456789abcdef0").toHex());
 		eq(BigInt.fromString("12345678901234567890").toHex(), BigIntTools.parseValueUnsigned("12345678901234567890").toHex());
-		eq(BigInt.fromHex("080000000").toHex(), BigIntTools.parseValueUnsigned("0x80000000").toHex());
+		eq(BigInt.fromHexSigned("080000000").toHex(), BigIntTools.parseValueUnsigned("0x80000000").toHex());
 	}
 
 	public function testMultiwordArithmeticCompare():Void {

+ 1 - 1
tests/unit/src/unit/TestMain.hx

@@ -69,7 +69,7 @@ function main() {
 		#if (!php && !lua)
 		new TestHttps(),
 		#end
-		#if (hl || jvm)
+		#if !lua 
 		new TestBigInt(),
 		#end
 		#if !no_pattern_matching