From 7ed5bcbeb2f97a75dabac5d06fccd1abf3d1c6fe Mon Sep 17 00:00:00 2001 From: uellenberg Date: Sun, 2 May 2021 14:44:02 -0700 Subject: [PATCH] Remove decimals from digits --- package.json | 4 +- src/NumberTools.ts | 18 ++++----- src/index.ts | 1 - src/types/Digit.ts | 14 ------- src/types/Num.ts | 93 ++++++++++++++-------------------------------- test/index.js | 35 ++++++----------- yarn.lock | 5 --- 7 files changed, 48 insertions(+), 122 deletions(-) delete mode 100644 src/types/Digit.ts diff --git a/package.json b/package.json index 2d3d25f..110739d 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,5 @@ "nyc": "^15.1.0", "typescript": "^4.2.4" }, - "dependencies": { - "parselib": "^1.0.0" - } + "dependencies": {} } diff --git a/src/NumberTools.ts b/src/NumberTools.ts index 7fb8213..d8f81bb 100644 --- a/src/NumberTools.ts +++ b/src/NumberTools.ts @@ -3,8 +3,6 @@ * @param num {number} - is the number which will be split. * @constructor */ -import {Digit} from "./types/Digit"; - export const SplitNumber = (num: number) : SplitNumber => { const split = num.toString().split("."); @@ -30,13 +28,11 @@ export interface SplitNumber { * Converts a digit to a number * @param digit {Digit} - the digit being converted. */ -export const DigitToNumber = (digit: Digit) : number => { +export const DigitToNumber = (digit: string) : number => { //Essentially, the way this works is that if the number is not an integer, then it is the character code - 87. This is because character code 97 (a) is the first character code for 10. - let num = parseInt(digit.number); - if(isNaN(num)) num = digit.number.charCodeAt(0) - 87; - - if(digit.decimals) num += digit.decimals/Math.pow(10, digit.decimals.toString().length); + let num = parseInt(digit); + if(isNaN(num)) num = digit.charCodeAt(0) - 87; return num; } @@ -46,12 +42,12 @@ export const DigitToNumber = (digit: Digit) : number => { * @param num {number} - the number that will be changed to a Digit. * @constructor */ -export const NumberToDigit = (num: number) : Digit => { +export const NumberToDigit = (num: number) : string => { //This is similar to the above, but in reverse. const split = SplitNumber(num); - return num < 10 ? {number: split.digits, decimals: split.decimals ? parseInt(split.decimals) : null} : {number: String.fromCharCode(parseInt(split.digits)+87), decimals: split.decimals ? parseInt(split.decimals) : null}; + return num < 10 ? split.digits : String.fromCharCode(parseInt(split.digits)+87); } /** @@ -69,8 +65,8 @@ export const FractionToBase = (fraction: number, base: number, precision: number const num = Math.floor((fraction * Math.pow(base, tries+1)) % base); let digit = NumberToDigit(num); - if(digit.number !== "0") { - digits.push(...toAdd, digit.number); + if(digit !== "0") { + digits.push(...toAdd, digit); toAdd = []; } else { toAdd.push("0"); diff --git a/src/index.ts b/src/index.ts index 182fad1..0b53412 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,2 @@ export {Num} from "./types/Num"; -export {Digit} from "./types/Digit"; export {NumOptions} from "./types/NumOptions"; \ No newline at end of file diff --git a/src/types/Digit.ts b/src/types/Digit.ts deleted file mode 100644 index c68e017..0000000 --- a/src/types/Digit.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * A digit in a number. - */ -export interface Digit { - /** - * The number of a digit. For example, in the number `A 2 3 4.56`, the number of the first digit is `A`. - */ - number: string; - - /** - * The decimals of a digit. For example, in the number `A 2 3 4.56`, the number of the fourth digit is `56`. - */ - decimals?: number; -} \ No newline at end of file diff --git a/src/types/Num.ts b/src/types/Num.ts index 6704c3c..41b3f13 100644 --- a/src/types/Num.ts +++ b/src/types/Num.ts @@ -1,9 +1,5 @@ -import {Digit} from "./Digit"; import {DigitToNumber, FractionToBase, NumberToDigit, SplitNumber} from "../NumberTools"; import {NumOptions} from "./NumOptions"; -import {RecursiveMap, RegexTokenizer, TokenizerChain} from "parselib"; - -const inputParseChain = new TokenizerChain(new RegexTokenizer(/[\[\]]/g)); /** * A class providing information about a number. @@ -26,14 +22,14 @@ export class Num { * For example, in the number `1234.56`, this will contain the digits `1234`. * @private */ - private readonly _digits: Digit[] = []; + private readonly _digits: string[] = []; /** * The decimal digits of a number. * For example, in the number `1234.56`, this will contain the digit `56`. * @private */ - private readonly _decimals: Digit[] = []; + private readonly _decimals: string[] = []; /** * A cache of all conversions to other number systems. @@ -61,60 +57,23 @@ export class Num { this._base = num.base; - let inputSplit = num.num.split(/\.(?![^[]*?])/g); + let inputSplit = num.num.split(/\./g); const decimals = inputSplit.length > 1 ? inputSplit.pop() : ""; - const digits = inputSplit.join(".") || "0"; - - const tokens = inputParseChain.run(digits); - const parsedDigits = RecursiveMap(tokens, token => token.isToken && token.value === "[", token => token.isToken && token.value === "]", token => { - const digitSplit = token.value.split("."); - - const number = digitSplit.shift() || "0"; - const decimals = digitSplit.shift(); - - if(number.length > 1){ - let out: Digit[] = []; - - for(const digit of number){ - out.push({number: digit}); - } - - return out; - } - - return {number, decimals}; - }, tokens => tokens, tokens => { - let out: Digit[] = []; - - tokens.forEach(token => { - if(Array.isArray(token)) out.push(...token); - else out.push(token); - }); - - return out; - }); + const digits = (inputSplit.join(".") || "0").split(""); let convertedNum = 0; - for (let i = 0; i < parsedDigits.length; i++) { - convertedNum += DigitToNumber({number: parsedDigits[i].number}) * Math.pow(this._base, parsedDigits.length-i-1); - - if(parsedDigits[i].decimals){ - const decimals1 = parsedDigits[i].decimals.toString(); - - for (let y = 0; y < decimals1.length; y++) { - convertedNum += DigitToNumber({number: decimals1[y]})/Math.pow(this._base, y+1)*Math.pow(this._base, parsedDigits.length-i-1); - } - } + for (let i = 0; i < digits.length; i++) { + convertedNum += DigitToNumber(digits[i]) * Math.pow(this._base, digits.length-i-1); } if(decimals){ for (let y = 0; y < decimals.length; y++) { - convertedNum += DigitToNumber({number: decimals[y]})/Math.pow(this._base, y+1); + convertedNum += DigitToNumber(decimals[y])/Math.pow(this._base, y+1); } } - + return new Num({num: convertedNum}); } else { if(typeof(num.num) === "string"){ @@ -128,12 +87,12 @@ export class Num { const split = SplitNumber(num.num); for (let digit of split.digits) { - this._digits.push({number: digit}); + this._digits.push(digit); } if(split.decimals){ for (let decimal of split.decimals) { - this._decimals.push({number: decimal}); + this._decimals.push(decimal); } } } @@ -148,33 +107,37 @@ export class Num { private Convert(base: number, precision: number) : void { if(this._cache.hasOwnProperty(base.toString() + "|" + precision.toString())) return; - const digit = parseInt(this._digits.map(digit => digit.number).join("")); + if(base === 10){ + let digitsPart = this._digits.join(""); + let decimalsPart = this._decimals.join(""); + + if(decimalsPart === "0") decimalsPart = ""; + + this._cache[base.toString() + "|" + precision.toString()] = digitsPart + (decimalsPart ? "." : "") + decimalsPart; + + return; + } + + let digit = parseInt(this._digits.join("")); const digitLog = Math.ceil(Math.log(digit)/Math.log(this._base)) + (digit % this._base === 0 ? 1 : 0); let digits: string[] = []; let decimals: string[] = []; - for (let i = 0; i < digitLog; i++){ - const number = Math.floor(digit/Math.pow(this._base, i)) % this._base; - const d = NumberToDigit(number); + for (let i = digitLog-1; i > -1; i--){ + let number = Math.floor((digit / Math.pow(this._base, i)) % this._base); + digit -= number * Math.pow(this._base, i); - let str = d.number; - if(d.decimals) { - str = "["+(str !== "0" ? str : "")+"."+FractionToBase(d.decimals / Math.pow(10, d.decimals.toString().length), this._base, precision).join("")+"]"; - } - - digits.push(str); + digits.push(NumberToDigit(number)); } - digits.reverse(); - if(this._base !== 10) { - let fraction = parseInt(this._decimals.map(decimal => decimal.number).join("")) / Math.pow(10, this._decimals.length); + let fraction = parseInt(this._decimals.join("")) / Math.pow(10, this._decimals.length); decimals.push(...FractionToBase(fraction, this._base, precision)); } else { for (let decimal of this._decimals) { - decimals.push(decimal.number); + decimals.push(decimal); } } diff --git a/test/index.js b/test/index.js index 7219e35..fb500da 100644 --- a/test/index.js +++ b/test/index.js @@ -8,20 +8,12 @@ describe("Num", () => { expect(new Num(100.1)).to.eql({ _base: 10, _cache: {}, _digits: [ - { - number: "1" - }, - { - number: "0" - }, - { - number: "0" - } + "1", + "0", + "0" ], _decimals: [ - { - number: "1" - } + "1" ] }); }); @@ -39,9 +31,9 @@ describe("Num", () => { context("with number to base 2.5", () => { it("should return the correct Num.", () => { - expect(new Num(9.5).ToBase(2.5).toString()).to.eql("1[.100212][1.100212].100212"); + expect(new Num(9.5).ToBase(2.5).toString()).to.eql("110.100212"); - expect(new Num(9).ToBase(2.5).toString()).to.eql("1[.100212][1.100212]"); + expect(new Num(9).ToBase(2.5).toString()).to.eql("110"); }); }); @@ -65,9 +57,9 @@ describe("Num", () => { //this shouldn't be possible context("with number to base 65536.65536", () => { it("should return the correct Num.", () => { - expect(new Num(5477458767.436).ToBase(65536.65536).toString()).to.eql("1[䛐.墑跢恎␄鏝庯保碷][趰.勀覴靧吧䒿箲뤯].濴ﮪ専祝㋟雏"); + expect(new Num(5477458767.436).ToBase(65536.65536).toString()).to.eql("1䛐.濴ﮪ専祝㋟雏"); - expect(new Num(5477458767).ToBase(65536.65536).toString()).to.eql("1[䛐.墑跢恎␄鏝庯保碷][趰.勀覴靧吧䒿箲뤯]"); + expect(new Num(5477458767).ToBase(65536.65536).toString()).to.eql("1䛐"); }); }); }); @@ -84,14 +76,13 @@ describe("Num", () => { context("with a base 2.5 number", () => { it("should return the correct Num.", () => { //9.5, some with inaccuracies - expect(new Num({num: "1[.100212][1.100212].100212", base: 2.5}).ToBase(10).toString()).to.eql("9.363343999999998"); + expect(new Num({num: "110.100212", base: 2.5}).ToBase(10).toString()).to.eql("9.219631999999999"); //9, some with inaccuracies - expect(new Num({num: "1[.100212][1.100212]", base: 2.5}).ToBase(10).toString()).to.eql("8.893711999999999"); + expect(new Num({num: "110", base: 2.5}).ToBase(10).toString()).to.eql("8.75"); }); }); - //this is ridiculous context("with a base 65536", () => { it("should return the correct Num.", () => { //I can't believe this actually worked @@ -102,13 +93,11 @@ describe("Num", () => { }); }); - //this shouldn't be possible context("with number to base 65536.65536", () => { it("should return the correct Num.", () => { - //I am converting a number to base 65536.65536 and back to base 10 losslessly. How the hell? - expect(new Num({num: "1[䛐.墑跢恎␄鏝庯保碷][趰.勀覴靧吧䒿箲뤯].濴ﮪ専祝㋟雏", base: 65536.65536}).ToBase(10).toString()).to.eql("5477458767.436"); + expect(new Num({num: "1䛐.濴ﮪ専祝㋟雏", base: 65536.65536}).ToBase(10).toString()).to.eql("5477458766.561177"); - expect(new Num({num: "1[䛐.墑跢恎␄鏝庯保碷][趰.勀覴靧吧䒿箲뤯]", base: 65536.65536}).ToBase(10).toString()).to.eql("5477458767"); + expect(new Num({num: "1䛐", base: 65536.65536}).ToBase(10).toString()).to.eql("5477458766.125177"); }); }); }); diff --git a/yarn.lock b/yarn.lock index bd38155..641a169 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1470,11 +1470,6 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parselib@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/parselib/-/parselib-1.0.0.tgz#681a25a4614c75a8bb211b1786a90e33d1e48c02" - integrity sha512-G+pcgRKqcJKODRBJdIKxJh2IQPUUB4/HCNG0uAcubPg1pD1eFEHu66mNnF95jRW/Kv17nnzpeEi69gcWSWteRA== - path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"