Fix bus when converting unsigned to signed numbers

This commit is contained in:
BorysLevytskyi
2023-05-10 22:00:40 +02:00
parent 214f85c52d
commit 5512dacb0a
5 changed files with 57 additions and 20 deletions

View File

@@ -1,5 +1,15 @@
import { Integer } from "./Integer"
import { UINT32_MAX_VALUE } from "./const";
import { INT32_MAX_VALUE, UINT32_MAX_VALUE } from "./const";
it('toString for unsigned', () => {
const s = Integer.unsigned(4294967295).toString(2)
expect(s).toBe("11111111111111111111111111111111");
});
it('detects size correctly for signed and unsiged version', () => {
expect(Integer.unsigned(UINT32_MAX_VALUE).maxBitSize).toBe(32);
expect(Integer.signed(UINT32_MAX_VALUE).maxBitSize).toBe(64);
})
it('converts signed to unsigned and vice versa', () => {
const n1 = new Integer(-1, 8);
@@ -21,7 +31,14 @@ it('convers to different type', () => {
const n = src.convertTo(dest);
expect(n.num()).toBe(UINT32_MAX_VALUE);
})
});
it('doesnt modify 64-bit number when converting from usinged to signed', () => {
expect(Integer.unsigned(4294967295).toSigned().num()).toBe(-1);
expect(Integer.unsigned(2147483647).toSigned().num()).toBe(2147483647);
});
it('converts to largest size', () => {
const n8 = new Integer(-1, 8);

View File

@@ -1,11 +1,11 @@
import { type } from "os";
import { INT32_MAX_VALUE, INT32_MIN_VALUE } from "./const";
import { asIntN } from "./utils";
import { INT32_MAX_VALUE, INT32_MIN_VALUE, UINT32_MAX_VALUE } from "./const";
import { asIntN, logLines as ln } from "./utils";
import formatter from "./formatter";
import calc from "./calc";
export type JsNumber = number | bigint;
export type IntegerInput = JsNumber | string;
export class Integer {
@@ -13,29 +13,37 @@ export class Integer {
readonly maxBitSize: number;
readonly signed: boolean;
constructor(value: JsNumber, maxBitSize?: number, signed? : boolean) {
constructor(value: IntegerInput, maxBitSize?: number, signed? : boolean) {
this.value = typeof value == "bigint" ? value : BigInt(value);
this.maxBitSize = maxBitSize != null ? maxBitSize : (value >= INT32_MIN_VALUE && value <= INT32_MAX_VALUE) ? 32 : 64;
this.signed = signed == null ? true : signed == true;
this.maxBitSize = maxBitSize != null ? maxBitSize : detectSize(this.value, this.signed);
if(!this.signed && this.value < 0)
throw new Error("Value " + value + " cannot be negative if the type is unsigned");
}
static unsigned(value : JsNumber, maxBitSize?: number) {
static unsigned(value : IntegerInput, maxBitSize?: number) {
return new Integer(value, maxBitSize, false);
}
static long(value: JsNumber) : Integer {
static signed(value : IntegerInput, maxBitSize?: number) {
return new Integer(value, maxBitSize, true);
}
static long(value: IntegerInput) : Integer {
return new Integer(value, 64);
}
static int(value: JsNumber) : Integer {
static int(value: IntegerInput) : Integer {
return new Integer(value, 32);
}
static short(value: JsNumber) : Integer {
static short(value: IntegerInput) : Integer {
return new Integer(value, 16);
}
static byte(value: JsNumber) : Integer {
static byte(value: IntegerInput) : Integer {
return new Integer(value, 8);
}
@@ -51,10 +59,13 @@ export class Integer {
if(this.signed)
return new Integer(this.value, this.maxBitSize, this.signed);
const bin = calc.engine.applyTwosComplement(this.toString(2));
const n = BigInt("0b"+bin);
const orig = this.toString(2).padStart(this.maxBitSize, '0');
const inverted = orig[0] == '1' ? calc.engine.applyTwosComplement(orig) : orig;
const n = BigInt("0b"+inverted);
const negative = orig[0] == '1';
return new Integer(bin[0] == '1' ? n : -n, this.maxBitSize, true)
return new Integer(negative ? -n : n, this.maxBitSize, true)
}
resize(newSize: number) {
@@ -115,4 +126,12 @@ export function asInteger(num: JsNumber | Integer | string): Integer {
export function isInteger(num: JsNumber | Integer): num is Integer {
return (<Integer>num).maxBitSize !== undefined;
}
}
function detectSize(value: bigint, signed: boolean): number {
if(!signed)
return value > UINT32_MAX_VALUE ? 64 : 32;
else
return value < INT32_MIN_VALUE || value > INT32_MAX_VALUE ? 64 : 32;
}

View File

@@ -247,7 +247,6 @@ function nextPowOfTwo(num: number) : number {
}
function equalizeSize(n1: Integer, n2: Integer) : [Integer, Integer] {
console.log('equalizeSize()', new Error().stack);
if(n1.maxBitSize == n2.maxBitSize)
{
if(n1.signed === n2.signed) return [n1,n2];

View File

@@ -26,4 +26,8 @@ function randomBool() {
return random(1, 10000) % 2 == 0;
}
export {chunkifyString, asIntN, random, randomBool};
function logLines(...params: any[]) {
console.log(params.join('\n'))
}
export {chunkifyString, asIntN, random, randomBool, logLines};

View File

@@ -58,9 +58,7 @@ function applyOperator(op1 : Operand, operator: string, op2 : Operand) : Operand
equalizeSize(op1, op2);
}
console.log(op1.value, operator, op2.value);
const result = calc.operation(op1.value, operator, op2.value);
console.log('=', result);
return new Operand(result, op2.base);
}