@dalet-oss/lexorank
Version:
A reference implementation of a list ordering system like JIRA's Lexorank algorithm
167 lines (166 loc) • 5.11 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LexoDecimal = void 0;
const lexoInteger_1 = require("./lexoInteger");
const stringBuilder_1 = require("../utils/stringBuilder");
class LexoDecimal {
constructor(mag, sig) {
this.mag = mag;
this.sig = sig;
}
static half(sys) {
const mid = (sys.getBase() / 2) | 0;
return LexoDecimal.make(lexoInteger_1.LexoInteger.make(sys, 1, [mid]), 1);
}
static parse(str, system) {
const partialIndex = str.indexOf(system.getRadixPointChar());
if (str.lastIndexOf(system.getRadixPointChar()) !== partialIndex) {
throw new Error('More than one ' + system.getRadixPointChar());
}
if (partialIndex < 0) {
return LexoDecimal.make(lexoInteger_1.LexoInteger.parse(str, system), 0);
}
const intStr = str.substring(0, partialIndex) + str.substring(partialIndex + 1);
return LexoDecimal.make(lexoInteger_1.LexoInteger.parse(intStr, system), str.length - 1 - partialIndex);
}
static from(integer) {
return LexoDecimal.make(integer, 0);
}
static make(integer, sig) {
if (integer.isZero()) {
return new LexoDecimal(integer, 0);
}
let zeroCount = 0;
for (let i = 0; i < sig && integer.getMag(i) === 0; ++i) {
++zeroCount;
}
const newInteger = integer.shiftRight(zeroCount);
const newSig = sig - zeroCount;
return new LexoDecimal(newInteger, newSig);
}
getSystem() {
return this.mag.getSystem();
}
add(other) {
let tmag = this.mag;
let tsig = this.sig;
let omag = other.mag;
let osig;
for (osig = other.sig; tsig < osig; ++tsig) {
tmag = tmag.shiftLeft();
}
while (tsig > osig) {
omag = omag.shiftLeft();
++osig;
}
return LexoDecimal.make(tmag.add(omag), tsig);
}
subtract(other) {
let thisMag = this.mag;
let thisSig = this.sig;
let otherMag = other.mag;
let otherSig;
for (otherSig = other.sig; thisSig < otherSig; ++thisSig) {
thisMag = thisMag.shiftLeft();
}
while (thisSig > otherSig) {
otherMag = otherMag.shiftLeft();
++otherSig;
}
return LexoDecimal.make(thisMag.subtract(otherMag), thisSig);
}
multiply(other) {
return LexoDecimal.make(this.mag.multiply(other.mag), this.sig + other.sig);
}
floor() {
return this.mag.shiftRight(this.sig);
}
ceil() {
if (this.isExact()) {
return this.mag;
}
const floor = this.floor();
return floor.add(lexoInteger_1.LexoInteger.one(floor.getSystem()));
}
isExact() {
if (this.sig === 0) {
return true;
}
for (let i = 0; i < this.sig; ++i) {
if (this.mag.getMag(i) !== 0) {
return false;
}
}
return true;
}
getScale() {
return this.sig;
}
setScale(nsig, ceiling = false) {
if (nsig >= this.sig) {
return this;
}
if (nsig < 0) {
nsig = 0;
}
const diff = this.sig - nsig;
let nmag = this.mag.shiftRight(diff);
if (ceiling) {
nmag = nmag.add(lexoInteger_1.LexoInteger.one(nmag.getSystem()));
}
return LexoDecimal.make(nmag, nsig);
}
compareTo(other) {
if (this === other) {
return 0;
}
if (!other) {
return 1;
}
let tMag = this.mag;
let oMag = other.mag;
if (this.sig > other.sig) {
oMag = oMag.shiftLeft(this.sig - other.sig);
}
else if (this.sig < other.sig) {
tMag = tMag.shiftLeft(other.sig - this.sig);
}
return tMag.compareTo(oMag);
}
format() {
const intStr = this.mag.format();
if (this.sig === 0) {
return intStr;
}
const sb = new stringBuilder_1.default(intStr);
const head = sb[0];
const specialHead = head === this.mag.getSystem().getPositiveChar() || head === this.mag.getSystem().getNegativeChar();
if (specialHead) {
sb.remove(0, 1);
}
while (sb.length < this.sig + 1) {
sb.insert(0, this.mag.getSystem().toChar(0));
}
sb.insert(sb.length - this.sig, this.mag.getSystem().getRadixPointChar());
if (sb.length - this.sig === 0) {
sb.insert(0, this.mag.getSystem().toChar(0));
}
if (specialHead) {
sb.insert(0, head);
}
return sb.toString();
}
equals(other) {
if (this === other) {
return true;
}
if (!other) {
return false;
}
return this.mag.equals(other.mag) && this.sig === other.sig;
}
toString() {
return this.format();
}
}
exports.LexoDecimal = LexoDecimal;